[PATCH v2 19/23] coresight: trbe: Reload the AUX buffer on overflow restart

From: Leo Yan

Date: Fri Oct 16 2026 - 13:11:09 EST


PERF_EVENT_IOC_SET_OUTPUT lets events share another event's mapped output
buffer. For AUX events, this also selects the associated AUX area and
sink configuration. Perf normally establishes this sharing during setup.

Consider the following hypothetical live-redirection sequence, permitted
by the inspected perf-core paths. P is a parent event and C is its
inherited event, with C->parent = P. A and B are mapped AUX destination
buffers owned by separate, disabled cs_etm events in different task
contexts. All three are per-task events restricted to the same CPU, with
compatible output settings. P has no mmap of its own, allowing its output
to be redirected while A and B remain mapped through their owner events.

1. P's output is redirected to A. C inherits from P and begins tracing
on the selected CPU, so its open AUX transaction and TRBE hardware
both use A. P can be inactive while C is running because their
events are scheduled with their respective tasks.
2. A userspace controller calls PERF_EVENT_IOC_SET_OUTPUT on P to select
B. ring_buffer_attach() calls perf_event_stop(P, 0), which returns for
inactive P without stopping C. P->rb now selects B, but C's existing
handle and hardware still use A.
3. C's next buffer overflow invokes trbe_handle_overflow() from the IRQ
handler. It saves buf for A, ends that AUX transaction, then calls
perf_aux_output_begin(handle, C). AUX begin follows C->parent and
reads P's current rb, rebinding the same handle to B.

This is a hypothetical API sequence, not a reproduced TRBE failure or
an observed buffer switch in normal perf record operation.

Without reloading buf, __arm_trbe_enable() calculates the next buffer
using B through the handle, but its workaround and hardware setup still
receive A. If B has never been enabled, its missing CPU association can
cause the normal-offset calculation to dereference NULL. With a snapshot
buffer, hardware may instead keep using A while perf accounts output to B.

Reload the sink configuration after perf_aux_output_begin() so the buffer
and handle refer to the same AUX transaction. If the buffer is missing or
its CPU association does not match the interrupt's CPU data, truncate the
new transaction and leave TRBE disabled. Truncation requests perf to stop
the event; a subsequent normal restart installs the buffer and its CPU
association through the sink enable path.

Stopping inherited writers during output redirection remains a separate
perf-core fix.

Signed-off-by: Leo Yan <leo.yan@xxxxxxx>
---
drivers/hwtracing/coresight/coresight-trbe.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 2328aab0a084a0ac123e950f846f404d120ec2c0..f1f102df6c387f53feaa12b89d3df89f734afcdb 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -1161,6 +1161,20 @@ static int trbe_handle_overflow(struct trbe_cpudata *cpudata)
if (!event_data)
return -EINVAL;

+ /*
+ * Reload the buffer after perf_aux_output_begin() so it matches the
+ * handle. A race with PERF_EVENT_IOC_SET_OUTPUT may select a buffer
+ * that has not been installed on this CPU and has no valid cpudata.
+ * If the buffer is missing or its CPU association does not match,
+ * truncate the trace to stop the event. A subsequent normal restart
+ * installs the buffer and its CPU association through sink enable.
+ */
+ buf = etm_perf_sink_config(handle);
+ if (!buf || buf->cpudata != cpudata) {
+ trbe_truncate_event(handle);
+ return -EINVAL;
+ }
+
return __arm_trbe_enable(buf, handle);
}


--
2.34.1