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 <[email protected]>
---
 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

Reply via email to