From: Shan Hai Date: Fri, 30 Nov 2018 00:56:52 +0000 (+0800) Subject: block: fix bdi vs gendisk lifetime mismatch X-Git-Tag: v4.1.12-124.31.3~388 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=8cb3e03c37591f10a6ace2e02903ce6d6d685850;p=users%2Fjedix%2Flinux-maple.git block: fix bdi vs gendisk lifetime mismatch Orabug: 28945039 Inspired by upstream commit df08c32ce3be5be138c1dbfcba203314a3a7cd6f The kABI breakage caused by the above upstream commit cannot be fixed by the uek_abi facilities because it extends a data structure which is embedded inside other data structures in block and filesystem codes. This patch fixes the breakage by moving the "owner" field from backing_dev_info to request_queue structure, it's safe to do this for below reasons: o the purpose of the upstream commit is just hold a reference to the gendisk in backing_dev_info to sync their lifetimes o the backing_dev_info is embedded into the request_queue, which means their lifetimes are in sync o so the lifetime of gendisk can be synced with any of request_queue or backing_dev_info o syncing with request_queue does not break kABI o we extended the request_queue structure previously and no third party binary driver breakage was reported The reason why crafted another patch instead of cherry-picking the upstream commit directly is that because including of blkdev.h in mm/backing_dev.c broke kABI too, note it's just inclusion without other changes. Open coded the get/set of owner field of request_queue to reduce the impact on blkdev.h to avoid other potential kABI breakage. v2: o move put owner after bdi_destroy(), followed the suggestion from Ashish Samant o update inline comment Signed-off-by: Shan Hai Reviewed-by: Ashish Samant Signed-off-by: Brian Maly --- diff --git a/block/blk-core.c b/block/blk-core.c index f2dae161d5a0..fdce89bab683 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -552,6 +552,11 @@ void blk_cleanup_queue(struct request_queue *q) bdi_destroy(&q->backing_dev_info); + if (q->owner) { + put_device(q->owner); + q->owner = NULL; + } + /* @q is and will stay empty, shutdown and put */ blk_put_queue(q); } diff --git a/block/genhd.c b/block/genhd.c index 60db28598670..db3571908616 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -613,6 +613,13 @@ void add_disk(struct gendisk *disk) /* Register BDI before referencing it from bdev */ bdi = &disk->queue->backing_dev_info; bdi_register_dev(bdi, disk_devt(disk)); + /* + * Get ref on gendisk and put it on blk_cleanup_queue() to avoid + * reuse of the same devt as name of bdi since the gendisk can be + * destroyed before bdi. + */ + disk->queue->owner = disk_to_dev(disk); + get_device(disk->queue->owner); blk_register_region(disk_devt(disk), disk->minors, NULL, exact_match, exact_lock, disk); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 851a75fbf80f..8bb62bfc2342 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -510,6 +510,7 @@ struct request_queue { struct blk_mq_tag_set *tag_set; struct list_head tag_set_list; UEK_KABI_EXTEND(struct work_struct timeout_work) + UEK_KABI_EXTEND(struct device *owner) }; #define QUEUE_FLAG_QUEUED 1 /* uses generic tag queueing */