Some PMUs rely on the fact that struct perf_event::hw::target always point to the actual event target during the whole event lifecycle, ie: from pmu::init() to event::destroy().
Now perf event ctx swapping on task sched switch breaks that guarantee. Solve that with providing a way for a PMU to pin the context of an event. Reported-by: [email protected] Cc: Borislav Petkov <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Dmitry Vyukov <[email protected]> Cc: Namhyung Kim <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: Arnaldo Carvalho de Melo <[email protected]> Cc: Masami Hiramatsu <[email protected]> Signed-off-by: Frederic Weisbecker <[email protected]> --- include/linux/perf_event.h | 2 ++ kernel/events/core.c | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 2ddae518dce6..ea700a193865 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -273,6 +273,8 @@ struct pmu { /* number of address filters this PMU can do */ unsigned int nr_addr_filters; + int pin_ctx; + /* * Fully disable/enable this PMU, can be used to protect from the PMI * as well as for lazy/batch writing of the MSRs. diff --git a/kernel/events/core.c b/kernel/events/core.c index 23efe6792abc..6b4bc6fc47aa 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -1689,6 +1689,9 @@ list_add_event(struct perf_event *event, struct perf_event_context *ctx) ctx->nr_stat++; ctx->generation++; + + if (event->pmu->pin_ctx) + ctx->pin_count++; } /* @@ -1885,6 +1888,9 @@ list_del_event(struct perf_event *event, struct perf_event_context *ctx) perf_event_set_state(event, PERF_EVENT_STATE_OFF); ctx->generation++; + + if (event->pmu->pin_ctx) + ctx->pin_count--; } static void perf_group_detach(struct perf_event *event) -- 2.21.0

