]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
block: fix bdi vs gendisk lifetime mismatch
authorShan Hai <shan.hai@oracle.com>
Fri, 30 Nov 2018 00:56:52 +0000 (08:56 +0800)
committerBrian Maly <brian.maly@oracle.com>
Tue, 4 Dec 2018 18:15:13 +0000 (13:15 -0500)
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 <ashish.samant@oracle.com>
  o update inline comment

Signed-off-by: Shan Hai <shan.hai@oracle.com>
Reviewed-by: Ashish Samant <ashish.samant@oracle.com>
Signed-off-by: Brian Maly <brian.maly@oracle.com>
block/blk-core.c
block/genhd.c
include/linux/blkdev.h

index f2dae161d5a0ba1e77ac1e6d56bc2680c3608a31..fdce89bab683b3b00def3f9ef33538df5355949e 100644 (file)
@@ -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);
 }
index 60db28598670da7a802997810f91ca9a9f33c83e..db3571908616237ddde616ef374c0fac35c6e7c5 100644 (file)
@@ -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);
index 851a75fbf80fe252e2727a9a51345682d6c012eb..8bb62bfc2342edb371a0c25061ff2441f2c62303 100644 (file)
@@ -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 */