]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
blk-mq: fix lockdep warning in __blk_mq_update_nr_hw_queues
authorMing Lei <ming.lei@redhat.com>
Fri, 15 Aug 2025 13:17:37 +0000 (21:17 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 28 Aug 2025 14:34:50 +0000 (16:34 +0200)
[ Upstream commit 2d82f3bd8910eb65e30bb2a3c9b945bfb3b6d661 ]

Commit 5989bfe6ac6b ("block: restore two stage elevator switch while
running nr_hw_queue update") reintroduced a lockdep warning by calling
blk_mq_freeze_queue_nomemsave() before switching the I/O scheduler.

The function blk_mq_elv_switch_none() calls elevator_change_done().
Running this while the queue is frozen causes a lockdep warning.

Fix this by reordering the operations: first, switch the I/O scheduler
to 'none', and then freeze the queue. This ensures that elevator_change_done()
is not called on an already frozen queue. And this way is safe because
elevator_set_none() does freeze queue before switching to none.

Also we still have to rely on blk_mq_elv_switch_back() for switching
back, and it has to cover unfrozen queue case.

Cc: Nilay Shroff <nilay@linux.ibm.com>
Cc: Yu Kuai <yukuai3@huawei.com>
Fixes: 5989bfe6ac6b ("block: restore two stage elevator switch while running nr_hw_queue update")
Signed-off-by: Ming Lei <ming.lei@redhat.com>
Reviewed-by: Yu Kuai <yukuai3@huawei.com>
Reviewed-by: Nilay Shroff <nilay@linux.ibm.com>
Link: https://lore.kernel.org/r/20250815131737.331692-1-ming.lei@redhat.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
block/blk-mq.c

index 4cb2f5ca86564f585ab30ca72770a7754832b626..355db0abe44b860e858300fe842bce5616058f5f 100644 (file)
@@ -5031,6 +5031,7 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set,
        unsigned int memflags;
        int i;
        struct xarray elv_tbl, et_tbl;
+       bool queues_frozen = false;
 
        lockdep_assert_held(&set->tag_list_lock);
 
@@ -5054,9 +5055,6 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set,
                blk_mq_sysfs_unregister_hctxs(q);
        }
 
-       list_for_each_entry(q, &set->tag_list, tag_set_list)
-               blk_mq_freeze_queue_nomemsave(q);
-
        /*
         * Switch IO scheduler to 'none', cleaning up the data associated
         * with the previous scheduler. We will switch back once we are done
@@ -5066,6 +5064,9 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set,
                if (blk_mq_elv_switch_none(q, &elv_tbl))
                        goto switch_back;
 
+       list_for_each_entry(q, &set->tag_list, tag_set_list)
+               blk_mq_freeze_queue_nomemsave(q);
+       queues_frozen = true;
        if (blk_mq_realloc_tag_set_tags(set, nr_hw_queues) < 0)
                goto switch_back;
 
@@ -5089,8 +5090,12 @@ fallback:
        }
 switch_back:
        /* The blk_mq_elv_switch_back unfreezes queue for us. */
-       list_for_each_entry(q, &set->tag_list, tag_set_list)
+       list_for_each_entry(q, &set->tag_list, tag_set_list) {
+               /* switch_back expects queue to be frozen */
+               if (!queues_frozen)
+                       blk_mq_freeze_queue_nomemsave(q);
                blk_mq_elv_switch_back(q, &elv_tbl, &et_tbl);
+       }
 
        list_for_each_entry(q, &set->tag_list, tag_set_list) {
                blk_mq_sysfs_register_hctxs(q);