]> www.infradead.org Git - users/willy/xarray.git/commitdiff
genhd: Convert to XArray
authorMatthew Wilcox <willy@infradead.org>
Sat, 20 Oct 2018 03:20:05 +0000 (23:20 -0400)
committerMatthew Wilcox (Oracle) <willy@infradead.org>
Thu, 8 Aug 2019 02:35:36 +0000 (22:35 -0400)
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@infradead.org>
block/genhd.c

index 54f1f0d381f4d28c7b4d07d4044e4f0f7d2ddb05..b4f50fd21f0a9f9291cf0a758183fa2def6f9c56 100644 (file)
@@ -18,7 +18,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>
@@ -31,11 +31,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;
 
@@ -488,7 +485,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) {
@@ -496,16 +494,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;
@@ -517,8 +509,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)
 {
@@ -526,21 +517,18 @@ 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)));
        }
 }
 
 /*
- * We invalidate devt by assigning NULL pointer for devt in idr.
+ * We invalidate devt by assigning NULL pointer for devt.
  */
 void blk_invalidate_devt(dev_t devt)
 {
        if (MAJOR(devt) == BLOCK_EXT_MAJOR) {
-               spin_lock_bh(&ext_devt_lock);
-               idr_replace(&ext_devt_idr, NULL, blk_mangle_minor(MINOR(devt)));
-               spin_unlock_bh(&ext_devt_lock);
+               xa_store_bh(&ext_devt, blk_mangle_minor(MINOR(devt)), NULL,
+                               GFP_KERNEL);
        }
 }
 
@@ -807,7 +795,7 @@ void del_gendisk(struct gendisk *disk)
        if (!(disk->flags & GENHD_FL_HIDDEN))
                blk_unregister_region(disk_devt(disk), disk->minors);
        /*
-        * Remove gendisk pointer from idr so that it cannot be looked up
+        * Remove gendisk pointer from xarray so that it cannot be looked up
         * while RCU period before freeing gendisk is running to prevent
         * use-after-free issues. Note that the device number stays
         * "in-use" until we really free the gendisk.
@@ -872,13 +860,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)
@@ -1322,8 +1310,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",
 };