]> www.infradead.org Git - users/willy/xarray.git/commitdiff
sg: Convert sg_index_idr to XArray
authorMatthew Wilcox <willy@infradead.org>
Sun, 10 Feb 2019 16:36:49 +0000 (11:36 -0500)
committerMatthew Wilcox (Oracle) <willy@infradead.org>
Thu, 8 Aug 2019 03:39:47 +0000 (23:39 -0400)
Signed-off-by: Matthew Wilcox <willy@infradead.org>
drivers/scsi/sg.c

index cce7575063839abc5aebd02f4f03933508b3039c..3955fb663bb37552e1e0a3a1d770edb8b1fc6194 100644 (file)
@@ -37,7 +37,6 @@ static int sg_version_num = 30536;    /* 2 digits for each component */
 #include <linux/poll.h>
 #include <linux/moduleparam.h>
 #include <linux/cdev.h>
-#include <linux/idr.h>
 #include <linux/seq_file.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
@@ -46,6 +45,7 @@ static int sg_version_num = 30536;    /* 2 digits for each component */
 #include <linux/atomic.h>
 #include <linux/ratelimit.h>
 #include <linux/uio.h>
+#include <linux/xarray.h>
 #include <linux/cred.h> /* for sg_check_file_access() */
 
 #include "scsi.h"
@@ -94,9 +94,7 @@ static int scatter_elem_sz_prev = SG_SCATTER_SZ;
 static int sg_add_device(struct device *, struct class_interface *);
 static void sg_remove_device(struct device *, struct class_interface *);
 
-static DEFINE_IDR(sg_index_idr);
-static DEFINE_RWLOCK(sg_index_lock);   /* Also used to lock
-                                                          file descriptor list for device */
+static DEFINE_XARRAY_FLAGS(sg_devs, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
 
 static struct class_interface sg_interface = {
        .add_dev        = sg_add_device,
@@ -1435,7 +1433,6 @@ sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
 {
        struct request_queue *q = scsidp->request_queue;
        Sg_device *sdp;
-       unsigned long iflags;
        int error;
        u32 k;
 
@@ -1446,24 +1443,22 @@ sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
                return ERR_PTR(-ENOMEM);
        }
 
-       idr_preload(GFP_KERNEL);
-       write_lock_irqsave(&sg_index_lock, iflags);
-
-       error = idr_alloc(&sg_index_idr, sdp, 0, SG_MAX_DEVS, GFP_NOWAIT);
+       xa_lock_irq(&sg_devs);
+       error = xa_alloc(&sg_devs, &k, sdp, XA_LIMIT(0, SG_MAX_DEVS),
+                       GFP_KERNEL);
        if (error < 0) {
-               if (error == -ENOSPC) {
+               if (error == -EBUSY) {
                        sdev_printk(KERN_WARNING, scsidp,
                                    "Unable to attach sg device type=%d, minor number exceeds %d\n",
                                    scsidp->type, SG_MAX_DEVS - 1);
                        error = -ENODEV;
                } else {
-                       sdev_printk(KERN_WARNING, scsidp, "%s: idr "
-                                   "allocation Sg_device failure: %d\n",
+                       sdev_printk(KERN_WARNING, scsidp,
+                                   "%s: ID allocation Sg_device failure: %d\n",
                                    __func__, error);
                }
                goto out_unlock;
        }
-       k = error;
 
        SCSI_LOG_TIMEOUT(3, sdev_printk(KERN_INFO, scsidp,
                                        "sg_alloc: dev=%d \n", k));
@@ -1482,8 +1477,7 @@ sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
        error = 0;
 
 out_unlock:
-       write_unlock_irqrestore(&sg_index_lock, iflags);
-       idr_preload_end();
+       xa_unlock_irq(&sg_devs);
 
        if (error) {
                kfree(sdp);
@@ -1500,7 +1494,6 @@ sg_add_device(struct device *cl_dev, struct class_interface *cl_intf)
        Sg_device *sdp = NULL;
        struct cdev * cdev = NULL;
        int error;
-       unsigned long iflags;
 
        disk = alloc_disk(1);
        if (!disk) {
@@ -1558,9 +1551,7 @@ sg_add_device(struct device *cl_dev, struct class_interface *cl_intf)
        return 0;
 
 cdev_add_err:
-       write_lock_irqsave(&sg_index_lock, iflags);
-       idr_remove(&sg_index_idr, sdp->index);
-       write_unlock_irqrestore(&sg_index_lock, iflags);
+       xa_erase_irq(&sg_devs, sdp->index);
        kfree(sdp);
 
 out:
@@ -1576,14 +1567,14 @@ sg_device_destroy(struct kref *kref)
        struct sg_device *sdp = container_of(kref, struct sg_device, d_ref);
        unsigned long flags;
 
-       /* CAUTION!  Note that the device can still be found via idr_find()
-        * even though the refcount is 0.  Therefore, do idr_remove() BEFORE
+       /* CAUTION!  Note that the device can still be found in sg_devs
+        * even though the refcount is 0.  Therefore, remove it BEFORE
         * any other cleanup.
         */
 
-       write_lock_irqsave(&sg_index_lock, flags);
-       idr_remove(&sg_index_idr, sdp->index);
-       write_unlock_irqrestore(&sg_index_lock, flags);
+       xa_lock_irqsave(&sg_devs, flags);
+       __xa_erase(&sg_devs, sdp->index);
+       xa_unlock_irqrestore(&sg_devs, flags);
 
        SCSI_LOG_TIMEOUT(3,
                sg_printk(KERN_INFO, sdp, "sg_device_destroy\n"));
@@ -1691,7 +1682,6 @@ exit_sg(void)
        sg_sysfs_valid = 0;
        unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0),
                                 SG_MAX_DEVS);
-       idr_destroy(&sg_index_idr);
 }
 
 static int
@@ -2238,34 +2228,22 @@ sg_remove_sfp(struct kref *kref)
 }
 
 #ifdef CONFIG_SCSI_PROC_FS
-static int
-sg_idr_max_id(int id, void *p, void *data)
-{
-       int *k = data;
-
-       if (*k < id)
-               *k = id;
-
-       return 0;
-}
-
 static int
 sg_last_dev(void)
 {
-       int k = -1;
-       unsigned long iflags;
+       void *p;
+       unsigned long index;
+
+       xa_for_each(&sg_devs, index, p)
+               ;
 
-       read_lock_irqsave(&sg_index_lock, iflags);
-       idr_for_each(&sg_index_idr, sg_idr_max_id, &k);
-       read_unlock_irqrestore(&sg_index_lock, iflags);
-       return k + 1;           /* origin 1 */
+       return index + 1;
 }
 #endif
 
-/* must be called with sg_index_lock held */
 static Sg_device *sg_lookup_dev(int dev)
 {
-       return idr_find(&sg_index_idr, dev);
+       return xa_load(&sg_devs, dev);
 }
 
 static Sg_device *
@@ -2274,7 +2252,7 @@ sg_get_dev(int dev)
        struct sg_device *sdp;
        unsigned long flags;
 
-       read_lock_irqsave(&sg_index_lock, flags);
+       xa_lock_irqsave(&sg_devs, flags);
        sdp = sg_lookup_dev(dev);
        if (!sdp)
                sdp = ERR_PTR(-ENXIO);
@@ -2285,7 +2263,7 @@ sg_get_dev(int dev)
                sdp = ERR_PTR(-ENODEV);
        } else
                kref_get(&sdp->d_ref);
-       read_unlock_irqrestore(&sg_index_lock, flags);
+       xa_unlock_irqrestore(&sg_devs, flags);
 
        return sdp;
 }
