So far block_device(for disk), gendisk and request queue are supposed to be killed at the same time, because we can retrieve request queue from both block_device->bd_queue and gendisk->queue directly, meantime disk is associated with request queue directly via q->disk. Also request queue's refcnt is grabbed when allocating disk, and released in disk's release handler. Also we put request queue in disk_release() and clear queue->disk there. Meantime disk can be released before running blk_cleanup_queue(). This way isn't reliable: - some block core code(blk-cgroup, io scheduler, ...) usually deals with request queue only, and sometimes they need to retrieve disk info via q->disk, but both io scheduler and blk-cgroup are shutdown in blk_release_queue() actually, and q->disk can be cleared before releasing queue. - q->disk is referred in fast io code path, such as io account code, but q->disk can be cleared when queue is active since queue is still needed for handling passthrough/private request after disk is deleted Move freeing disk into queue's release handler, so that block_device(for disk), gendisk and request queue can be removed at the same time basically, then q->disk can be used reliably. This way is reasonable too, since request queue becomes dying actually in del_gendisk(), see commit 8e141f9eb803 ("block: drain file system I/O on del_gendisk"). Signed-off-by: Ming Lei <ming.lei@xxxxxxxxxx> --- block/blk-sysfs.c | 13 +++++++++++++ block/genhd.c | 7 +++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index e20eadfcf5c8..dc8af443b29b 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -12,6 +12,7 @@ #include <linux/blk-mq.h> #include <linux/blk-cgroup.h> #include <linux/debugfs.h> +#include <linux/fs.h> #include "blk.h" #include "blk-mq.h" @@ -811,6 +812,18 @@ static void blk_release_queue(struct kobject *kobj) bioset_exit(&q->bio_split); + /* + * Free associated disk now if there is. + * + * Follows cases in which request queue hasn't disk: + * + * - not active LUN probed for scsi host + * + * - nvme's admin queue + */ + if (q->disk) + iput(q->disk->part0->bd_inode); + ida_simple_remove(&blk_queue_ida, q->id); call_rcu(&q->rcu_head, blk_free_queue_rcu); } diff --git a/block/genhd.c b/block/genhd.c index 626c8406f21a..6357cab37eef 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -1112,9 +1112,12 @@ static void disk_release(struct device *dev) disk_release_events(disk); kfree(disk->random); xa_destroy(&disk->part_tbl); - disk->queue->disk = NULL; + + /* + * delay freeing disk/and its bdev into request queue's release + * handler, then all can be killed at the same time + */ blk_put_queue(disk->queue); - iput(disk->part0->bd_inode); /* frees the disk */ } static int block_uevent(struct device *dev, struct kobj_uevent_env *env) -- 2.31.1