Skip to content

Commit df08c32

Browse files
djbwaxboe
authored andcommitted
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>
1 parent 71f79fb commit df08c32

File tree

4 files changed

+22
-1
lines changed

4 files changed

+22
-1
lines changed

block/genhd.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,7 @@ void device_add_disk(struct device *parent, struct gendisk *disk)
614614

615615
/* Register BDI before referencing it from bdev */
616616
bdi = &disk->queue->backing_dev_info;
617-
bdi_register_dev(bdi, disk_devt(disk));
617+
bdi_register_owner(bdi, disk_to_dev(disk));
618618

619619
blk_register_region(disk_devt(disk), disk->minors, NULL,
620620
exact_match, exact_lock, disk);

include/linux/backing-dev-defs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ struct backing_dev_info {
163163
wait_queue_head_t wb_waitq;
164164

165165
struct device *dev;
166+
struct device *owner;
166167

167168
struct timer_list laptop_mode_wb_timer;
168169

include/linux/backing-dev.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ __printf(3, 4)
2424
int bdi_register(struct backing_dev_info *bdi, struct device *parent,
2525
const char *fmt, ...);
2626
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);
2728
void bdi_unregister(struct backing_dev_info *bdi);
2829

2930
int __must_check bdi_setup_and_register(struct backing_dev_info *, char *);

mm/backing-dev.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,20 @@ int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev)
825825
}
826826
EXPORT_SYMBOL(bdi_register_dev);
827827

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+
828842
/*
829843
* Remove bdi from bdi_list, and ensure that it is no longer visible
830844
*/
@@ -849,6 +863,11 @@ void bdi_unregister(struct backing_dev_info *bdi)
849863
device_unregister(bdi->dev);
850864
bdi->dev = NULL;
851865
}
866+
867+
if (bdi->owner) {
868+
put_device(bdi->owner);
869+
bdi->owner = NULL;
870+
}
852871
}
853872

854873
void bdi_exit(struct backing_dev_info *bdi)

0 commit comments

Comments
 (0)