* [PATCH] block: stop the timeout timer when releasing a never added disk
@ 2026-07-27 20:12 Chao Shi
2026-07-28 4:23 ` Christoph Hellwig
2026-07-29 11:23 ` Jens Axboe
0 siblings, 2 replies; 7+ messages in thread
From: Chao Shi @ 2026-07-27 20:12 UTC (permalink / raw)
To: Jens Axboe
Cc: Christoph Hellwig, Ming Lei, Hannes Reinecke, Keith Busch,
Damien Le Moal, Weidong Zhu, linux-block, linux-nvme,
linux-kernel
disk_release() undoes blk_mq_init_allocated_queue() for a disk whose
probe failed before add_disk(), but it only calls blk_mq_exit_queue().
Nothing there stops q->timeout, and that timer rolls forward: it stays
pending until it next expires, not until the last request completes.
So if the driver issued any I/O before adding the disk, the
request_queue is freed while still linked into a timer wheel bucket.
Commit 6f8191fdf41d ("block: simplify disk shutdown") dropped the
blk_cleanup_queue() call that used to stop it. __del_gendisk() and
blk_mq_destroy_queue() still do; only the probe failure path lost it.
nvme gets there because nvme_update_ns_info() submits Report Zones or
FDP io-mgmt-recv on ns->queue before the disk is added, so a later
failure - a concurrent reset setting NVME_CTRL_FROZEN, or
device_add_disk() failing - lands in put_disk() with the timer armed:
BUG: KASAN: slab-use-after-free in detach_if_pending+0x30c/0x340
Write of size 8 at addr ffff888004d71310 by task kworker/u8:2/37
__timer_delete_sync+0x156/0x240 kernel/time/timer.c:1621
blk_sync_queue+0x22/0x40 block/blk-core.c:222
nvme_sync_queues+0x100/0x150 drivers/nvme/host/core.c:5362
nvme_reset_work+0x138/0x930 drivers/nvme/host/pci.c:3264
Allocated by task 34:
__blk_mq_alloc_disk+0x33/0x100 block/blk-mq.c:4462
nvme_alloc_ns+0x290/0x3870 drivers/nvme/host/core.c:4146
Freed by task 0:
blk_free_queue_rcu+0x3a/0x50 block/blk-core.c:254
rcu_core+0xc10/0x1730 kernel/rcu/tree.c:2857
The queue being synced there is ctrl->admin_q, only a victim sharing a
timer wheel bucket with the freed queue's dangling entry; other runs
tripped in enqueue_timer(), __run_timers() or blk_mq_timeout_work().
Failing nvme_alloc_ns() with a debug patch makes it deterministic: one
leaked timer trips KASAN within seconds, while 1987 patched releases
produced no splat.
Stop the timer and the queue work items before blk_mq_exit_queue(), like
blk_mq_destroy_queue() does.
Found by FuzzNvme.
Fixes: 6f8191fdf41d ("block: simplify disk shutdown")
Acked-by: Weidong Zhu <weizhu@fiu.edu>
Signed-off-by: Chao Shi <coshi036@gmail.com>
---
block/genhd.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/block/genhd.c b/block/genhd.c
index df2c3c69b467..e8ce0cabf392 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -1281,14 +1281,18 @@ static void disk_release(struct device *dev)
/*
* To undo the all initialization from blk_mq_init_allocated_queue in
* case of a probe failure where add_disk is never called we have to
- * call blk_mq_exit_queue here. We can't do this for the more common
- * teardown case (yet) as the tagset can be gone by the time the disk
- * is released once it was added.
+ * call blk_mq_exit_queue here, after stopping the timer and work items
+ * that I/O issued before add_disk may have left pending. We can't do
+ * this for the more common teardown case (yet) as the tagset can be
+ * gone by the time the disk is released once it was added.
*/
if (queue_is_mq(disk->queue) &&
test_bit(GD_OWNS_QUEUE, &disk->state) &&
- !test_bit(GD_ADDED, &disk->state))
+ !test_bit(GD_ADDED, &disk->state)) {
+ blk_sync_queue(disk->queue);
+ blk_mq_cancel_work_sync(disk->queue);
blk_mq_exit_queue(disk->queue);
+ }
blkcg_exit_disk(disk);
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] block: stop the timeout timer when releasing a never added disk
2026-07-27 20:12 [PATCH] block: stop the timeout timer when releasing a never added disk Chao Shi
@ 2026-07-28 4:23 ` Christoph Hellwig
2026-07-29 7:55 ` Chris S
2026-07-29 11:23 ` Jens Axboe
1 sibling, 1 reply; 7+ messages in thread
From: Christoph Hellwig @ 2026-07-28 4:23 UTC (permalink / raw)
To: Chao Shi
Cc: Jens Axboe, Christoph Hellwig, Ming Lei, Hannes Reinecke,
Keith Busch, Damien Le Moal, Weidong Zhu, linux-block,
linux-nvme, linux-kernel
Looks good:
Reviewed-by: Christoph Hellwig <hch@lst.de>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] block: stop the timeout timer when releasing a never added disk
2026-07-28 4:23 ` Christoph Hellwig
@ 2026-07-29 7:55 ` Chris S
0 siblings, 0 replies; 7+ messages in thread
From: Chris S @ 2026-07-29 7:55 UTC (permalink / raw)
To: Christoph Hellwig
Cc: Jens Axboe, Ming Lei, Hannes Reinecke, Keith Busch,
Damien Le Moal, Weidong Zhu, linux-block, linux-nvme,
linux-kernel
Thank you!
Best,
Chao
On Tue, Jul 28, 2026 at 12:23 AM Christoph Hellwig <hch@lst.de> wrote:
>
> Looks good:
>
> Reviewed-by: Christoph Hellwig <hch@lst.de>
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] block: stop the timeout timer when releasing a never added disk
2026-07-27 20:12 [PATCH] block: stop the timeout timer when releasing a never added disk Chao Shi
2026-07-28 4:23 ` Christoph Hellwig
@ 2026-07-29 11:23 ` Jens Axboe
2026-07-29 18:05 ` Chris S
` (2 more replies)
1 sibling, 3 replies; 7+ messages in thread
From: Jens Axboe @ 2026-07-29 11:23 UTC (permalink / raw)
To: Chao Shi
Cc: Christoph Hellwig, Ming Lei, Hannes Reinecke, Keith Busch,
Damien Le Moal, Weidong Zhu, linux-block, linux-nvme,
linux-kernel
On Mon, 27 Jul 2026 16:12:57 -0400, Chao Shi wrote:
> disk_release() undoes blk_mq_init_allocated_queue() for a disk whose
> probe failed before add_disk(), but it only calls blk_mq_exit_queue().
> Nothing there stops q->timeout, and that timer rolls forward: it stays
> pending until it next expires, not until the last request completes.
> So if the driver issued any I/O before adding the disk, the
> request_queue is freed while still linked into a timer wheel bucket.
>
> [...]
Applied, thanks!
[1/1] block: stop the timeout timer when releasing a never added disk
commit: 26cb8ebbfaf713c82e142d08828d4d765057633b
Best regards,
--
Jens Axboe
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] block: stop the timeout timer when releasing a never added disk
2026-07-29 11:23 ` Jens Axboe
@ 2026-07-29 18:05 ` Chris S
2026-07-30 19:42 ` Chris S
2026-07-30 19:48 ` Chris S
2 siblings, 0 replies; 7+ messages in thread
From: Chris S @ 2026-07-29 18:05 UTC (permalink / raw)
To: Jens Axboe
Cc: Christoph Hellwig, Ming Lei, Hannes Reinecke, Keith Busch,
Damien Le Moal, Weidong Zhu, linux-block, linux-nvme,
linux-kernel
Thank you so much!
Best,
Chao
On Wed, Jul 29, 2026 at 7:23 AM Jens Axboe <axboe@kernel.dk> wrote:
>
>
> On Mon, 27 Jul 2026 16:12:57 -0400, Chao Shi wrote:
> > disk_release() undoes blk_mq_init_allocated_queue() for a disk whose
> > probe failed before add_disk(), but it only calls blk_mq_exit_queue().
> > Nothing there stops q->timeout, and that timer rolls forward: it stays
> > pending until it next expires, not until the last request completes.
> > So if the driver issued any I/O before adding the disk, the
> > request_queue is freed while still linked into a timer wheel bucket.
> >
> > [...]
>
> Applied, thanks!
>
> [1/1] block: stop the timeout timer when releasing a never added disk
> commit: 26cb8ebbfaf713c82e142d08828d4d765057633b
>
> Best regards,
> --
> Jens Axboe
>
>
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] block: stop the timeout timer when releasing a never added disk
2026-07-29 11:23 ` Jens Axboe
2026-07-29 18:05 ` Chris S
@ 2026-07-30 19:42 ` Chris S
2026-07-30 19:48 ` Chris S
2 siblings, 0 replies; 7+ messages in thread
From: Chris S @ 2026-07-30 19:42 UTC (permalink / raw)
To: Jens Axboe
Cc: Christoph Hellwig, Ming Lei, Hannes Reinecke, Keith Busch,
Damien Le Moal, Weidong Zhu, linux-block, linux-nvme,
linux-kernel
Hi Jan, I'm currently working on the changes we discussed. Based on
vfs.all now. Four things came out of writing it that I would rather
resolve before posting.
1. mark_buffer_write_io_error() is not safe for jbd2's buffers yet. It
dereferences bh->b_folio->mapping directly (fs/buffer.c:1057), and
jbd2_journal_write_metadata_buffer() points the temporary bh at
virt_to_folio(jh->b_frozen_data), which is slab-backed.
buffer_set_crypto_ctx() right next to it already uses folio_mapping() for
exactly this reason. So I would send a prerequisite converting
mark_buffer_write_io_error() to folio_mapping() before the jbd2 change.
Also worth noting the consequence of A2: in ordered mode the temp bh
inherits the source folio, so the error lands on the bdev mapping and
mapping_set_error() errseq_set()s s_wb_err - a later syncfs() on an
unrelated fd of the same fs can then return EIO.
2. gfs2 already has what we are building: gfs2_end_log_write_bh()
(fs/gfs2/lops.c:171) calls mark_buffer_write_io_error() and does not clear
uptodate. Which means fs/gfs2/log.c:110 and :324 are blind to log write
errors today, and converting them is not behaviour-preserving - it makes
them start catching those. I think that is right, but say if you would
rather it were separate.
3. On the sticky BH_Write_EIO: I am adding it to BUFFER_FLAGS_DISCARD as
you suggested. That covers discard_buffer(), but there are four other
clear_buffer_req() sites (fs/buffer.c:1687, fs/gfs2/aops.c:600,
fs/jbd2/commit.c:1035, fs/jbd2/transaction.c:2462). Three of them also
clear_buffer_mapped() and NULL b_bdev, so __bh_submit()'s
BUG_ON(!buffer_mapped(bh)) makes them unreachable. Only
clean_bdev_aliases() leaves the buffer writable, and I could not construct
a workload that reaches it. So I am not sending the ungating patch. The
one place it would matter is ocfs2: fs/ocfs2/journal.c:691 is nested
inside an if (!buffer_uptodate(bh)) at :675 that goes dead once the clear
is gone, so :691 has to be hoisted out, and it then becomes a pre-use
check on a sticky flag rather than a post-write one. I will Cc ocfs2-devel
on that patch.
4. fs/jbd2/transaction.c:923, J_EXPECT_JH(jh, buffer_uptodate(bh)) in
jbd2_freeze_jh_data(): after the series a failed write leaves the buffer
uptodate, so this stops firing for write errors. Arguably correct - the
in-memory copy being frozen is still valid - but it is your assert. Leave
it, or convert it? I instrumented it and ran ext4 with data=journal under
injected write errors, forcing copy-out; it never saw a non-uptodate
buffer, so I have no evidence either way.
One thing I did settle by testing. fs/ext4/ext4_jbd2.c:416 open-codes
buffer_req(bh) && !buffer_uptodate(bh) after sync_dirty_buffer(), which
already returns -EIO. On an instrumented kernel (ext4 without a journal,
-o sync, injected write errors) the two agreed on all 40 occurrences and
never diverged, with BH_Write_EIO set every time. So that site just
consumes the return value and the buffer_req() question goes away.
Best,
Chao
On Wed, Jul 29, 2026 at 7:23 AM Jens Axboe <axboe@kernel.dk> wrote:
>
>
> On Mon, 27 Jul 2026 16:12:57 -0400, Chao Shi wrote:
> > disk_release() undoes blk_mq_init_allocated_queue() for a disk whose
> > probe failed before add_disk(), but it only calls blk_mq_exit_queue().
> > Nothing there stops q->timeout, and that timer rolls forward: it stays
> > pending until it next expires, not until the last request completes.
> > So if the driver issued any I/O before adding the disk, the
> > request_queue is freed while still linked into a timer wheel bucket.
> >
> > [...]
>
> Applied, thanks!
>
> [1/1] block: stop the timeout timer when releasing a never added disk
> commit: 26cb8ebbfaf713c82e142d08828d4d765057633b
>
> Best regards,
> --
> Jens Axboe
>
>
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] block: stop the timeout timer when releasing a never added disk
2026-07-29 11:23 ` Jens Axboe
2026-07-29 18:05 ` Chris S
2026-07-30 19:42 ` Chris S
@ 2026-07-30 19:48 ` Chris S
2 siblings, 0 replies; 7+ messages in thread
From: Chris S @ 2026-07-30 19:48 UTC (permalink / raw)
To: Jens Axboe
Cc: Christoph Hellwig, Ming Lei, Hannes Reinecke, Keith Busch,
Damien Le Moal, Weidong Zhu, linux-block, linux-nvme,
linux-kernel
Sorry for the mistake, I think I replied to the wrong emails.
Best,
Chao
On Wed, Jul 29, 2026 at 7:23 AM Jens Axboe <axboe@kernel.dk> wrote:
>
>
> On Mon, 27 Jul 2026 16:12:57 -0400, Chao Shi wrote:
> > disk_release() undoes blk_mq_init_allocated_queue() for a disk whose
> > probe failed before add_disk(), but it only calls blk_mq_exit_queue().
> > Nothing there stops q->timeout, and that timer rolls forward: it stays
> > pending until it next expires, not until the last request completes.
> > So if the driver issued any I/O before adding the disk, the
> > request_queue is freed while still linked into a timer wheel bucket.
> >
> > [...]
>
> Applied, thanks!
>
> [1/1] block: stop the timeout timer when releasing a never added disk
> commit: 26cb8ebbfaf713c82e142d08828d4d765057633b
>
> Best regards,
> --
> Jens Axboe
>
>
>
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-07-30 19:49 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-07-27 20:12 [PATCH] block: stop the timeout timer when releasing a never added disk Chao Shi
2026-07-28 4:23 ` Christoph Hellwig
2026-07-29 7:55 ` Chris S
2026-07-29 11:23 ` Jens Axboe
2026-07-29 18:05 ` Chris S
2026-07-30 19:42 ` Chris S
2026-07-30 19:48 ` Chris S
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®