]> www.infradead.org Git - users/willy/xarray.git/commitdiff
coresight: Convert etr_bufs to XArray
authorMatthew Wilcox (Oracle) <willy@infradead.org>
Wed, 7 Aug 2019 12:48:51 +0000 (08:48 -0400)
committerMatthew Wilcox (Oracle) <willy@infradead.org>
Fri, 9 Aug 2019 01:38:19 +0000 (21:38 -0400)
Use an XArray instead of an IDR to hold the etr_bufs.  The cmpxchg
operator leads to simpler code than the prior allocation code.  We don't
need the mutex any more as the XArray contains its own spinlock to
protect against simultaneous modifications.

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
drivers/hwtracing/coresight/coresight-tmc-etr.c
drivers/hwtracing/coresight/coresight-tmc.c
drivers/hwtracing/coresight/coresight-tmc.h

index 17006705287a525c697d9970ffed9f7e99aaef6f..8fd9bf7ed8b44cb48fdc1fc57a652b20942d2b3a 100644 (file)
@@ -8,7 +8,6 @@
 #include <linux/coresight.h>
 #include <linux/dma-mapping.h>
 #include <linux/iommu.h>
-#include <linux/idr.h>
 #include <linux/mutex.h>
 #include <linux/refcount.h>
 #include <linux/slab.h>
@@ -1225,11 +1224,9 @@ get_perf_etr_buf_cpu_wide(struct tmc_drvdata *drvdata,
                          struct perf_event *event, int nr_pages,
                          void **pages, bool snapshot)
 {
-       int ret;
        pid_t pid = task_pid_nr(event->owner);
-       struct etr_buf *etr_buf;
+       struct etr_buf *etr_buf, *curr;
 
-retry:
        /*
         * An etr_perf_buffer is associated with an event and holds a reference
         * to the AUX ring buffer that was created for that event.  In CPU-wide
@@ -1248,16 +1245,16 @@ retry:
         * allocated for this session.  If so it is shared with this event,
         * otherwise it is created.
         */
-       mutex_lock(&drvdata->idr_mutex);
-       etr_buf = idr_find(&drvdata->idr, pid);
+       xa_lock(&drvdata->bufs);
+       etr_buf = xa_load(&drvdata->bufs, pid);
        if (etr_buf) {
                refcount_inc(&etr_buf->refcount);
-               mutex_unlock(&drvdata->idr_mutex);
+               xa_unlock(&drvdata->bufs);
                return etr_buf;
        }
 
        /* If we made it here no buffer has been allocated, do so now. */
-       mutex_unlock(&drvdata->idr_mutex);
+       xa_unlock(&drvdata->bufs);
 
        etr_buf = alloc_etr_buf(drvdata, event, nr_pages, pages, snapshot);
        if (IS_ERR(etr_buf))
@@ -1265,25 +1262,20 @@ retry:
 
        refcount_set(&etr_buf->refcount, 1);
 
-       /* Now that we have a buffer, add it to the IDR. */
-       mutex_lock(&drvdata->idr_mutex);
-       ret = idr_alloc(&drvdata->idr, etr_buf, pid, pid + 1, GFP_KERNEL);
-       mutex_unlock(&drvdata->idr_mutex);
+       /* Now that we have a buffer, add it to the array. */
+       curr = xa_cmpxchg(&drvdata->bufs, pid, NULL, etr_buf, GFP_KERNEL);
+       if (!curr)
+               return etr_buf;
 
-       /* Another event with this session ID has allocated this buffer. */
-       if (ret == -ENOSPC) {
-               tmc_free_etr_buf(etr_buf);
-               goto retry;
-       }
+       tmc_free_etr_buf(etr_buf);
 
-       /* The IDR can't allocate room for a new session, abandon ship. */
-       if (ret == -ENOMEM) {
-               tmc_free_etr_buf(etr_buf);
-               return ERR_PTR(ret);
-       }
+       /* Can't allocate room for a new session, abandon ship. */
+       if (xa_is_err(curr))
+               return ERR_PTR(xa_err(curr));
 
-
-       return etr_buf;
+       /* Use the one in the array after all */
+       refcount_inc(&curr->refcount);
+       return curr;
 }
 
 static struct etr_buf *
