From 89a2381482d8ff8e4fe0b7d32797bb4f77503b89 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 28 Oct 2026 10:41:40 -0600 Subject: [PATCH] blk-mq: exit the hctxs of a queue under tag_list_lock blk_mq_update_nr_hw_queues() exits and replaces the hctxs of every queue on set->tag_list under tag_list_lock. blk_mq_exit_queue() exits its hctxs without the lock and only then takes the queue off the list, so an update running at the same time exits them again and sets up new ones that nobody exits. del_gendisk() is kept away by update_nr_hwq_lock, disk_release() of a never added disk and blk_mq_destroy_queue() are not, and nvme_alloc_ns() drops such a disk when it finds the queues frozen by a reset. Hold tag_list_lock for both steps. Fixes: 630ef623ed26 ("blk-mq: Swap two calls in blk_mq_exit_queue()") Signed-off-by: Josef Bacik Link: https://patch.msgid.link/20261028164415.1262013-38-axboe@kernel.dk Signed-off-by: Jens Axboe --- block/blk-mq.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/block/blk-mq.c b/block/blk-mq.c index fe7ff041bd6d..6418c2a7cd2c 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -4338,7 +4338,8 @@ static void blk_mq_del_queue_tag_set(struct request_queue *q) { struct blk_mq_tag_set *set = q->tag_set; - mutex_lock(&set->tag_list_lock); + lockdep_assert_held(&set->tag_list_lock); + list_del_rcu(&q->tag_set_list); if (list_is_singular(&set->tag_list)) { /* just transitioned to unshared */ @@ -4346,7 +4347,6 @@ static void blk_mq_del_queue_tag_set(struct request_queue *q) /* update existing queue */ blk_mq_update_tag_set_shared(set, false); } - mutex_unlock(&set->tag_list_lock); } static void blk_mq_add_queue_tag_set(struct blk_mq_tag_set *set, @@ -4710,10 +4710,16 @@ void blk_mq_exit_queue(struct request_queue *q) { struct blk_mq_tag_set *set = q->tag_set; + /* + * As long as the queue is on set->tag_list, its hctxs belong to + * blk_mq_update_nr_hw_queues() as well, which exits and replaces them. + */ + mutex_lock(&set->tag_list_lock); /* Checks hctx->flags & BLK_MQ_F_TAG_QUEUE_SHARED. */ blk_mq_exit_hw_queues(q, set, set->nr_hw_queues); /* May clear BLK_MQ_F_TAG_QUEUE_SHARED in hctx->flags. */ blk_mq_del_queue_tag_set(q); + mutex_unlock(&set->tag_list_lock); } static int __blk_mq_alloc_rq_maps(struct blk_mq_tag_set *set)