Skip to content

Commit 9de5cb0

Browse files
thenzlz3DD3r
authored andcommitted
block: fix ext_devt_idr handling
commit 7b74e91 upstream. While adding and removing a lot of disks disks and partitions this sometimes shows up: WARNING: at fs/sysfs/dir.c:512 sysfs_add_one+0xc9/0x130() (Not tainted) Hardware name: sysfs: cannot create duplicate filename '/dev/block/259:751' Modules linked in: raid1 autofs4 bnx2fc cnic uio fcoe libfcoe libfc 8021q scsi_transport_fc scsi_tgt garp stp llc sunrpc cpufreq_ondemand powernow_k8 freq_table mperf ipv6 dm_mirror dm_region_hash dm_log power_meter microcode dcdbas serio_raw amd64_edac_mod edac_core edac_mce_amd i2c_piix4 i2c_core k10temp bnx2 sg ixgbe dca mdio ext4 mbcache jbd2 dm_round_robin sr_mod cdrom sd_mod crc_t10dif ata_generic pata_acpi pata_atiixp ahci mptsas mptscsih mptbase scsi_transport_sas dm_multipath dm_mod [last unloaded: scsi_wait_scan] Pid: 44103, comm: async/16 Not tainted 2.6.32-195.el6.x86_64 #1 Call Trace: warn_slowpath_common+0x87/0xc0 warn_slowpath_fmt+0x46/0x50 sysfs_add_one+0xc9/0x130 sysfs_do_create_link+0x12b/0x170 sysfs_create_link+0x13/0x20 device_add+0x317/0x650 idr_get_new+0x13/0x50 add_partition+0x21c/0x390 rescan_partitions+0x32b/0x470 sd_open+0x81/0x1f0 [sd_mod] __blkdev_get+0x1b6/0x3c0 blkdev_get+0x10/0x20 register_disk+0x155/0x170 add_disk+0xa6/0x160 sd_probe_async+0x13b/0x210 [sd_mod] add_wait_queue+0x46/0x60 async_thread+0x102/0x250 default_wake_function+0x0/0x20 async_thread+0x0/0x250 kthread+0x96/0xa0 child_rip+0xa/0x20 kthread+0x0/0xa0 child_rip+0x0/0x20 This most likely happens because dev_t is freed while the number is still used and idr_get_new() is not protected on every use. The fix adds a mutex where it wasn't before and moves the dev_t free function so it is called after device del. Signed-off-by: Tomas Henzl <[email protected]> Cc: Jens Axboe <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 6bf0f00 commit 9de5cb0

File tree

2 files changed

+6
-2
lines changed

2 files changed

+6
-2
lines changed

block/genhd.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,14 +420,18 @@ int blk_alloc_devt(struct hd_struct *part, dev_t *devt)
420420
do {
421421
if (!idr_pre_get(&ext_devt_idr, GFP_KERNEL))
422422
return -ENOMEM;
423+
mutex_lock(&ext_devt_mutex);
423424
rc = idr_get_new(&ext_devt_idr, part, &idx);
425+
mutex_unlock(&ext_devt_mutex);
424426
} while (rc == -EAGAIN);
425427

426428
if (rc)
427429
return rc;
428430

429431
if (idx > MAX_EXT_DEVT) {
432+
mutex_lock(&ext_devt_mutex);
430433
idr_remove(&ext_devt_idr, idx);
434+
mutex_unlock(&ext_devt_mutex);
431435
return -EBUSY;
432436
}
433437

@@ -644,7 +648,6 @@ void del_gendisk(struct gendisk *disk)
644648
disk_part_iter_exit(&piter);
645649

646650
invalidate_partition(disk, 0);
647-
blk_free_devt(disk_to_dev(disk)->devt);
648651
set_capacity(disk, 0);
649652
disk->flags &= ~GENHD_FL_UP;
650653

@@ -662,6 +665,7 @@ void del_gendisk(struct gendisk *disk)
662665
if (!sysfs_deprecated)
663666
sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk)));
664667
device_del(disk_to_dev(disk));
668+
blk_free_devt(disk_to_dev(disk)->devt);
665669
}
666670
EXPORT_SYMBOL(del_gendisk);
667671

block/partition-generic.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,11 +260,11 @@ void delete_partition(struct gendisk *disk, int partno)
260260
if (!part)
261261
return;
262262

263-
blk_free_devt(part_devt(part));
264263
rcu_assign_pointer(ptbl->part[partno], NULL);
265264
rcu_assign_pointer(ptbl->last_lookup, NULL);
266265
kobject_put(part->holder_dir);
267266
device_del(part_to_dev(part));
267+
blk_free_devt(part_devt(part));
268268

269269
hd_struct_put(part);
270270
}

0 commit comments

Comments
 (0)