Commit df08c32ce3be5be138c1dbfcba203314a3a7cd6f
Committed by
Jens Axboe
1 parent
71f79fb317
Exists in
smarct4x-processor-sdk-04.01.00.06
and in
1 other branch
block: fix bdi vs gendisk lifetime mismatch
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>
Showing 4 changed files with 22 additions and 1 deletions Side-by-side Diff
block/genhd.c
... | ... | @@ -614,7 +614,7 @@ |
614 | 614 | |
615 | 615 | /* Register BDI before referencing it from bdev */ |
616 | 616 | bdi = &disk->queue->backing_dev_info; |
617 | - bdi_register_dev(bdi, disk_devt(disk)); | |
617 | + bdi_register_owner(bdi, disk_to_dev(disk)); | |
618 | 618 | |
619 | 619 | blk_register_region(disk_devt(disk), disk->minors, NULL, |
620 | 620 | exact_match, exact_lock, disk); |
include/linux/backing-dev-defs.h
include/linux/backing-dev.h
... | ... | @@ -24,6 +24,7 @@ |
24 | 24 | int bdi_register(struct backing_dev_info *bdi, struct device *parent, |
25 | 25 | const char *fmt, ...); |
26 | 26 | int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev); |
27 | +int bdi_register_owner(struct backing_dev_info *bdi, struct device *owner); | |
27 | 28 | void bdi_unregister(struct backing_dev_info *bdi); |
28 | 29 | |
29 | 30 | int __must_check bdi_setup_and_register(struct backing_dev_info *, char *); |
mm/backing-dev.c
... | ... | @@ -825,6 +825,20 @@ |
825 | 825 | } |
826 | 826 | EXPORT_SYMBOL(bdi_register_dev); |
827 | 827 | |
828 | +int bdi_register_owner(struct backing_dev_info *bdi, struct device *owner) | |
829 | +{ | |
830 | + int rc; | |
831 | + | |
832 | + rc = bdi_register(bdi, NULL, "%u:%u", MAJOR(owner->devt), | |
833 | + MINOR(owner->devt)); | |
834 | + if (rc) | |
835 | + return rc; | |
836 | + bdi->owner = owner; | |
837 | + get_device(owner); | |
838 | + return 0; | |
839 | +} | |
840 | +EXPORT_SYMBOL(bdi_register_owner); | |
841 | + | |
828 | 842 | /* |
829 | 843 | * Remove bdi from bdi_list, and ensure that it is no longer visible |
830 | 844 | */ |
... | ... | @@ -848,6 +862,11 @@ |
848 | 862 | bdi_debug_unregister(bdi); |
849 | 863 | device_unregister(bdi->dev); |
850 | 864 | bdi->dev = NULL; |
865 | + } | |
866 | + | |
867 | + if (bdi->owner) { | |
868 | + put_device(bdi->owner); | |
869 | + bdi->owner = NULL; | |
851 | 870 | } |
852 | 871 | } |
853 | 872 |