Re: [RESEND][PATCH v15 2/4] perf: Support deferred user callchains
From: Peter Zijlstra <peterz@infradead.org>
Date: 2025-09-23 09:19:49
Also in:
bpf, lkml
On Mon, Sep 08, 2025 at 01:14:14PM -0400, Steven Rostedt wrote:
+static void perf_event_callchain_deferred(struct callback_head *work)
+{
+ struct perf_event *event = container_of(work, struct perf_event, pending_unwind_work);
+ struct perf_callchain_deferred_event deferred_event;
+ u64 callchain_context = PERF_CONTEXT_USER;
+ struct unwind_stacktrace trace;
+ struct perf_output_handle handle;
+ struct perf_sample_data data;
+ u64 nr;
+
+ if (!event->pending_unwind_callback)
+ return;
+
+ if (unwind_user_faultable(&trace) < 0)
+ goto out;This is broken. Because:
+ + /* + * All accesses to the event must belong to the same implicit RCU + * read-side critical section as the ->pending_unwind_callback reset. + * See comment in perf_pending_unwind_sync(). + */ + guard(rcu)();
Here you start a guard, that lasts until close of function..
+
+ if (current->flags & (PF_KTHREAD | PF_USER_WORKER))
+ goto out;
+
+ nr = trace.nr + 1 ; /* '+1' == callchain_context */
+
+ deferred_event.header.type = PERF_RECORD_CALLCHAIN_DEFERRED;
+ deferred_event.header.misc = PERF_RECORD_MISC_USER;
+ deferred_event.header.size = sizeof(deferred_event) + (nr * sizeof(u64));
+
+ deferred_event.nr = nr;
+ deferred_event.cookie = unwind_user_get_cookie();
+
+ perf_event_header__init_id(&deferred_event.header, &data, event);
+
+ if (perf_output_begin(&handle, &data, event, deferred_event.header.size))
+ goto out;
+
+ perf_output_put(&handle, deferred_event);
+ perf_output_put(&handle, callchain_context);
+ /* trace.entries[] are not guaranteed to be 64bit */
+ for (int i = 0; i < trace.nr; i++) {
+ u64 entry = trace.entries[i];
+ perf_output_put(&handle, entry);
+ }
+ perf_event__output_id_sample(event, &handle, &data);
+
+ perf_output_end(&handle);
+
+out:Which very much includes here, so your goto jumps into a scope, which is not permitted. GCC can fail to warn on this, but clang will consistently fail to compile this. Surely the robot would've told you by now -- even if you're not using clang yourself.
+ event->pending_unwind_callback = 0; + local_dec(&event->ctx->nr_no_switch_fast); + rcuwait_wake_up(&event->pending_unwind_wait); +}