Replace the IDR with the XArray. Includes converting the lookup from being protected by a spinlock to being protected by RCU. Signed-off-by: Matthew Wilcox <willy@xxxxxxxxxxxxx> --- block/genhd.c | 42 ++++++++++++++++-------------------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/block/genhd.c b/block/genhd.c index 703267865f14..7bb4d15f7574 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -17,7 +17,7 @@ #include <linux/kmod.h> #include <linux/kobj_map.h> #include <linux/mutex.h> -#include <linux/idr.h> +#include <linux/xarray.h> #include <linux/log2.h> #include <linux/pm_runtime.h> #include <linux/badblocks.h> @@ -30,11 +30,8 @@ struct kobject *block_depr; /* for extended dynamic devt allocation, currently only one major is used */ #define NR_EXT_DEVT (1 << MINORBITS) -/* For extended devt allocation. ext_devt_lock prevents look up - * results from going away underneath its user. - */ -static DEFINE_SPINLOCK(ext_devt_lock); -static DEFINE_IDR(ext_devt_idr); +/* For extended devt allocation */ +static DEFINE_XARRAY_FLAGS(ext_devt, XA_FLAGS_LOCK_BH | XA_FLAGS_ALLOC); static const struct device_type disk_type; @@ -487,7 +484,8 @@ static int blk_mangle_minor(int minor) int blk_alloc_devt(struct hd_struct *part, dev_t *devt) { struct gendisk *disk = part_to_disk(part); - int idx; + u32 idx; + int err; /* in consecutive minor range? */ if (part->partno < disk->minors) { @@ -495,16 +493,10 @@ int blk_alloc_devt(struct hd_struct *part, dev_t *devt) return 0; } - /* allocate ext devt */ - idr_preload(GFP_KERNEL); - - spin_lock_bh(&ext_devt_lock); - idx = idr_alloc(&ext_devt_idr, part, 0, NR_EXT_DEVT, GFP_NOWAIT); - spin_unlock_bh(&ext_devt_lock); - - idr_preload_end(); - if (idx < 0) - return idx == -ENOSPC ? -EBUSY : idx; + err = xa_alloc(&ext_devt, &idx, part, XA_LIMIT(0, NR_EXT_DEVT - 1), + GFP_KERNEL); + if (err < 0) + return err; *devt = MKDEV(BLOCK_EXT_MAJOR, blk_mangle_minor(idx)); return 0; @@ -516,8 +508,7 @@ int blk_alloc_devt(struct hd_struct *part, dev_t *devt) * * Free @devt which was allocated using blk_alloc_devt(). * - * CONTEXT: - * Might sleep. + * Context: Might sleep. */ void blk_free_devt(dev_t devt) { @@ -525,9 +516,7 @@ void blk_free_devt(dev_t devt) return; if (MAJOR(devt) == BLOCK_EXT_MAJOR) { - spin_lock_bh(&ext_devt_lock); - idr_remove(&ext_devt_idr, blk_mangle_minor(MINOR(devt))); - spin_unlock_bh(&ext_devt_lock); + xa_erase_bh(&ext_devt, blk_mangle_minor(MINOR(devt))); } } @@ -852,13 +841,13 @@ struct gendisk *get_gendisk(dev_t devt, int *partno) } else { struct hd_struct *part; - spin_lock_bh(&ext_devt_lock); - part = idr_find(&ext_devt_idr, blk_mangle_minor(MINOR(devt))); + rcu_read_lock(); + part = xa_load(&ext_devt, blk_mangle_minor(MINOR(devt))); if (part && get_disk_and_module(part_to_disk(part))) { *partno = part->partno; disk = part_to_disk(part); } - spin_unlock_bh(&ext_devt_lock); + rcu_read_unlock(); } if (!disk) @@ -1303,8 +1292,9 @@ static void disk_release(struct device *dev) hd_free_part(&disk->part0); if (disk->queue) blk_put_queue(disk->queue); - kfree(disk); + kfree_rcu(disk, part0.rcu_work.rcu); } + struct class block_class = { .name = "block", }; -- 2.20.1