public inbox for linux-arm-kernel@lists.infradead.org
 help / color / mirror / Atom feed
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);
> 



  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