aboutsummaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorTomas Henzl2013-02-27 19:03:32 -0600
committerGreg Kroah-Hartman2013-03-03 16:03:35 -0600
commitc5799187ac9e45170a0ddfe1df074227b9a0b8f6 (patch)
tree38e1fe84b963cb6dfb034061166d2f35556c6fbe /block
parent68719e23c62aff61969713cd2158dd0fa37d45cd (diff)
downloadkernel-omap-c5799187ac9e45170a0ddfe1df074227b9a0b8f6.tar.gz
kernel-omap-c5799187ac9e45170a0ddfe1df074227b9a0b8f6.tar.xz
kernel-omap-c5799187ac9e45170a0ddfe1df074227b9a0b8f6.zip
block: fix ext_devt_idr handling
commit 7b74e912785a11572da43292786ed07ada7e3e0c 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 <thenzl@redhat.com> Cc: Jens Axboe <axboe@kernel.dk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'block')
-rw-r--r--block/genhd.c6
-rw-r--r--block/partition-generic.c2
2 files changed, 6 insertions, 2 deletions
diff --git a/block/genhd.c b/block/genhd.c
index 3993ebf4135f..35d0290885aa 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -422,14 +422,18 @@ int blk_alloc_devt(struct hd_struct *part, dev_t *devt)
422 do { 422 do {
423 if (!idr_pre_get(&ext_devt_idr, GFP_KERNEL)) 423 if (!idr_pre_get(&ext_devt_idr, GFP_KERNEL))
424 return -ENOMEM; 424 return -ENOMEM;
425 mutex_lock(&ext_devt_mutex);
425 rc = idr_get_new(&ext_devt_idr, part, &idx); 426 rc = idr_get_new(&ext_devt_idr, part, &idx);
427 mutex_unlock(&ext_devt_mutex);
426 } while (rc == -EAGAIN); 428 } while (rc == -EAGAIN);
427 429
428 if (rc) 430 if (rc)
429 return rc; 431 return rc;
430 432
431 if (idx > MAX_EXT_DEVT) { 433 if (idx > MAX_EXT_DEVT) {
434 mutex_lock(&ext_devt_mutex);
432 idr_remove(&ext_devt_idr, idx); 435 idr_remove(&ext_devt_idr, idx);
436 mutex_unlock(&ext_devt_mutex);
433 return -EBUSY; 437 return -EBUSY;
434 } 438 }
435 439
@@ -646,7 +650,6 @@ void del_gendisk(struct gendisk *disk)
646 disk_part_iter_exit(&piter); 650 disk_part_iter_exit(&piter);
647 651
648 invalidate_partition(disk, 0); 652 invalidate_partition(disk, 0);
649 blk_free_devt(disk_to_dev(disk)->devt);
650 set_capacity(disk, 0); 653 set_capacity(disk, 0);
651 disk->flags &= ~GENHD_FL_UP; 654 disk->flags &= ~GENHD_FL_UP;
652 655
@@ -664,6 +667,7 @@ void del_gendisk(struct gendisk *disk)
664 if (!sysfs_deprecated) 667 if (!sysfs_deprecated)
665 sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk))); 668 sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk)));
666 device_del(disk_to_dev(disk)); 669 device_del(disk_to_dev(disk));
670 blk_free_devt(disk_to_dev(disk)->devt);
667} 671}
668EXPORT_SYMBOL(del_gendisk); 672EXPORT_SYMBOL(del_gendisk);
669 673
diff --git a/block/partition-generic.c b/block/partition-generic.c
index f1d14519cc04..1cb4deca1324 100644
--- a/block/partition-generic.c
+++ b/block/partition-generic.c
@@ -249,11 +249,11 @@ void delete_partition(struct gendisk *disk, int partno)
249 if (!part) 249 if (!part)
250 return; 250 return;
251 251
252 blk_free_devt(part_devt(part));
253 rcu_assign_pointer(ptbl->part[partno], NULL); 252 rcu_assign_pointer(ptbl->part[partno], NULL);
254 rcu_assign_pointer(ptbl->last_lookup, NULL); 253 rcu_assign_pointer(ptbl->last_lookup, NULL);
255 kobject_put(part->holder_dir); 254 kobject_put(part->holder_dir);
256 device_del(part_to_dev(part)); 255 device_del(part_to_dev(part));
256 blk_free_devt(part_devt(part));
257 257
258 hd_struct_put(part); 258 hd_struct_put(part);
259} 259}