@@ -2471,7 +2449,7 @@ static int sg_proc_seq_show_dev(struct seq_file *s, void *v)
        struct scsi_device *scsidp;
        unsigned long iflags;
 
-       read_lock_irqsave(&sg_index_lock, iflags);
+       xa_lock_irqsave(&sg_devs, iflags);
        sdp = it ? sg_lookup_dev(it->index) : NULL;
        if ((NULL == sdp) || (NULL == sdp->device) ||
            (atomic_read(&sdp->detaching)))
@@ -2486,7 +2464,7 @@ static int sg_proc_seq_show_dev(struct seq_file *s, void *v)
                              (int) atomic_read(&scsidp->device_busy),
                              (int) scsi_device_online(scsidp));
        }
-       read_unlock_irqrestore(&sg_index_lock, iflags);
+       xa_unlock_irqrestore(&sg_devs, iflags);
        return 0;
 }
 
@@ -2497,7 +2475,7 @@ static int sg_proc_seq_show_devstrs(struct seq_file *s, void *v)
        struct scsi_device *scsidp;
        unsigned long iflags;
 
-       read_lock_irqsave(&sg_index_lock, iflags);
+       xa_lock_irqsave(&sg_devs, iflags);
        sdp = it ? sg_lookup_dev(it->index) : NULL;
        scsidp = sdp ? sdp->device : NULL;
        if (sdp && scsidp && (!atomic_read(&sdp->detaching)))
@@ -2505,11 +2483,11 @@ static int sg_proc_seq_show_devstrs(struct seq_file *s, void *v)
                           scsidp->vendor, scsidp->model, scsidp->rev);
        else
                seq_puts(s, "<no active device>\n");
-       read_unlock_irqrestore(&sg_index_lock, iflags);
+       xa_unlock_irqrestore(&sg_devs, iflags);
        return 0;
 }
 
-/* must be called while holding sg_index_lock */
+/* must be called while holding sg_devs lock */
 static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp)
 {
        int k, new_interface, blen, usg;
@@ -2583,7 +2561,7 @@ static int sg_proc_seq_show_debug(struct seq_file *s, void *v)
                seq_printf(s, "max_active_device=%d  def_reserved_size=%d\n",
                           (int)it->max, sg_big_buff);
 
-       read_lock_irqsave(&sg_index_lock, iflags);
+       xa_lock_irqsave(&sg_devs, iflags);
        sdp = it ? sg_lookup_dev(it->index) : NULL;
        if (NULL == sdp)
                goto skip;
@@ -2607,7 +2585,7 @@ static int sg_proc_seq_show_debug(struct seq_file *s, void *v)
        }
        read_unlock(&sdp->sfd_lock);
 skip:
-       read_unlock_irqrestore(&sg_index_lock, iflags);
+       xa_unlock_irqrestore(&sg_devs, iflags);
        return 0;
 }