Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

blk-mq: fix lockdep warning in __blk_mq_update_nr_hw_queues

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>

authored by

Ming Lei and committed by
Jens Axboe
2d82f3bd d0a2b527

+9 -4
+9 -4
block/blk-mq.c
··· 5033 5033 unsigned int memflags; 5034 5034 int i; 5035 5035 struct xarray elv_tbl, et_tbl; 5036 + bool queues_frozen = false; 5036 5037 5037 5038 lockdep_assert_held(&set->tag_list_lock); 5038 5039 ··· 5057 5056 blk_mq_sysfs_unregister_hctxs(q); 5058 5057 } 5059 5058 5060 - list_for_each_entry(q, &set->tag_list, tag_set_list) 5061 - blk_mq_freeze_queue_nomemsave(q); 5062 - 5063 5059 /* 5064 5060 * Switch IO scheduler to 'none', cleaning up the data associated 5065 5061 * with the previous scheduler. We will switch back once we are done ··· 5066 5068 if (blk_mq_elv_switch_none(q, &elv_tbl)) 5067 5069 goto switch_back; 5068 5070 5071 + list_for_each_entry(q, &set->tag_list, tag_set_list) 5072 + blk_mq_freeze_queue_nomemsave(q); 5073 + queues_frozen = true; 5069 5074 if (blk_mq_realloc_tag_set_tags(set, nr_hw_queues) < 0) 5070 5075 goto switch_back; 5071 5076 ··· 5092 5091 } 5093 5092 switch_back: 5094 5093 /* The blk_mq_elv_switch_back unfreezes queue for us. */ 5095 - list_for_each_entry(q, &set->tag_list, tag_set_list) 5094 + list_for_each_entry(q, &set->tag_list, tag_set_list) { 5095 + /* switch_back expects queue to be frozen */ 5096 + if (!queues_frozen) 5097 + blk_mq_freeze_queue_nomemsave(q); 5096 5098 blk_mq_elv_switch_back(q, &elv_tbl, &et_tbl); 5099 + } 5097 5100 5098 5101 list_for_each_entry(q, &set->tag_list, tag_set_list) { 5099 5102 blk_mq_sysfs_register_hctxs(q);