From: Suzuki K Poulose <suzuki.poulose@arm.com>
To: Leo Yan <leo.yan@arm.com>, Mike Leach <mike.leach@arm.com>,
James Clark <james.clark@linaro.org>,
Yeoreum Yun <yeoreum.yun@arm.com>,
Mark Rutland <mark.rutland@arm.com>,
Will Deacon <will@kernel.org>, Yabin Cui <yabinc@google.com>,
Keita Morisaki <keyz@google.com>,
Jie Gan <jie.gan@oss.qualcomm.com>,
Yuanfang Zhang <quic_yuanfang@quicinc.com>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Alexander Shishkin <alexander.shishkin@linux.intel.com>,
Tamas Petz <tamas.petz@arm.com>,
Thomas Gleixner <tglx@kernel.org>,
Peter Zijlstra <peterz@infradead.org>
Cc: coresight@lists.linaro.org, linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH v11 09/27] coresight: Grab per-CPU source device during AUX setup
Date: Wed, 6 May 2026 10:08:30 +0100 [thread overview]
Message-ID: <741aa6b6-5544-408c-b97f-dddd53774d3c@arm.com> (raw)
In-Reply-To: <20260501-arm_coresight_path_power_management_improvement-v11-9-fc7fb9d5af1c@arm.com>
On 01/05/2026 17:47, Leo Yan wrote:
> etm_setup_aux() may access a per-CPU source device while ETM module is
> being unloaded, leading to a potential use-after-free.
>
> Therefore, this commit takes references to the device, which is
> sufficient to prevent the csdev from being released. This ensures that
> csdev can be safely accessed.
>
> Refactor the perf path build code into etm_event_build_path(), making
> it easier to use the coresight_{get|put}_percpu_source_ref() pairs.
> Update the comments accordingly to reflect the new flow.
>
> Signed-off-by: Leo Yan <leo.yan@arm.com>
> ---
> drivers/hwtracing/coresight/coresight-core.c | 29 ++++-
> drivers/hwtracing/coresight/coresight-etm-perf.c | 157 +++++++++++++----------
> drivers/hwtracing/coresight/coresight-priv.h | 3 +-
> 3 files changed, 120 insertions(+), 69 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
> index 6da15f2ef9dc9770e7aa79cc94a7ed3d2f3ad871..b01e63fbbb4b990d4f5ec61c8fa4da63dd59a4b9 100644
> --- a/drivers/hwtracing/coresight/coresight-core.c
> +++ b/drivers/hwtracing/coresight/coresight-core.c
> @@ -109,13 +109,38 @@ static void coresight_clear_percpu_source(struct coresight_device *csdev)
> per_cpu(csdev_source, csdev->cpu) = NULL;
> }
>
> -struct coresight_device *coresight_get_percpu_source(int cpu)
> +struct coresight_device *coresight_get_percpu_source_ref(int cpu)
> {
> + struct coresight_device *csdev;
> +
> if (WARN_ON(cpu < 0))
> return NULL;
>
> guard(raw_spinlock_irqsave)(&coresight_dev_lock);
> - return per_cpu(csdev_source, cpu);
> +
> + csdev = per_cpu(csdev_source, cpu);
> + if (!csdev)
> + return NULL;
> +
> + /* Make sure csdev is safe to access */
It may be worth adding a comment here :
/*
* Holding a reference to the csdev->dev ensures that the
* coresight_device is live for the caller. The path building
* logic can safely either build a path to the sink or fail
* if the device is being unregistered (if there was a race).
* The caller can skip the "source" device, if no path could
* be built.
*/
Suzuki
> + get_device(&csdev->dev);
> +
> + return csdev;
> +}
> +
> +void coresight_put_percpu_source_ref(struct coresight_device *csdev)
> +{
> + if (!csdev || !coresight_is_percpu_source(csdev))
> + return;
> +
> + guard(raw_spinlock_irqsave)(&coresight_dev_lock);
> +
> + /*
> + * When the device's refcount reaches zero, coresight_device_release()
> + * is invoked. This is safe even in atomic context, as the release
> + * function does not sleep.
> + */
> + put_device(&csdev->dev);
> }
>
> struct coresight_device *coresight_get_source(struct coresight_path *path)
> diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c
> index d3b13ef130439fd501f88395d0de9dd21b84b827..9950ad481f29eed3bfac8fe4ae3a593b53830617 100644
> --- a/drivers/hwtracing/coresight/coresight-etm-perf.c
> +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c
> @@ -338,6 +338,85 @@ static struct coresight_path *etm_event_get_ctxt_path(struct etm_ctxt *ctxt)
> return path;
> }
>
> +static struct coresight_path *
> +etm_event_build_path(struct perf_event *event, int cpu,
> + struct coresight_device *user_sink,
> + struct coresight_device *match_sink)
> +{
> + struct coresight_path *path = NULL;
> + struct coresight_device *source, *sink;
> +
> + source = coresight_get_percpu_source_ref(cpu);
> +
> + /*
> + * If there is no ETM associated with this CPU or ever we try to trace
> + * on this CPU, we handle it accordingly.
> + */
> + if (!source)
> + return NULL;
> +
> + /*
> + * If AUX pause feature is enabled but the ETM driver does not
> + * support the operations, skip for this source.
> + */
> + if (event->attr.aux_start_paused &&
> + (!source_ops(source)->pause_perf ||
> + !source_ops(source)->resume_perf)) {
> + dev_err_once(&source->dev, "AUX pause is not supported.\n");
> + goto out;
> + }
> +
> + /* If sink has been specified by user, directly use it */
> + if (user_sink) {
> + sink = user_sink;
> + } else {
> + /*
> + * No sink provided - look for a default sink for all the ETMs,
> + * where this event can be scheduled.
> + *
> + * We allocate the sink specific buffers only once for this
> + * event. If the ETMs have different default sink devices, we
> + * can only use a single "type" of sink as the event can carry
> + * only one sink specific buffer. Thus we have to make sure
> + * that the sinks are of the same type and driven by the same
> + * driver, as the one we allocate the buffer for. We don't
> + * trace on a CPU if the sink is not compatible.
> + */
> +
> + /* Find the default sink for this ETM */
> + sink = coresight_find_default_sink(source);
> + if (!sink)
> + goto out;
> +
> + /* Check if this sink compatible with the last sink */
> + if (match_sink && !sinks_compatible(match_sink, sink))
> + goto out;
> + }
> +
> + /*
> + * Building a path doesn't enable it, it simply builds a
> + * list of devices from source to sink that can be
> + * referenced later when the path is actually needed.
> + */
> + path = coresight_build_path(source, sink);
> + if (IS_ERR(path))
> + goto out;
> +
> + /* ensure we can allocate a trace ID for this CPU */
> + coresight_path_assign_trace_id(path, CS_MODE_PERF);
> + if (!IS_VALID_CS_TRACE_ID(path->trace_id)) {
> + coresight_release_path(path);
> + path = NULL;
> + goto out;
> + }
> +
> + coresight_trace_id_perf_start(&sink->perf_sink_id_map);
> +
> +out:
> + coresight_put_percpu_source_ref(source);
> + return IS_ERR_OR_NULL(path) ? NULL : path;
> +}
> +
> static void *etm_setup_aux(struct perf_event *event, void **pages,
> int nr_pages, bool overwrite)
> {
> @@ -345,7 +424,7 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
> int cpu = event->cpu;
> cpumask_t *mask;
> struct coresight_device *sink = NULL;
> - struct coresight_device *user_sink = NULL, *last_sink = NULL;
> + struct coresight_device *user_sink = NULL;
> struct etm_event_data *event_data = NULL;
>
> event_data = alloc_event_data(cpu);
> @@ -377,80 +456,26 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
> */
> for_each_cpu(cpu, mask) {
> struct coresight_path *path;
> - struct coresight_device *csdev;
>
> - csdev = coresight_get_percpu_source(cpu);
> - /*
> - * If there is no ETM associated with this CPU clear it from
> - * the mask and continue with the rest. If ever we try to trace
> - * on this CPU, we handle it accordingly.
> - */
> - if (!csdev) {
> + path = etm_event_build_path(event, cpu, user_sink, sink);
> + if (!path) {
> + /*
> + * Failed to create a path for the CPU, clear it from
> + * the mask and continue to next one.
> + */
> cpumask_clear_cpu(cpu, mask);
> continue;
> }
>
> - /*
> - * If AUX pause feature is enabled but the ETM driver does not
> - * support the operations, clear this CPU from the mask and
> - * continue to next one.
> - */
> - if (event->attr.aux_start_paused &&
> - (!source_ops(csdev)->pause_perf || !source_ops(csdev)->resume_perf)) {
> - dev_err_once(&csdev->dev, "AUX pause is not supported.\n");
> - cpumask_clear_cpu(cpu, mask);
> - continue;
> - }
>
> /*
> - * No sink provided - look for a default sink for all the ETMs,
> - * where this event can be scheduled.
> - * We allocate the sink specific buffers only once for this
> - * event. If the ETMs have different default sink devices, we
> - * can only use a single "type" of sink as the event can carry
> - * only one sink specific buffer. Thus we have to make sure
> - * that the sinks are of the same type and driven by the same
> - * driver, as the one we allocate the buffer for. As such
> - * we choose the first sink and check if the remaining ETMs
> - * have a compatible default sink. We don't trace on a CPU
> - * if the sink is not compatible.
> - */
> - if (!user_sink) {
> - /* Find the default sink for this ETM */
> - sink = coresight_find_default_sink(csdev);
> - if (!sink) {
> - cpumask_clear_cpu(cpu, mask);
> - continue;
> - }
> -
> - /* Check if this sink compatible with the last sink */
> - if (last_sink && !sinks_compatible(last_sink, sink)) {
> - cpumask_clear_cpu(cpu, mask);
> - continue;
> - }
> - last_sink = sink;
> - }
> -
> - /*
> - * Building a path doesn't enable it, it simply builds a
> - * list of devices from source to sink that can be
> - * referenced later when the path is actually needed.
> + * The first found sink is saved here and passed to
> + * etm_event_build_path() to check whether the remaining ETMs
> + * have a compatible default sink.
> */
> - path = coresight_build_path(csdev, sink);
> - if (IS_ERR(path)) {
> - cpumask_clear_cpu(cpu, mask);
> - continue;
> - }
> -
> - /* ensure we can allocate a trace ID for this CPU */
> - coresight_path_assign_trace_id(path, CS_MODE_PERF);
> - if (!IS_VALID_CS_TRACE_ID(path->trace_id)) {
> - cpumask_clear_cpu(cpu, mask);
> - coresight_release_path(path);
> - continue;
> - }
> + if (!user_sink && !sink)
> + sink = coresight_get_sink(path);
>
> - coresight_trace_id_perf_start(&sink->perf_sink_id_map);
> *etm_event_cpu_path_ptr(event_data, cpu) = path;
> }
>
> diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
> index 7ce79fa36232bb1b0af768423777bab27cacee95..a1aab67e23db7fdea5139100312b3eb7cd31df51 100644
> --- a/drivers/hwtracing/coresight/coresight-priv.h
> +++ b/drivers/hwtracing/coresight/coresight-priv.h
> @@ -249,7 +249,8 @@ void coresight_add_helper(struct coresight_device *csdev,
> void coresight_set_percpu_sink(int cpu, struct coresight_device *csdev);
> struct coresight_device *coresight_get_percpu_sink(int cpu);
> struct coresight_device *coresight_get_source(struct coresight_path *path);
> -struct coresight_device *coresight_get_percpu_source(int cpu);
> +struct coresight_device *coresight_get_percpu_source_ref(int cpu);
> +void coresight_put_percpu_source_ref(struct coresight_device *csdev);
> void coresight_disable_source(struct coresight_device *csdev, void *data);
> void coresight_pause_source(struct coresight_device *csdev);
> int coresight_resume_source(struct coresight_device *csdev);
>
next prev parent reply other threads:[~2026-05-06 9:09 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-01 16:47 [PATCH v11 00/27] CoreSight: Refactor power management for CoreSight path Leo Yan
2026-05-01 16:47 ` [PATCH v11 01/27] coresight: Handle helper enable failure properly Leo Yan
2026-05-01 16:47 ` [PATCH v11 02/27] coresight: Extract device init into coresight_init_device() Leo Yan
2026-05-01 16:47 ` [PATCH v11 03/27] coresight: Populate CPU ID into coresight_device Leo Yan
2026-05-01 16:47 ` [PATCH v11 04/27] coresight: Remove .cpu_id() callback from source ops Leo Yan
2026-05-01 16:47 ` [PATCH v11 05/27] coresight: Take hotplug lock in enable_source_store() for Sysfs mode Leo Yan
2026-05-01 16:47 ` [PATCH v11 06/27] coresight: perf: Retrieve path and source from event data Leo Yan
2026-05-01 16:47 ` [PATCH v11 07/27] coresight: Take a reference on csdev Leo Yan
2026-05-01 16:47 ` [PATCH v11 08/27] coresight: Move per-CPU source pointer to core layer Leo Yan
2026-05-01 16:47 ` [PATCH v11 09/27] coresight: Grab per-CPU source device during AUX setup Leo Yan
2026-05-06 9:08 ` Suzuki K Poulose [this message]
2026-05-01 16:47 ` [PATCH v11 10/27] coresight: Register CPU PM notifier in core layer Leo Yan
2026-05-01 16:47 ` [PATCH v11 11/27] coresight: etm4x: Hook CPU PM callbacks Leo Yan
2026-05-01 16:47 ` [PATCH v11 12/27] coresight: etm4x: Remove redundant checks in PM save and restore Leo Yan
2026-05-01 16:47 ` [PATCH v11 13/27] coresight: syscfg: Use IRQ-safe spinlock to protect active variables Leo Yan
2026-05-01 16:47 ` [PATCH v11 14/27] coresight: Move source helper disabling to coresight_disable_path() Leo Yan
2026-05-06 9:05 ` Suzuki K Poulose
2026-05-06 9:33 ` Leo Yan
2026-05-01 16:47 ` [PATCH v11 15/27] coresight: Control path with range Leo Yan
2026-05-01 16:47 ` [PATCH v11 16/27] coresight: Use helpers to fetch first and last nodes Leo Yan
2026-05-01 16:47 ` [PATCH v11 17/27] coresight: Introduce coresight_enable_source() helper Leo Yan
2026-05-01 16:47 ` [PATCH v11 18/27] coresight: Save active path for system tracers Leo Yan
2026-05-01 16:48 ` [PATCH v11 19/27] coresight: etm4x: Set active path on target CPU Leo Yan
2026-05-01 16:48 ` [PATCH v11 20/27] coresight: etm3x: " Leo Yan
2026-05-01 16:48 ` [PATCH v11 21/27] coresight: sysfs: Use source's path pointer for path control Leo Yan
2026-05-01 16:48 ` [PATCH v11 22/27] coresight: Control path during CPU idle Leo Yan
2026-05-01 16:48 ` [PATCH v11 23/27] coresight: Add PM callbacks for sink device Leo Yan
2026-05-01 16:48 ` [PATCH v11 24/27] coresight: trbe: Save and restore state across CPU low power state Leo Yan
2026-05-01 16:48 ` [PATCH v11 25/27] coresight: sysfs: Increment refcount only for system tracers Leo Yan
2026-05-06 9:57 ` Suzuki K Poulose
2026-05-06 10:18 ` Leo Yan
2026-05-01 16:48 ` [PATCH v11 26/27] coresight: Move CPU hotplug callbacks to core layer Leo Yan
2026-05-01 16:48 ` [PATCH v11 27/27] coresight: sysfs: Validate CPU online status for per-CPU sources Leo Yan
2026-05-06 7:33 ` [PATCH v11 00/27] CoreSight: Refactor power management for CoreSight path Jie Gan
2026-05-06 9:38 ` Leo Yan
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=741aa6b6-5544-408c-b97f-dddd53774d3c@arm.com \
--to=suzuki.poulose@arm.com \
--cc=alexander.shishkin@linux.intel.com \
--cc=coresight@lists.linaro.org \
--cc=gregkh@linuxfoundation.org \
--cc=james.clark@linaro.org \
--cc=jie.gan@oss.qualcomm.com \
--cc=keyz@google.com \
--cc=leo.yan@arm.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=mark.rutland@arm.com \
--cc=mike.leach@arm.com \
--cc=peterz@infradead.org \
--cc=quic_yuanfang@quicinc.com \
--cc=tamas.petz@arm.com \
--cc=tglx@kernel.org \
--cc=will@kernel.org \
--cc=yabinc@google.com \
--cc=yeoreum.yun@arm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox