]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
perf/aux: Fix pending disable flow when the AUX ring buffer overruns
authorLeo Yan <leo.yan@arm.com>
Wed, 25 Jun 2025 17:07:37 +0000 (18:07 +0100)
committerIngo Molnar <mingo@kernel.org>
Thu, 26 Jun 2025 08:50:37 +0000 (10:50 +0200)
If an AUX event overruns, the event core layer intends to disable the
event by setting the 'pending_disable' flag. Unfortunately, the event
is not actually disabled afterwards.

In commit:

  ca6c21327c6a ("perf: Fix missing SIGTRAPs")

the 'pending_disable' flag was changed to a boolean. However, the
AUX event code was not updated accordingly. The flag ends up holding a
CPU number. If this number is zero, the flag is taken as false and the
IRQ work is never triggered.

Later, with commit:

  2b84def990d3 ("perf: Split __perf_pending_irq() out of perf_pending_irq()")

a new IRQ work 'pending_disable_irq' was introduced to handle event
disabling. The AUX event path was not updated to kick off the work queue.

To fix this bug, when an AUX ring buffer overrun is detected, call
perf_event_disable_inatomic() to initiate the pending disable flow.

Also update the outdated comment for setting the flag, to reflect the
boolean values (0 or 1).

Fixes: 2b84def990d3 ("perf: Split __perf_pending_irq() out of perf_pending_irq()")
Fixes: ca6c21327c6a ("perf: Fix missing SIGTRAPs")
Signed-off-by: Leo Yan <leo.yan@arm.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: James Clark <james.clark@linaro.org>
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Ian Rogers <irogers@google.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Liang Kan <kan.liang@linux.intel.com>
Cc: Marco Elver <elver@google.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Cc: linux-perf-users@vger.kernel.org
Link: https://lore.kernel.org/r/20250625170737.2918295-1-leo.yan@arm.com
kernel/events/core.c
kernel/events/ring_buffer.c

index 1f746469fda58dbc7651184adfd75962932026fb..7281230044d0dce87f460e9ff7c5696737d786a9 100644 (file)
@@ -7251,15 +7251,15 @@ static void __perf_pending_disable(struct perf_event *event)
         *  CPU-A                       CPU-B
         *
         *  perf_event_disable_inatomic()
-        *    @pending_disable = CPU-A;
+        *    @pending_disable = 1;
         *    irq_work_queue();
         *
         *  sched-out
-        *    @pending_disable = -1;
+        *    @pending_disable = 0;
         *
         *                              sched-in
         *                              perf_event_disable_inatomic()
-        *                                @pending_disable = CPU-B;
+        *                                @pending_disable = 1;
         *                                irq_work_queue(); // FAILS
         *
         *  irq_work_run()
index d2aef87c7e9f8e7c48fd2b6d26f3e6dac7666e9b..aa9a759e824fee5766dc8047f35f63ac12d0cd39 100644 (file)
@@ -441,7 +441,7 @@ void *perf_aux_output_begin(struct perf_output_handle *handle,
                 * store that will be enabled on successful return
                 */
                if (!handle->size) { /* A, matches D */
-                       event->pending_disable = smp_processor_id();
+                       perf_event_disable_inatomic(handle->event);
                        perf_output_wakeup(handle);
                        WRITE_ONCE(rb->aux_nest, 0);
                        goto err_put;
@@ -526,7 +526,7 @@ void perf_aux_output_end(struct perf_output_handle *handle, unsigned long size)
 
        if (wakeup) {
                if (handle->aux_flags & PERF_AUX_FLAG_TRUNCATED)
-                       handle->event->pending_disable = smp_processor_id();
+                       perf_event_disable_inatomic(handle->event);
                perf_output_wakeup(handle);
        }