Re: [PATCH v5 1/4] perf/core: Fix sched_task callbacks for CPU-wide branch stack events
Andrii Nakryiko <[email protected]> Thu, 30 Jul 2026 12:56:03 -0700
| Newsgroups | org.kernel.vger.linux-perf-users,org.infradead.lists.linux-arm-kernel,org.kernel.vger.bpf,org.kernel.vger.linux-kernel,org.kernel.vger.linux-kselftest |
|---|---|
| Message-ID | <CAEf4BzakTaTr16F4xRF4wti46Gfq7Csky=drai=aE_aUSOFbTQ@mail.gmail.com> |
On Tue, Jun 16, 2026 at 8:57 AM Puranjay Mohan <[email protected]> wrote: > > perf_pmu_sched_task() returns early when cpuctx->task_ctx is non-NULL, > deferring to perf_ctx_sched_task_cb() in the context sched_in/out > paths. But perf_ctx_sched_task_cb() only walks the task context's > pmu_ctx_list -- PMUs that have only CPU-wide events are not on that > list and their sched_task callback is silently skipped. > > On ARM64 with CPU-wide branch recording: > > perf record -b -e cycles -a -- ls > > armv8pmu_sched_task() is skipped whenever the scheduled task has an > unrelated perf event (e.g. a software event), and branch records leak > across task boundaries. > > A second problem exists in __perf_pmu_sched_task(): it passes > cpc->task_epc directly to pmu->sched_task(), but task_epc is NULL for > PMUs with only CPU-wide events. When perf_pmu_sched_task() does reach > the loop (because cpuctx->task_ctx is NULL), this causes a NULL > pointer dereference: > > Unable to handle kernel NULL pointer dereference at virtual address 00[.] > PC is at armv8pmu_sched_task+0x14/0x50 > Call trace: > armv8pmu_sched_task+0x14/0x50 (P) > perf_pmu_sched_task+0xac/0x108 > __perf_event_task_sched_out+0x6c/0xe0 > > Fix both: > > - Remove the blanket early return in perf_pmu_sched_task() when > cpuctx->task_ctx is set. Instead, skip individual CPCs that have a > task_epc (those are handled by perf_ctx_sched_task_cb()). CPCs > without a task_epc are CPU-only and must be handled here. > > - Fall back to &cpc->epc in __perf_pmu_sched_task() when task_epc is > NULL, so the callback always gets a valid pmu_ctx. > > Fixes: bd2756811766 ("perf: Rewrite core context handling") > Signed-off-by: Puranjay Mohan <[email protected]> > --- > kernel/events/core.c | 17 +++++++++++++---- > 1 file changed, 13 insertions(+), 4 deletions(-) > This looks like perf core bug fix, Peter/Ingo, would you like to take this directly into your tip/perf/urgent tree? > diff --git a/kernel/events/core.c b/kernel/events/core.c > index 6d1f8bad7e1c..6604f6e8f352 100644 > --- a/kernel/events/core.c > +++ b/kernel/events/core.c > @@ -3906,7 +3906,8 @@ static void __perf_pmu_sched_task(struct perf_cpu_pmu_context *cpc, > perf_ctx_lock(cpuctx, cpuctx->task_ctx); > perf_pmu_disable(pmu); > > - pmu->sched_task(cpc->task_epc, task, sched_in); > + pmu->sched_task(cpc->task_epc ? cpc->task_epc : &cpc->epc, > + task, sched_in); > > perf_pmu_enable(pmu); > perf_ctx_unlock(cpuctx, cpuctx->task_ctx); > @@ -3919,12 +3920,20 @@ static void perf_pmu_sched_task(struct task_struct *prev, > struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context); > struct perf_cpu_pmu_context *cpc; > > - /* cpuctx->task_ctx will be handled in perf_event_context_sched_in/out */ > - if (prev == next || cpuctx->task_ctx) > + if (prev == next) > return; > > - list_for_each_entry(cpc, this_cpu_ptr(&sched_cb_list), sched_cb_entry) > + list_for_each_entry(cpc, this_cpu_ptr(&sched_cb_list), sched_cb_entry) { > + /* > + * PMUs with per-task events are handled by > + * perf_ctx_sched_task_cb() via perf_event_context_sched_in/out > + * when a task context is active. > + */ > + if (cpuctx->task_ctx && cpc->task_epc) > + continue; > + > __perf_pmu_sched_task(cpc, sched_in ? next : prev, sched_in); > + } > } > > static void perf_event_switch(struct task_struct *task, > -- > 2.53.0-Meta >