]> www.infradead.org Git - users/willy/xarray.git/commitdiff
loop: Convert loop_index_idr to XArray
authorMatthew Wilcox <willy@infradead.org>
Tue, 5 Feb 2019 22:03:19 +0000 (17:03 -0500)
committerMatthew Wilcox (Oracle) <willy@infradead.org>
Thu, 8 Aug 2019 02:35:37 +0000 (22:35 -0400)
Signed-off-by: Matthew Wilcox <willy@infradead.org>
drivers/block/loop.c

index 3036883fc9f878f1714dcdfe1d6803a27853304a..323f0796d79a92990d9987be2ed0fa2188c306e9 100644 (file)
@@ -83,7 +83,7 @@
 
 #include <linux/uaccess.h>
 
-static DEFINE_IDR(loop_index_idr);
+static DEFINE_XARRAY_ALLOC(loop_devs);
 static DEFINE_MUTEX(loop_ctl_mutex);
 
 static int max_part;
@@ -1849,28 +1849,23 @@ int loop_register_transfer(struct loop_func_table *funcs)
        return 0;
 }
 
-static int unregister_transfer_cb(int id, void *ptr, void *data)
-{
-       struct loop_device *lo = ptr;
-       struct loop_func_table *xfer = data;
-
-       mutex_lock(&loop_ctl_mutex);
-       if (lo->lo_encryption == xfer)
-               loop_release_xfer(lo);
-       mutex_unlock(&loop_ctl_mutex);
-       return 0;
-}
-
 int loop_unregister_transfer(int number)
 {
        unsigned int n = number;
        struct loop_func_table *xfer;
+       struct loop_device *lo;
+       unsigned long index;
 
        if (n == 0 || n >= MAX_LO_CRYPT || (xfer = xfer_funcs[n]) == NULL)
                return -EINVAL;
 
        xfer_funcs[n] = NULL;
-       idr_for_each(&loop_index_idr, &unregister_transfer_cb, xfer);
+       xa_for_each(&loop_devs, index, lo) {
+               mutex_lock(&loop_ctl_mutex);
+               if (lo->lo_encryption == xfer)
+                       loop_release_xfer(lo);
+               mutex_unlock(&loop_ctl_mutex);
+       }
        return 0;
 }
 
@@ -1972,15 +1967,14 @@ static int loop_add(struct loop_device **l, int i)
 
        /* allocate id, if @id >= 0, we're requesting that specific id */
        if (i >= 0) {
-               err = idr_alloc(&loop_index_idr, lo, i, i + 1, GFP_KERNEL);
-               if (err == -ENOSPC)
-                       err = -EEXIST;
+               err = xa_insert(&loop_devs, i, lo, GFP_KERNEL);
        } else {
-               err = idr_alloc(&loop_index_idr, lo, 0, 0, GFP_KERNEL);
+               err = xa_alloc(&loop_devs, &i, lo, xa_limit_32b, GFP_KERNEL);
        }
+       if (err == -EBUSY)
+               err = -EEXIST;
        if (err < 0)
                goto out_free_dev;
-       i = err;
 
        err = -ENOMEM;
        lo->tag_set.ops = &loop_mq_ops;
@@ -1993,7 +1987,7 @@ static int loop_add(struct loop_device **l, int i)
 
        err = blk_mq_alloc_tag_set(&lo->tag_set);
        if (err)
-               goto out_free_idr;
+               goto out_free_xa;
 
        lo->lo_queue = blk_mq_init_queue(&lo->tag_set);
        if (IS_ERR(lo->lo_queue)) {
@@ -2055,8 +2049,8 @@ out_free_queue:
        blk_cleanup_queue(lo->lo_queue);
 out_cleanup_tags:
        blk_mq_free_tag_set(&lo->tag_set);
-out_free_idr:
-       idr_remove(&loop_index_idr, i);
+out_free_xa:
+       xa_erase(&loop_devs, i);
 out_free_dev:
        kfree(lo);
 out:
@@ -2072,41 +2066,28 @@ static void loop_remove(struct loop_device *lo)
        kfree(lo);
 }
 
-static int find_free_cb(int id, void *ptr, void *data)
-{
-       struct loop_device *lo = ptr;
-       struct loop_device **l = data;
-
-       if (lo->lo_state == Lo_unbound) {
-               *l = lo;
-               return 1;
-       }
-       return 0;
-}
-
 static int loop_lookup(struct loop_device **l, int i)
 {
        struct loop_device *lo;
        int ret = -ENODEV;
 
        if (i < 0) {
-               int err;
+               unsigned long index;
 
-               err = idr_for_each(&loop_index_idr, &find_free_cb, &lo);
-               if (err == 1) {
-                       *l = lo;
-                       ret = lo->lo_number;
+               xa_for_each(&loop_devs, index, lo) {
+                       if (lo->lo_state != Lo_unbound)
+                               continue;
+                       break;
                }
-               goto out;
+       } else {
+               /* lookup and return a specific i */
+               lo = xa_load(&loop_devs, i);
        }
 
-       /* lookup and return a specific i */
-       lo = idr_find(&loop_index_idr, i);
        if (lo) {
                *l = lo;
                ret = lo->lo_number;
        }
-out:
        return ret;
 }
 
@@ -2163,7 +2144,7 @@ static long loop_control_ioctl(struct file *file, unsigned int cmd,
                        break;
                }
                lo->lo_disk->private_data = NULL;
-               idr_remove(&loop_index_idr, lo->lo_number);
+               xa_erase(&loop_devs, lo->lo_number);
                loop_remove(lo);
                break;
        case LOOP_CTL_GET_FREE:
@@ -2270,23 +2251,16 @@ err_out:
        return err;
 }
 
-static int loop_exit_cb(int id, void *ptr, void *data)
-{
-       struct loop_device *lo = ptr;
-
-       loop_remove(lo);
-       return 0;
-}
-
 static void __exit loop_exit(void)
 {
-       unsigned long range;
-
-       range = max_loop ? max_loop << part_shift : 1UL << MINORBITS;
+       struct loop_device *lo;
+       unsigned long range, index;
 
-       idr_for_each(&loop_index_idr, &loop_exit_cb, NULL);
-       idr_destroy(&loop_index_idr);
+       xa_for_each(&loop_devs, index, lo)
+               loop_remove(lo);
+       xa_destroy(&loop_devs);
 
+       range = max_loop ? max_loop << part_shift : 1UL << MINORBITS;
        blk_unregister_region(MKDEV(LOOP_MAJOR, 0), range);
        unregister_blkdev(LOOP_MAJOR, "loop");