From: Matthew Wilcox (Oracle) Date: Wed, 7 Aug 2019 12:48:51 +0000 (-0400) Subject: coresight: Convert etr_bufs to XArray X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=9cc4aa812ae6bbcba21ecefaf9d6f68f87c97183;p=users%2Fwilly%2Fxarray.git coresight: Convert etr_bufs to XArray 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) --- diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 17006705287a..8fd9bf7ed8b4 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -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); diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c index be37aff573b4..b970d37b9fdb 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.c +++ b/drivers/hwtracing/coresight/coresight-tmc.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -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: diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index 1ed50411cc3c..a70ead7e3153 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -8,7 +8,7 @@ #define _CORESIGHT_TMC_H #include -#include +#include #include #include #include @@ -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; };