diff options
author | Dan Williams <dan.j.williams@intel.com> | 2016-07-31 14:15:13 -0400 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2016-08-04 16:19:16 -0400 |
commit | df08c32ce3be5be138c1dbfcba203314a3a7cd6f (patch) | |
tree | 906ceebd01ea4ff2ff2785c5b6df7fee3faba737 /mm | |
parent | 71f79fb3179e69b0c1448a2101a866d871c66e7f (diff) |
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>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/backing-dev.c | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/mm/backing-dev.c b/mm/backing-dev.c index efe237742074..8fde443f36d7 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c | |||
@@ -825,6 +825,20 @@ int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev) | |||
825 | } | 825 | } |
826 | EXPORT_SYMBOL(bdi_register_dev); | 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 | * Remove bdi from bdi_list, and ensure that it is no longer visible | 843 | * Remove bdi from bdi_list, and ensure that it is no longer visible |
830 | */ | 844 | */ |
@@ -849,6 +863,11 @@ void bdi_unregister(struct backing_dev_info *bdi) | |||
849 | device_unregister(bdi->dev); | 863 | device_unregister(bdi->dev); |
850 | bdi->dev = NULL; | 864 | bdi->dev = NULL; |
851 | } | 865 | } |
866 | |||
867 | if (bdi->owner) { | ||
868 | put_device(bdi->owner); | ||
869 | bdi->owner = NULL; | ||
870 | } | ||
852 | } | 871 | } |
853 | 872 | ||
854 | void bdi_exit(struct backing_dev_info *bdi) | 873 | void bdi_exit(struct backing_dev_info *bdi) |