@@ -1382,25 +1374,22 @@ static void tmc_free_etr_buffer(void *config)
        if (!etr_buf)
                goto free_etr_perf_buffer;
 
-       mutex_lock(&drvdata->idr_mutex);
        /* If we are not the last one to use the buffer, don't touch it. */
-       if (!refcount_dec_and_test(&etr_buf->refcount)) {
-               mutex_unlock(&drvdata->idr_mutex);
+       if (!refcount_dec_and_lock(&etr_buf->refcount, &drvdata->bufs.xa_lock))
                goto free_etr_perf_buffer;
-       }
 
-       /* We are the last one, remove from the IDR and free the buffer. */
-       buf = idr_remove(&drvdata->idr, etr_perf->pid);
-       mutex_unlock(&drvdata->idr_mutex);
+       /* We are the last one, remove from the array and free the buffer. */
+       buf = __xa_erase(&drvdata->bufs, etr_perf->pid);
+       xa_unlock(&drvdata->bufs);
 
        /*
         * Something went very wrong if the buffer associated with this ID
-        * is not the same in the IDR.  Leak to avoid use after free.
+        * is not the same in the array.  Leak to avoid use after free.
         */
        if (buf && WARN_ON(buf != etr_buf))
                goto free_etr_perf_buffer;
 
-       tmc_free_etr_buf(etr_perf->etr_buf);
+       tmc_free_etr_buf(etr_buf);
 
 free_etr_perf_buffer:
        kfree(etr_perf);
index be37aff573b44a225de50a1dd36475cafc1ecfc5..b970d37b9fdb1b1c718f87e9b3f5edaae21f19af 100644 (file)
@@ -8,7 +8,6 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/device.h>
-#include <linux/idr.h>
 #include <linux/io.h>
 #include <linux/err.h>
 #include <linux/fs.h>
@@ -450,8 +449,7 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
                                         coresight_get_uci_data(id));
                if (ret)
                        goto out;
-               idr_init(&drvdata->idr);
-               mutex_init(&drvdata->idr_mutex);
+               xa_init(&drvdata->bufs);
                dev_list = &etr_devs;
                break;
        case TMC_CONFIG_TYPE_ETF:
index 1ed50411cc3c34540fd1f7ebd3759241d55741a4..a70ead7e31537408ee84d050251551f4ae8e2635 100644 (file)
@@ -8,7 +8,7 @@
 #define _CORESIGHT_TMC_H
 
 #include <linux/dma-mapping.h>
-#include <linux/idr.h>
+#include <linux/xarray.h>
 #include <linux/miscdevice.h>
 #include <linux/mutex.h>
 #include <linux/refcount.h>
@@ -176,8 +176,7 @@ struct etr_buf {
  * @trigger_cntr: amount of words to store after a trigger.
  * @etr_caps:  Bitmask of capabilities of the TMC ETR, inferred from the
  *             device configuration register (DEVID)
- * @idr:       Holds etr_bufs allocated for this ETR.
- * @idr_mutex: Access serialisation for idr.
+ * @bufs:      Holds etr_bufs allocated for this ETR.
  * @perf_data: PERF buffer for ETR.
  * @sysfs_data:        SYSFS buffer for ETR.
  */
@@ -199,8 +198,7 @@ struct tmc_drvdata {
        enum tmc_mem_intf_width memwidth;
        u32                     trigger_cntr;
        u32                     etr_caps;
-       struct idr              idr;
-       struct mutex            idr_mutex;
+       struct xarray           bufs;
        struct etr_buf          *sysfs_buf;
        void                    *perf_data;
 };