Skip to content

Commit 2da7809

Browse files
Keith Buschaxboe
Keith Busch
authored andcommitted
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 <[email protected]> Cc: [email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent 5676e7b commit 2da7809

File tree

2 files changed

+15
-11
lines changed

2 files changed

+15
-11
lines changed

block/genhd.c

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ struct kobject *block_depr;
2828
/* for extended dynamic devt allocation, currently only one major is used */
2929
#define NR_EXT_DEVT (1 << MINORBITS)
3030

31-
/* For extended devt allocation. ext_devt_mutex prevents look up
31+
/* For extended devt allocation. ext_devt_lock prevents look up
3232
* results from going away underneath its user.
3333
*/
34-
static DEFINE_MUTEX(ext_devt_mutex);
34+
static DEFINE_SPINLOCK(ext_devt_lock);
3535
static DEFINE_IDR(ext_devt_idr);
3636

3737
static struct device_type disk_type;
@@ -420,9 +420,13 @@ int blk_alloc_devt(struct hd_struct *part, dev_t *devt)
420420
}
421421

422422
/* allocate ext devt */
423-
mutex_lock(&ext_devt_mutex);
424-
idx = idr_alloc(&ext_devt_idr, part, 0, NR_EXT_DEVT, GFP_KERNEL);
425-
mutex_unlock(&ext_devt_mutex);
423+
idr_preload(GFP_KERNEL);
424+
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();
426430
if (idx < 0)
427431
return idx == -ENOSPC ? -EBUSY : idx;
428432

@@ -447,9 +451,9 @@ void blk_free_devt(dev_t devt)
447451
return;
448452

449453
if (MAJOR(devt) == BLOCK_EXT_MAJOR) {
450-
mutex_lock(&ext_devt_mutex);
454+
spin_lock(&ext_devt_lock);
451455
idr_remove(&ext_devt_idr, blk_mangle_minor(MINOR(devt)));
452-
mutex_unlock(&ext_devt_mutex);
456+
spin_unlock(&ext_devt_lock);
453457
}
454458
}
455459

@@ -665,7 +669,6 @@ void del_gendisk(struct gendisk *disk)
665669
sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk)));
666670
pm_runtime_set_memalloc_noio(disk_to_dev(disk), false);
667671
device_del(disk_to_dev(disk));
668-
blk_free_devt(disk_to_dev(disk)->devt);
669672
}
670673
EXPORT_SYMBOL(del_gendisk);
671674

@@ -690,13 +693,13 @@ struct gendisk *get_gendisk(dev_t devt, int *partno)
690693
} else {
691694
struct hd_struct *part;
692695

693-
mutex_lock(&ext_devt_mutex);
696+
spin_lock(&ext_devt_lock);
694697
part = idr_find(&ext_devt_idr, blk_mangle_minor(MINOR(devt)));
695698
if (part && get_disk(part_to_disk(part))) {
696699
*partno = part->partno;
697700
disk = part_to_disk(part);
698701
}
699-
mutex_unlock(&ext_devt_mutex);
702+
spin_unlock(&ext_devt_lock);
700703
}
701704

702705
return disk;
@@ -1098,6 +1101,7 @@ static void disk_release(struct device *dev)
10981101
{
10991102
struct gendisk *disk = dev_to_disk(dev);
11001103

1104+
blk_free_devt(dev->devt);
11011105
disk_release_events(disk);
11021106
kfree(disk->random);
11031107
disk_replace_part_tbl(disk, NULL);

block/partition-generic.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ static const struct attribute_group *part_attr_groups[] = {
211211
static void part_release(struct device *dev)
212212
{
213213
struct hd_struct *p = dev_to_part(dev);
214+
blk_free_devt(dev->devt);
214215
free_part_stats(p);
215216
free_part_info(p);
216217
kfree(p);
@@ -253,7 +254,6 @@ void delete_partition(struct gendisk *disk, int partno)
253254
rcu_assign_pointer(ptbl->last_lookup, NULL);
254255
kobject_put(part->holder_dir);
255256
device_del(part_to_dev(part));
256-
blk_free_devt(part_devt(part));
257257

258258
hd_struct_put(part);
259259
}

0 commit comments

Comments
 (0)