Skip to content

Commit f9a9098

Browse files
Ming Leigregkh
authored andcommitted
blk-mq: fix lockdep warning in __blk_mq_update_nr_hw_queues
[ Upstream commit 2d82f3b ] Commit 5989bfe ("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 <[email protected]> Cc: Yu Kuai <[email protected]> Fixes: 5989bfe ("block: restore two stage elevator switch while running nr_hw_queue update") Signed-off-by: Ming Lei <[email protected]> Reviewed-by: Yu Kuai <[email protected]> Reviewed-by: Nilay Shroff <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent e01facf commit f9a9098

1 file changed

Lines changed: 9 additions & 4 deletions

File tree

block/blk-mq.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5031,6 +5031,7 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set,
50315031
unsigned int memflags;
50325032
int i;
50335033
struct xarray elv_tbl, et_tbl;
5034+
bool queues_frozen = false;
50345035

50355036
lockdep_assert_held(&set->tag_list_lock);
50365037

@@ -5054,9 +5055,6 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set,
50545055
blk_mq_sysfs_unregister_hctxs(q);
50555056
}
50565057

5057-
list_for_each_entry(q, &set->tag_list, tag_set_list)
5058-
blk_mq_freeze_queue_nomemsave(q);
5059-
50605058
/*
50615059
* Switch IO scheduler to 'none', cleaning up the data associated
50625060
* 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,
50665064
if (blk_mq_elv_switch_none(q, &elv_tbl))
50675065
goto switch_back;
50685066

5067+
list_for_each_entry(q, &set->tag_list, tag_set_list)
5068+
blk_mq_freeze_queue_nomemsave(q);
5069+
queues_frozen = true;
50695070
if (blk_mq_realloc_tag_set_tags(set, nr_hw_queues) < 0)
50705071
goto switch_back;
50715072

@@ -5089,8 +5090,12 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set,
50895090
}
50905091
switch_back:
50915092
/* The blk_mq_elv_switch_back unfreezes queue for us. */
5092-
list_for_each_entry(q, &set->tag_list, tag_set_list)
5093+
list_for_each_entry(q, &set->tag_list, tag_set_list) {
5094+
/* switch_back expects queue to be frozen */
5095+
if (!queues_frozen)
5096+
blk_mq_freeze_queue_nomemsave(q);
50935097
blk_mq_elv_switch_back(q, &elv_tbl, &et_tbl);
5098+
}
50945099

50955100
list_for_each_entry(q, &set->tag_list, tag_set_list) {
50965101
blk_mq_sysfs_register_hctxs(q);

0 commit comments

Comments
 (0)