block: unifying elevator change

Elevator change is one well-define behavior:

- tear down current elevator if it exists

- setup new elevator

It is supposed to cover any case for changing elevator by single
internal API, typically the following cases:

- setup default elevator in add_disk()

- switch to none in del_disk()

- reset elevator in blk_mq_update_nr_hw_queues()

- switch elevator in sysfs `store` elevator attribute

This patch uses elevator_change() to cover all above cases:

- every elevator switch is serialized with each other: add_disk/del_disk/
store elevator is serialized already, blk_mq_update_nr_hw_queues() uses
srcu for syncing with the other three cases

- for both add_disk()/del_disk(), queue freeze works at atomic mode
or has been froze, so the freeze in elevator_change() won't add extra
delay

- `struct elev_change_ctx` instance holds any info for changing elevator

Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Nilay Shroff <nilay@linux.ibm.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Ming Lei <ming.lei@redhat.com>
Link: https://lore.kernel.org/r/20250505141805.2751237-17-ming.lei@redhat.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
Ming Lei
2025-05-05 22:17:54 +08:00
committed by Jens Axboe
parent 1e9db5c427
commit 1e44bedbc9
4 changed files with 67 additions and 101 deletions

View File

@@ -869,14 +869,9 @@ int blk_register_queue(struct gendisk *disk)
if (ret)
goto out_unregister_ia_ranges;
if (queue_is_mq(q))
elevator_set_default(q);
mutex_lock(&q->elevator_lock);
if (q->elevator) {
ret = elv_register_queue(q, false);
if (ret) {
mutex_unlock(&q->elevator_lock);
goto out_crypto_sysfs_unregister;
}
}
wbt_enable_default(disk);
mutex_unlock(&q->elevator_lock);
@@ -902,8 +897,6 @@ int blk_register_queue(struct gendisk *disk)
return ret;
out_crypto_sysfs_unregister:
blk_crypto_sysfs_unregister(disk);
out_unregister_ia_ranges:
disk_unregister_independent_access_ranges(disk);
out_debugfs_remove:
@@ -951,9 +944,11 @@ void blk_unregister_queue(struct gendisk *disk)
blk_mq_sysfs_unregister(disk);
blk_crypto_sysfs_unregister(disk);
mutex_lock(&q->elevator_lock);
elv_unregister_queue(q);
mutex_unlock(&q->elevator_lock);
if (queue_is_mq(q)) {
blk_mq_quiesce_queue(q);
elevator_set_none(q);
blk_mq_unquiesce_queue(q);
}
mutex_lock(&q->sysfs_lock);
disk_unregister_independent_access_ranges(disk);