diff options
author | Keith Busch <keith.busch@intel.com> | 2014-08-26 11:05:36 -0400 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2014-09-03 17:01:02 -0400 |
commit | 2da78092dda13f1efd26edbbf99a567776913750 (patch) | |
tree | 9f245a022542d626c948ebfb886106ce3f7e62ae /block | |
parent | 5676e7b6db02b80eafc2e3ad316d5f2fee817ecb (diff) |
block: Fix dev_t minor allocation lifetime
Releases the dev_t minor when all references are closed to prevent
another device from acquiring the same major/minor.
Since the partition's release may be invoked from call_rcu's soft-irq
context, the ext_dev_idr's mutex had to be replaced with a spinlock so
as not so sleep.
Signed-off-by: Keith Busch <keith.busch@intel.com>
Cc: stable@kernel.org
Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'block')
-rw-r--r-- | block/genhd.c | 24 | ||||
-rw-r--r-- | block/partition-generic.c | 2 |
2 files changed, 15 insertions, 11 deletions
diff --git a/block/genhd.c b/block/genhd.c index 791f41943132..09da5e4a8e03 100644 --- a/block/genhd.c +++ b/block/genhd.c | |||
@@ -28,10 +28,10 @@ struct kobject *block_depr; | |||
28 | /* for extended dynamic devt allocation, currently only one major is used */ | 28 | /* for extended dynamic devt allocation, currently only one major is used */ |
29 | #define NR_EXT_DEVT (1 << MINORBITS) | 29 | #define NR_EXT_DEVT (1 << MINORBITS) |
30 | 30 | ||
31 | /* For extended devt allocation. ext_devt_mutex prevents look up | 31 | /* For extended devt allocation. ext_devt_lock prevents look up |
32 | * results from going away underneath its user. | 32 | * results from going away underneath its user. |
33 | */ | 33 | */ |
34 | static DEFINE_MUTEX(ext_devt_mutex); | 34 | static DEFINE_SPINLOCK(ext_devt_lock); |
35 | static DEFINE_IDR(ext_devt_idr); | 35 | static DEFINE_IDR(ext_devt_idr); |
36 | 36 | ||
37 | static struct device_type disk_type; | 37 | static struct device_type disk_type; |
@@ -420,9 +420,13 @@ int blk_alloc_devt(struct hd_struct *part, dev_t *devt) | |||
420 | } | 420 | } |
421 | 421 | ||
422 | /* allocate ext devt */ | 422 | /* allocate ext devt */ |
423 | mutex_lock(&ext_devt_mutex); | 423 | idr_preload(GFP_KERNEL); |
424 | idx = idr_alloc(&ext_devt_idr, part, 0, NR_EXT_DEVT, GFP_KERNEL); | 424 | |
425 | mutex_unlock(&ext_devt_mutex); | 425 | spin_lock(&ext_devt_lock); |
426 | idx = idr_alloc(&ext_devt_idr, part, 0, NR_EXT_DEVT, GFP_NOWAIT); | ||
427 | spin_unlock(&ext_devt_lock); | ||
428 | |||
429 | idr_preload_end(); | ||
426 | if (idx < 0) | 430 | if (idx < 0) |
427 | return idx == -ENOSPC ? -EBUSY : idx; | 431 | return idx == -ENOSPC ? -EBUSY : idx; |
428 | 432 | ||
@@ -447,9 +451,9 @@ void blk_free_devt(dev_t devt) | |||
447 | return; | 451 | return; |
448 | 452 | ||
449 | if (MAJOR(devt) == BLOCK_EXT_MAJOR) { | 453 | if (MAJOR(devt) == BLOCK_EXT_MAJOR) { |
450 | mutex_lock(&ext_devt_mutex); | 454 | spin_lock(&ext_devt_lock); |
451 | idr_remove(&ext_devt_idr, blk_mangle_minor(MINOR(devt))); | 455 | idr_remove(&ext_devt_idr, blk_mangle_minor(MINOR(devt))); |
452 | mutex_unlock(&ext_devt_mutex); | 456 | spin_unlock(&ext_devt_lock); |
453 | } | 457 | } |
454 | } | 458 | } |
455 | 459 | ||
@@ -665,7 +669,6 @@ void del_gendisk(struct gendisk *disk) | |||
665 | sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk))); | 669 | sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk))); |
666 | pm_runtime_set_memalloc_noio(disk_to_dev(disk), false); | 670 | pm_runtime_set_memalloc_noio(disk_to_dev(disk), false); |
667 | device_del(disk_to_dev(disk)); | 671 | device_del(disk_to_dev(disk)); |
668 | blk_free_devt(disk_to_dev(disk)->devt); | ||
669 | } | 672 | } |
670 | EXPORT_SYMBOL(del_gendisk); | 673 | EXPORT_SYMBOL(del_gendisk); |
671 | 674 | ||
@@ -690,13 +693,13 @@ struct gendisk *get_gendisk(dev_t devt, int *partno) | |||
690 | } else { | 693 | } else { |
691 | struct hd_struct *part; | 694 | struct hd_struct *part; |
692 | 695 | ||
693 | mutex_lock(&ext_devt_mutex); | 696 | spin_lock(&ext_devt_lock); |
694 | part = idr_find(&ext_devt_idr, blk_mangle_minor(MINOR(devt))); | 697 | part = idr_find(&ext_devt_idr, blk_mangle_minor(MINOR(devt))); |
695 | if (part && get_disk(part_to_disk(part))) { | 698 | if (part && get_disk(part_to_disk(part))) { |
696 | *partno = part->partno; | 699 | *partno = part->partno; |
697 | disk = part_to_disk(part); | 700 | disk = part_to_disk(part); |
698 | } | 701 | } |
699 | mutex_unlock(&ext_devt_mutex); | 702 | spin_unlock(&ext_devt_lock); |
700 | } | 703 | } |
701 | 704 | ||
702 | return disk; | 705 | return disk; |
@@ -1098,6 +1101,7 @@ static void disk_release(struct device *dev) | |||
1098 | { | 1101 | { |
1099 | struct gendisk *disk = dev_to_disk(dev); | 1102 | struct gendisk *disk = dev_to_disk(dev); |
1100 | 1103 | ||
1104 | blk_free_devt(dev->devt); | ||
1101 | disk_release_events(disk); | 1105 | disk_release_events(disk); |
1102 | kfree(disk->random); | 1106 | kfree(disk->random); |
1103 | disk_replace_part_tbl(disk, NULL); | 1107 | disk_replace_part_tbl(disk, NULL); |
diff --git a/block/partition-generic.c b/block/partition-generic.c index 789cdea05893..0d9e5f97f0a8 100644 --- a/block/partition-generic.c +++ b/block/partition-generic.c | |||
@@ -211,6 +211,7 @@ static const struct attribute_group *part_attr_groups[] = { | |||
211 | static void part_release(struct device *dev) | 211 | static void part_release(struct device *dev) |
212 | { | 212 | { |
213 | struct hd_struct *p = dev_to_part(dev); | 213 | struct hd_struct *p = dev_to_part(dev); |
214 | blk_free_devt(dev->devt); | ||
214 | free_part_stats(p); | 215 | free_part_stats(p); |
215 | free_part_info(p); | 216 | free_part_info(p); |
216 | kfree(p); | 217 | kfree(p); |
@@ -253,7 +254,6 @@ void delete_partition(struct gendisk *disk, int partno) | |||
253 | rcu_assign_pointer(ptbl->last_lookup, NULL); | 254 | rcu_assign_pointer(ptbl->last_lookup, NULL); |
254 | kobject_put(part->holder_dir); | 255 | kobject_put(part->holder_dir); |
255 | device_del(part_to_dev(part)); | 256 | 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 | } |