[PATCH] blk-mq: reset queue state on scheduler teardown

From: Jianan Huang

Date: Fri Oct 23 2026 - 05:27:52 EST


We observed I/O timeouts with requests stalled in per-CPU software
queues.

The affected queue had no elevator, but QUEUE_FLAG_SQ_SCHED remained
set. A failed elevator switch can leave this state when falling back to
none without clearing the flag. With empty hctx dispatch lists, a
queue-wide restart on CPU4 would skip requests pending in ctx5/ctx7:

CPU4: blk_mq_run_hw_queues(q)
sq_hctx = hctx4
hctx4: no pending requests -> selected
hctx5: 9 reads in ctx5 -> skipped
hctx7: 3 writes in ctx7 -> skipped

The pending requests may remain undispatched until another event runs
their hardware queues.

Clear the flag and restore nr_requests and async_depth to the driver
queue depth in the common scheduler teardown path, covering both
scheduler exit and failed initialization.

Fixes: 4d337cebcb1c ("blk-mq: avoid to touch q->elevator without any protection")
Assisted-by: LLM
Signed-off-by: Jianan Huang <jnhuang95@xxxxxxxxx>
---
block/blk-mq-sched.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/block/blk-mq-sched.c b/block/blk-mq-sched.c
index 0a00f5a76f5a..d7b45778732b 100644
--- a/block/blk-mq-sched.c
+++ b/block/blk-mq-sched.c
@@ -374,7 +374,7 @@ bool blk_mq_sched_try_insert_merge(struct request_queue *q, struct request *rq,
}
EXPORT_SYMBOL_GPL(blk_mq_sched_try_insert_merge);

-/* called in queue's release handler, tagset has gone away */
+/* Clear scheduler tags and reset queue state. */
static void blk_mq_sched_tags_teardown(struct request_queue *q, unsigned int flags)
{
struct blk_mq_hw_ctx *hctx;
@@ -385,6 +385,10 @@ static void blk_mq_sched_tags_teardown(struct request_queue *q, unsigned int fla

if (blk_mq_is_shared_tags(flags))
q->sched_shared_tags = NULL;
+
+ blk_queue_flag_clear(QUEUE_FLAG_SQ_SCHED, q);
+ q->nr_requests = q->tag_set->queue_depth;
+ q->async_depth = q->tag_set->queue_depth;
}

void blk_mq_sched_reg_debugfs(struct request_queue *q)
--
2.43.0