* Re: [PATCH v1] perf/core: Restore header fields in sideband output callbacks
2026-09-29 1:42 [PATCH v1] perf/core: Restore header fields in sideband output callbacks Ian Rogers
@ 2026-09-29 12:04 ` Peter Zijlstra
0 siblings, 0 replies; 2+ messages in thread
From: Peter Zijlstra @ 2026-09-29 12:04 UTC (permalink / raw)
To: Ian Rogers
Cc: Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Adrian Hunter,
James Clark, Song Liu, Alexei Starovoitov, linux-perf-users,
linux-kernel, bpf, stable
On Mon, Sep 28, 2026 at 06:42:06PM -0700, Ian Rogers wrote:
> perf_iterate_sb() invokes its callback for each matching perf_event on
> the CPU and task context, passing a shared caller-allocated event
> structure.
>
> perf_event_header__init_id() increments header->size by
> event->id_header_size. Unlike perf_event_task_output(),
> perf_event_comm_output(), perf_event_namespaces_output(),
> perf_event_cgroup_output(), perf_event_mmap_output(), and
> perf_callchain_deferred_output(), three sideband callbacks failed to
> save and restore header.size around perf_event_header__init_id():
> - perf_event_ksymbol_output()
> - perf_event_bpf_output()
> - perf_event_text_poke_output()
I also found perf_event_switch_output(). Does something like so also
work?
---
kernel/events/core.c | 131 ++++++++++++++++++++++++---------------------------
1 file changed, 61 insertions(+), 70 deletions(-)
diff --git a/kernel/events/core.c b/kernel/events/core.c
index de05df65ab3d..28770ca689c8 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -9108,12 +9108,22 @@ perf_event_read_event(struct perf_event *event,
perf_output_end(&handle);
}
-typedef void (perf_iterate_f)(struct perf_event *event, void *data);
+typedef void (perf_iterate_f)(struct perf_event *event, struct perf_event_header *header);
+
+static __always_inline
+void __perf_iterate_output(perf_iterate_f output,
+ struct perf_event *event,
+ struct perf_event_header *header)
+{
+ struct perf_event_header old = *header;
+ output(event, header);
+ *header = old;
+}
static void
perf_iterate_ctx(struct perf_event_context *ctx,
perf_iterate_f output,
- void *data, bool all)
+ struct perf_event_header *header, bool all)
{
struct perf_event *event;
@@ -9125,11 +9135,11 @@ perf_iterate_ctx(struct perf_event_context *ctx,
continue;
}
- output(event, data);
+ __perf_iterate_output(output, event, header);
}
}
-static void perf_iterate_sb_cpu(perf_iterate_f output, void *data)
+static void perf_iterate_sb_cpu(perf_iterate_f output, struct perf_event_header *header)
{
struct pmu_event_list *pel = this_cpu_ptr(&pmu_sb_events);
struct perf_event *event;
@@ -9147,7 +9157,8 @@ static void perf_iterate_sb_cpu(perf_iterate_f output, void *data)
continue;
if (!event_filter_match(event))
continue;
- output(event, data);
+
+ __perf_iterate_output(output, event, header);
}
}
@@ -9158,7 +9169,7 @@ static void perf_iterate_sb_cpu(perf_iterate_f output, void *data)
* your event, otherwise it might not get delivered.
*/
static void
-perf_iterate_sb(perf_iterate_f output, void *data,
+perf_iterate_sb(perf_iterate_f output, struct perf_event_header *header,
struct perf_event_context *task_ctx)
{
struct perf_event_context *ctx;
@@ -9172,15 +9183,15 @@ perf_iterate_sb(perf_iterate_f output, void *data,
* context.
*/
if (task_ctx) {
- perf_iterate_ctx(task_ctx, output, data, false);
+ perf_iterate_ctx(task_ctx, output, header, false);
goto done;
}
- perf_iterate_sb_cpu(output, data);
+ perf_iterate_sb_cpu(output, header);
ctx = rcu_dereference(current->perf_event_ctxp);
if (ctx)
- perf_iterate_ctx(ctx, output, data, false);
+ perf_iterate_ctx(ctx, output, header, false);
done:
preempt_enable();
rcu_read_unlock();
@@ -9347,13 +9358,13 @@ static int perf_event_task_match(struct perf_event *event)
}
static void perf_event_task_output(struct perf_event *event,
- void *data)
+ struct perf_event_header *header)
{
- struct perf_task_event *task_event = data;
+ auto task_event = container_of(header, struct perf_task_event, event_id.header);
+ struct task_struct *task = task_event->task;
struct perf_output_handle handle;
struct perf_sample_data sample;
- struct task_struct *task = task_event->task;
- int ret, size = task_event->event_id.header.size;
+ int ret;
if (!perf_event_task_match(event))
return;
@@ -9363,7 +9374,7 @@ static void perf_event_task_output(struct perf_event *event,
ret = perf_output_begin(&handle, &sample, event,
task_event->event_id.header.size);
if (ret)
- goto out;
+ return;
task_event->event_id.pid = perf_event_pid(event, task);
task_event->event_id.tid = perf_event_tid(event, task);
@@ -9385,8 +9396,6 @@ static void perf_event_task_output(struct perf_event *event,
perf_event__output_id_sample(event, &handle, &sample);
perf_output_end(&handle);
-out:
- task_event->event_id.header.size = size;
}
static void perf_event_task(struct task_struct *task,
@@ -9418,7 +9427,7 @@ static void perf_event_task(struct task_struct *task,
};
perf_iterate_sb(perf_event_task_output,
- &task_event,
+ &task_event.event_id.header,
task_ctx);
}
@@ -9499,12 +9508,11 @@ static int perf_event_comm_match(struct perf_event *event)
}
static void perf_event_comm_output(struct perf_event *event,
- void *data)
+ struct perf_event_header *header)
{
- struct perf_comm_event *comm_event = data;
+ auto comm_event = container_of(header, struct perf_comm_event, event_id.header);
struct perf_output_handle handle;
struct perf_sample_data sample;
- int size = comm_event->event_id.header.size;
int ret;
if (!perf_event_comm_match(event))
@@ -9513,9 +9521,8 @@ static void perf_event_comm_output(struct perf_event *event,
perf_event_header__init_id(&comm_event->event_id.header, &sample, event);
ret = perf_output_begin(&handle, &sample, event,
comm_event->event_id.header.size);
-
if (ret)
- goto out;
+ return;
comm_event->event_id.pid = perf_event_pid(event, comm_event->task);
comm_event->event_id.tid = perf_event_tid(event, comm_event->task);
@@ -9527,8 +9534,6 @@ static void perf_event_comm_output(struct perf_event *event,
perf_event__output_id_sample(event, &handle, &sample);
perf_output_end(&handle);
-out:
- comm_event->event_id.header.size = size;
}
static void perf_event_comm_event(struct perf_comm_event *comm_event)
@@ -9546,7 +9551,7 @@ static void perf_event_comm_event(struct perf_comm_event *comm_event)
comm_event->event_id.header.size = sizeof(comm_event->event_id) + size;
perf_iterate_sb(perf_event_comm_output,
- comm_event,
+ &comm_event->event_id.header,
NULL);
}
@@ -9598,12 +9603,11 @@ static int perf_event_namespaces_match(struct perf_event *event)
}
static void perf_event_namespaces_output(struct perf_event *event,
- void *data)
+ struct perf_event_header *header)
{
- struct perf_namespaces_event *namespaces_event = data;
+ auto namespaces_event = container_of(header, struct perf_namespaces_event, event_id.header);
struct perf_output_handle handle;
struct perf_sample_data sample;
- u16 header_size = namespaces_event->event_id.header.size;
int ret;
if (!perf_event_namespaces_match(event))
@@ -9614,7 +9618,7 @@ static void perf_event_namespaces_output(struct perf_event *event,
ret = perf_output_begin(&handle, &sample, event,
namespaces_event->event_id.header.size);
if (ret)
- goto out;
+ return;
namespaces_event->event_id.pid = perf_event_pid(event,
namespaces_event->task);
@@ -9626,8 +9630,6 @@ static void perf_event_namespaces_output(struct perf_event *event,
perf_event__output_id_sample(event, &handle, &sample);
perf_output_end(&handle);
-out:
- namespaces_event->event_id.header.size = header_size;
}
static void perf_fill_ns_link_info(struct perf_ns_link_info *ns_link_info,
@@ -9701,7 +9703,7 @@ void perf_event_namespaces(struct task_struct *task)
#endif
perf_iterate_sb(perf_event_namespaces_output,
- &namespaces_event,
+ &namespaces_event.event_id.header,
NULL);
}
@@ -9725,12 +9727,11 @@ static int perf_event_cgroup_match(struct perf_event *event)
return event->attr.cgroup;
}
-static void perf_event_cgroup_output(struct perf_event *event, void *data)
+static void perf_event_cgroup_output(struct perf_event *event, struct perf_event_header *header)
{
- struct perf_cgroup_event *cgroup_event = data;
+ auto cgroup_event = container_of(header, struct perf_cgroup_event, event_id.header);
struct perf_output_handle handle;
struct perf_sample_data sample;
- u16 header_size = cgroup_event->event_id.header.size;
int ret;
if (!perf_event_cgroup_match(event))
@@ -9741,7 +9742,7 @@ static void perf_event_cgroup_output(struct perf_event *event, void *data)
ret = perf_output_begin(&handle, &sample, event,
cgroup_event->event_id.header.size);
if (ret)
- goto out;
+ return;
perf_output_put(&handle, cgroup_event->event_id);
__output_copy(&handle, cgroup_event->path, cgroup_event->path_size);
@@ -9749,8 +9750,6 @@ static void perf_event_cgroup_output(struct perf_event *event, void *data)
perf_event__output_id_sample(event, &handle, &sample);
perf_output_end(&handle);
-out:
- cgroup_event->event_id.header.size = header_size;
}
static void perf_event_cgroup(struct cgroup *cgrp)
@@ -9796,7 +9795,7 @@ static void perf_event_cgroup(struct cgroup *cgrp)
cgroup_event.path_size = size;
perf_iterate_sb(perf_event_cgroup_output,
- &cgroup_event,
+ &cgroup_event.event_id.header,
NULL);
kfree(pathname);
@@ -9832,9 +9831,8 @@ struct perf_mmap_event {
};
static int perf_event_mmap_match(struct perf_event *event,
- void *data)
+ struct perf_mmap_event *mmap_event)
{
- struct perf_mmap_event *mmap_event = data;
struct vm_area_struct *vma = mmap_event->vma;
int executable = vma->vm_flags & VM_EXEC;
@@ -9843,17 +9841,15 @@ static int perf_event_mmap_match(struct perf_event *event,
}
static void perf_event_mmap_output(struct perf_event *event,
- void *data)
+ struct perf_event_header *header)
{
- struct perf_mmap_event *mmap_event = data;
+ auto mmap_event = container_of(header, struct perf_mmap_event, event_id.header);
struct perf_output_handle handle;
struct perf_sample_data sample;
- int size = mmap_event->event_id.header.size;
- u32 type = mmap_event->event_id.header.type;
bool use_build_id;
int ret;
- if (!perf_event_mmap_match(event, data))
+ if (!perf_event_mmap_match(event, mmap_event))
return;
if (event->attr.mmap2) {
@@ -9870,7 +9866,7 @@ static void perf_event_mmap_output(struct perf_event *event,
ret = perf_output_begin(&handle, &sample, event,
mmap_event->event_id.header.size);
if (ret)
- goto out;
+ return;
mmap_event->event_id.pid = perf_event_pid(event, current);
mmap_event->event_id.tid = perf_event_tid(event, current);
@@ -9904,9 +9900,6 @@ static void perf_event_mmap_output(struct perf_event *event,
perf_event__output_id_sample(event, &handle, &sample);
perf_output_end(&handle);
-out:
- mmap_event->event_id.header.size = size;
- mmap_event->event_id.header.type = type;
}
static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
@@ -10011,7 +10004,7 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
build_id_parse_nofault(vma, mmap_event->build_id, &mmap_event->build_id_size);
perf_iterate_sb(perf_event_mmap_output,
- mmap_event,
+ &mmap_event->event_id.header,
NULL);
kfree(buf);
@@ -10236,9 +10229,9 @@ static int perf_event_switch_match(struct perf_event *event)
return event->attr.context_switch;
}
-static void perf_event_switch_output(struct perf_event *event, void *data)
+static void perf_event_switch_output(struct perf_event *event, struct perf_event_header *header)
{
- struct perf_switch_event *se = data;
+ auto se = container_of(header, struct perf_switch_event, event_id.header);
struct perf_output_handle handle;
struct perf_sample_data sample;
int ret;
@@ -10301,7 +10294,7 @@ static void perf_event_switch(struct task_struct *task,
PERF_RECORD_MISC_SWITCH_OUT_PREEMPT;
}
- perf_iterate_sb(perf_event_switch_output, &switch_event, NULL);
+ perf_iterate_sb(perf_event_switch_output, &switch_event.event_id.header, NULL);
}
/*
@@ -10366,9 +10359,9 @@ static int perf_event_ksymbol_match(struct perf_event *event)
return event->attr.ksymbol;
}
-static void perf_event_ksymbol_output(struct perf_event *event, void *data)
+static void perf_event_ksymbol_output(struct perf_event *event, struct perf_event_header *header)
{
- struct perf_ksymbol_event *ksymbol_event = data;
+ auto ksymbol_event = container_of(header, struct perf_ksymbol_event, event_id.header);
struct perf_output_handle handle;
struct perf_sample_data sample;
int ret;
@@ -10430,7 +10423,7 @@ void perf_event_ksymbol(u16 ksym_type, u64 addr, u32 len, bool unregister,
},
};
- perf_iterate_sb(perf_event_ksymbol_output, &ksymbol_event, NULL);
+ perf_iterate_sb(perf_event_ksymbol_output, &ksymbol_event.event_id.header, NULL);
return;
err:
WARN_ONCE(1, "%s: Invalid KSYMBOL type 0x%x\n", __func__, ksym_type);
@@ -10456,9 +10449,9 @@ static int perf_event_bpf_match(struct perf_event *event)
return event->attr.bpf_event;
}
-static void perf_event_bpf_output(struct perf_event *event, void *data)
+static void perf_event_bpf_output(struct perf_event *event, struct perf_event_header *header)
{
- struct perf_bpf_event *bpf_event = data;
+ auto bpf_event = container_of(header, struct perf_bpf_event, event_id.header);
struct perf_output_handle handle;
struct perf_sample_data sample;
int ret;
@@ -10536,7 +10529,7 @@ void perf_event_bpf_event(struct bpf_prog *prog,
BUILD_BUG_ON(BPF_TAG_SIZE % sizeof(u64));
memcpy(bpf_event.event_id.tag, prog->tag, BPF_TAG_SIZE);
- perf_iterate_sb(perf_event_bpf_output, &bpf_event, NULL);
+ perf_iterate_sb(perf_event_bpf_output, &bpf_event.event_id.header, NULL);
}
struct perf_callchain_deferred_event {
@@ -10549,12 +10542,12 @@ struct perf_callchain_deferred_event {
} event;
};
-static void perf_callchain_deferred_output(struct perf_event *event, void *data)
+static void perf_callchain_deferred_output(struct perf_event *event, struct perf_event_header *header)
{
- struct perf_callchain_deferred_event *deferred_event = data;
+ auto deferred_event = container_of(header, struct perf_callchain_deferred_event, event.header);
struct perf_output_handle handle;
struct perf_sample_data sample;
- int ret, size = deferred_event->event.header.size;
+ int ret;
if (!event->attr.defer_output)
return;
@@ -10565,7 +10558,7 @@ static void perf_callchain_deferred_output(struct perf_event *event, void *data)
ret = perf_output_begin(&handle, &sample, event,
deferred_event->event.header.size);
if (ret)
- goto out;
+ return;
perf_output_put(&handle, deferred_event->event);
for (int i = 0; i < deferred_event->trace->nr; i++) {
@@ -10575,8 +10568,6 @@ static void perf_callchain_deferred_output(struct perf_event *event, void *data)
perf_event__output_id_sample(event, &handle, &sample);
perf_output_end(&handle);
-out:
- deferred_event->event.header.size = size;
}
static void perf_unwind_deferred_callback(struct unwind_work *work,
@@ -10596,7 +10587,7 @@ static void perf_unwind_deferred_callback(struct unwind_work *work,
},
};
- perf_iterate_sb(perf_callchain_deferred_output, &deferred_event, NULL);
+ perf_iterate_sb(perf_callchain_deferred_output, &deferred_event.event.header, NULL);
}
struct perf_text_poke_event {
@@ -10618,9 +10609,9 @@ static int perf_event_text_poke_match(struct perf_event *event)
return event->attr.text_poke;
}
-static void perf_event_text_poke_output(struct perf_event *event, void *data)
+static void perf_event_text_poke_output(struct perf_event *event, struct perf_event_header *header)
{
- struct perf_text_poke_event *text_poke_event = data;
+ auto text_poke_event = container_of(header, struct perf_text_poke_event, event_id.header);
struct perf_output_handle handle;
struct perf_sample_data sample;
u64 padding = 0;
@@ -10680,7 +10671,7 @@ void perf_event_text_poke(const void *addr, const void *old_bytes,
},
};
- perf_iterate_sb(perf_event_text_poke_output, &text_poke_event, NULL);
+ perf_iterate_sb(perf_event_text_poke_output, &text_poke_event.event_id.header, NULL);
}
void perf_event_itrace_started(struct perf_event *event)
^ permalink raw reply [flat|nested] 2+ messages in thread