The following commit has been merged into the perf/urgent branch of tip:
Commit-ID: 07c5972951f088094776038006a0592a46d14bbc Gitweb: https://git.kernel.org/tip/07c5972951f088094776038006a0592a46d14bbc Author: Song Liu songliubraving@fb.com AuthorDate: Wed, 22 Jan 2020 11:50:27 -08:00 Committer: Ingo Molnar mingo@kernel.org CommitterDate: Tue, 28 Jan 2020 21:20:19 +01:00
perf/cgroups: Install cgroup events to correct cpuctx
cgroup events are always installed in the cpuctx. However, when it is not installed via IPI, list_update_cgroup_event() adds it to cpuctx of current CPU, which triggers list corruption:
[] list_add double add: new=ffff888ff7cf0db0, prev=ffff888ff7ce82f0, next=ffff888ff7cf0db0.
To reproduce this, we can simply run:
# perf stat -e cs -a & # perf stat -e cs -G anycgroup
Fix this by installing it to cpuctx that contains event->ctx, and the proper cgrp_cpuctx_list.
Fixes: db0503e4f675 ("perf/core: Optimize perf_install_in_event()") Suggested-by: Peter Zijlstra (Intel) peterz@infradead.org Signed-off-by: Song Liu songliubraving@fb.com Signed-off-by: Peter Zijlstra (Intel) peterz@infradead.org Signed-off-by: Ingo Molnar mingo@kernel.org Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/20200122195027.2112449-1-songliubraving@fb.com --- kernel/events/core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/kernel/events/core.c b/kernel/events/core.c index 2d9aeba..fdb7f7e 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -951,9 +951,9 @@ list_update_cgroup_event(struct perf_event *event,
/* * Because cgroup events are always per-cpu events, - * this will always be called from the right CPU. + * @ctx == &cpuctx->ctx. */ - cpuctx = __get_cpu_context(ctx); + cpuctx = container_of(ctx, struct perf_cpu_context, ctx);
/* * Since setting cpuctx->cgrp is conditional on the current @cgrp @@ -979,7 +979,8 @@ list_update_cgroup_event(struct perf_event *event,
cpuctx_entry = &cpuctx->cgrp_cpuctx_entry; if (add) - list_add(cpuctx_entry, this_cpu_ptr(&cgrp_cpuctx_list)); + list_add(cpuctx_entry, + per_cpu_ptr(&cgrp_cpuctx_list, event->cpu)); else list_del(cpuctx_entry); }