target: Convert devices_idr to XArray
authorMatthew Wilcox <willy@infradead.org>
Wed, 9 Jan 2019 13:34:37 +0000 (08:34 -0500)
committerMatthew Wilcox (Oracle) <willy@infradead.org>
Fri, 9 Aug 2019 01:38:14 +0000 (21:38 -0400)
Signed-off-by: Matthew Wilcox <willy@infradead.org>
drivers/target/target_core_device.c

index 04bf2acd3800ded1e776c087f7e2145bf219553b..1c86613a5cc4962fcae914ce81d4cf5bb5fa40b4 100644 (file)
@@ -36,9 +36,7 @@
 #include "target_core_pr.h"
 #include "target_core_ua.h"
 
-static DEFINE_MUTEX(device_mutex);
-static LIST_HEAD(device_list);
-static DEFINE_IDR(devices_idr);
+static DEFINE_XARRAY_ALLOC(device_list);
 
 static struct se_hba *lun0_hba;
 /* not static, needed by tpg.c */
@@ -853,42 +851,6 @@ sector_t target_to_linux_sector(struct se_device *dev, sector_t lb)
 }
 EXPORT_SYMBOL(target_to_linux_sector);
 
-struct devices_idr_iter {
-       struct config_item *prev_item;
-       int (*fn)(struct se_device *dev, void *data);
-       void *data;
-};
-
-static int target_devices_idr_iter(int id, void *p, void *data)
-        __must_hold(&device_mutex)
-{
-       struct devices_idr_iter *iter = data;
-       struct se_device *dev = p;
-       int ret;
-
-       config_item_put(iter->prev_item);
-       iter->prev_item = NULL;
-
-       /*
-        * We add the device early to the idr, so it can be used
-        * by backend modules during configuration. We do not want
-        * to allow other callers to access partially setup devices,
-        * so we skip them here.
-        */
-       if (!target_dev_configured(dev))
-               return 0;
-
-       iter->prev_item = config_item_get_unless_zero(&dev->dev_group.cg_item);
-       if (!iter->prev_item)
-               return 0;
-       mutex_unlock(&device_mutex);
-
-       ret = iter->fn(dev, iter->data);
-
-       mutex_lock(&device_mutex);
-       return ret;
-}
-
 /**
  * target_for_each_device - iterate over configured devices
  * @fn: iterator function
@@ -900,20 +862,41 @@ static int target_devices_idr_iter(int id, void *p, void *data)
 int target_for_each_device(int (*fn)(struct se_device *dev, void *data),
                           void *data)
 {
-       struct devices_idr_iter iter = { .fn = fn, .data = data };
-       int ret;
+       unsigned long i;
+       struct se_device *dev;
+       int ret = 0;
+
+       xa_for_each(&device_list, i, dev) {
+               struct config_item *item;
+
+               /*
+                * We add the device early to the list, so it can be used
+                * by backend modules during configuration. We do not want
+                * to allow other callers to access partially setup devices,
+                * so we skip them here.
+                */
+               if (!target_dev_configured(dev))
+                       continue;
+
+               item = config_item_get_unless_zero(&dev->dev_group.cg_item);
+               if (!item)
+                       continue;
+
+               ret = fn(dev, data);
+
+               config_item_put(item);
+               if (ret)
+                       break;
+       }
 
-       mutex_lock(&device_mutex);
-       ret = idr_for_each(&devices_idr, target_devices_idr_iter, &iter);
-       mutex_unlock(&device_mutex);
-       config_item_put(iter.prev_item);
        return ret;
 }
 
 int target_configure_device(struct se_device *dev)
 {
+       static u32 next;
        struct se_hba *hba = dev->se_hba;
-       int ret, id;
+       int ret;
 
        if (target_dev_configured(dev)) {
                pr_err("se_dev->se_dev_ptr already set for storage"
@@ -924,19 +907,15 @@ int target_configure_device(struct se_device *dev)
        /*
         * Add early so modules like tcmu can use during its
         * configuration.
-        */
-       mutex_lock(&device_mutex);
-       /*
         * Use cyclic to try and avoid collisions with devices
         * that were recently removed.
         */
-       id = idr_alloc_cyclic(&devices_idr, dev, 0, INT_MAX, GFP_KERNEL);
-       mutex_unlock(&device_mutex);
-       if (id < 0) {
+       ret = xa_alloc_cyclic(&device_list, &dev->dev_index, dev, xa_limit_32b,
+                       &next, GFP_KERNEL);
+       if (ret < 0) {
                ret = -ENOMEM;
                goto out;
        }
-       dev->dev_index = id;
 
        ret = dev->transport->configure_device(dev);
        if (ret)
@@ -979,9 +958,7 @@ int target_configure_device(struct se_device *dev)
 out_destroy_device:
        dev->transport->destroy_device(dev);
 out_free_index:
-       mutex_lock(&device_mutex);
-       idr_remove(&devices_idr, dev->dev_index);
-       mutex_unlock(&device_mutex);
+       xa_erase(&device_list, dev->dev_index);
 out:
        se_release_vpd_for_dev(dev);
        return ret;
@@ -995,10 +972,7 @@ void target_free_device(struct se_device *dev)
 
        if (target_dev_configured(dev)) {
                dev->transport->destroy_device(dev);
-
-               mutex_lock(&device_mutex);
-               idr_remove(&devices_idr, dev->dev_index);
-               mutex_unlock(&device_mutex);
+               xa_erase(&device_list, dev->dev_index);
 
                spin_lock(&hba->device_lock);
                hba->dev_count--;