]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
block: fix bdi vs gendisk lifetime mismatch
authorDan Williams <dan.j.williams@intel.com>
Sat, 15 Sep 2018 00:34:35 +0000 (17:34 -0700)
committerBrian Maly <brian.maly@oracle.com>
Tue, 30 Oct 2018 17:27:27 +0000 (13:27 -0400)
Orabug: 28645416

The name for a bdi of a gendisk is derived from the gendisk's devt.
However, since the gendisk is destroyed before the bdi it leaves a
window where a new gendisk could dynamically reuse the same devt
while a bdi with the same name is still live.  Arrange for the bdi to hold a
reference against its "owner" disk device while it is registered.
Otherwise we can hit sysfs duplicate name collisions like the
following:

WARNING: CPU: 10 PID: 2078 at fs/sysfs/dir.c:31
sysfs_warn_dup+0x64/0x80
sysfs: cannot create duplicate filename
'/devices/virtual/bdi/259:1'

Hardware name: HP ProLiant DL580 Gen8, BIOS P79 05/06/2015
0000000000000286 0000000002c04ad5 ffff88006f24f970 ffffffff8134caec
ffff88006f24f9c0 0000000000000000 ffff88006f24f9b0 ffffffff8108c351
0000001f0000000c ffff88105d236000 ffff88105d1031e0 ffff8800357427f8
Call Trace:
 [<ffffffff8134caec>] dump_stack+0x63/0x87
 [<ffffffff8108c351>] __warn+0xd1/0xf0
 [<ffffffff8108c3cf>] warn_slowpath_fmt+0x5f/0x80
 [<ffffffff812a0d34>] sysfs_warn_dup+0x64/0x80
 [<ffffffff812a0e1e>] sysfs_create_dir_ns+0x7e/0x90
 [<ffffffff8134faaa>] kobject_add_internal+0xaa/0x320
 [<ffffffff81358d4e>] ? vsnprintf+0x34e/0x4d0
 [<ffffffff8134ff55>] kobject_add+0x75/0xd0
 [<ffffffff816e66b2>] ? mutex_lock+0x12/0x2f
 [<ffffffff8148b0a5>] device_add+0x125/0x610
 [<ffffffff8148b788>] device_create_groups_vargs+0xd8/0x100
 [<ffffffff8148b7cc>] device_create_vargs+0x1c/0x20
 [<ffffffff811b775c>] bdi_register+0x8c/0x180
 [<ffffffff811b7877>] bdi_register_dev+0x27/0x30
 [<ffffffff813317f5>] add_disk+0x175/0x4a0

Cc: <stable@vger.kernel.org>
Reported-by: Yi Zhang <yizhan@redhat.com>
Tested-by: Yi Zhang <yizhan@redhat.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Fixed up missing 0 return in bdi_register_owner().

Signed-off-by: Jens Axboe <axboe@fb.com>
(cherrypicked from commit df08c32ce3be5be138c1dbfcba203314a3a7cd6f)
Conflicts: mm/backing-dev.c
           include/linux/backing-dev.h

The patch breaks KABI as-is because of the introduction of a new "owner"
field in struct backing_dev_info. To work around that, use the
UEK_KABI_EXTEND() macro to wrap the "owner" filed with ifdef GENKSYMS.

Signed-off-by: Ashish Samant <ashish.samant@oracle.com>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Brian Maly <brian.maly@oracle.com>
block/genhd.c
include/linux/backing-dev.h
mm/backing-dev.c

index 60db28598670da7a802997810f91ca9a9f33c83e..24fcb43e61ee6a60a166974d2d425d02a603b971 100644 (file)
@@ -612,7 +612,7 @@ 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));
+       bdi_register_owner(bdi, disk_to_dev(disk));
 
        blk_register_region(disk_devt(disk), disk->minors, NULL,
                            exact_match, exact_lock, disk);
index d87d8eced06407c59c6d231f9e707bdcc398ce52..3cf1f7409a7c7f54a275a0866dd4863180d3b8a0 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/atomic.h>
 #include <linux/sysctl.h>
 #include <linux/workqueue.h>
+#include <linux/uek_kabi.h>
 
 struct page;
 struct device;
@@ -105,6 +106,7 @@ struct backing_dev_info {
        struct dentry *debug_dir;
        struct dentry *debug_stats;
 #endif
+       UEK_KABI_EXTEND(struct device *owner)
 };
 
 struct backing_dev_info *inode_to_bdi(struct inode *inode);
@@ -116,6 +118,7 @@ __printf(3, 4)
 int bdi_register(struct backing_dev_info *bdi, struct device *parent,
                const char *fmt, ...);
 int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev);
+int bdi_register_owner(struct backing_dev_info *bdi, struct device *owner);
 int __must_check bdi_setup_and_register(struct backing_dev_info *, char *);
 void bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages,
                        enum wb_reason reason);
index 000e7b3b9896f2a9479687befd2442c43193614e..d9ec4976f5f171cedf6b30627e4f6c8e1f8118b3 100644 (file)
@@ -332,6 +332,20 @@ int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev)
 }
 EXPORT_SYMBOL(bdi_register_dev);
 
+int bdi_register_owner(struct backing_dev_info *bdi, struct device *owner)
+{
+       int rc;
+
+       rc = bdi_register(bdi, NULL, "%u:%u", MAJOR(owner->devt),
+                         MINOR(owner->devt));
+       if (rc)
+               return rc;
+       bdi->owner = owner;
+       get_device(owner);
+       return 0;
+}
+EXPORT_SYMBOL(bdi_register_owner);
+
 /*
  * Remove bdi from the global list and shutdown any threads we have running
  */
@@ -437,6 +451,11 @@ void bdi_destroy(struct backing_dev_info *bdi)
                bdi->dev = NULL;
        }
 
+       if (bdi->owner) {
+               put_device(bdi->owner);
+               bdi->owner = NULL;
+       }
+
        for (i = 0; i < NR_BDI_STAT_ITEMS; i++)
                percpu_counter_destroy(&bdi->bdi_stat[i]);
        fprop_local_destroy_percpu(&bdi->completions);