From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: From: Kamal Mostafa To: linux-kernel@vger.kernel.org, stable@vger.kernel.org, kernel-team@lists.ubuntu.com Cc: "Peter Zijlstra (Intel)" , Arnaldo Carvalho de Melo , Jiri Olsa , Linus Torvalds , Ingo Molnar , Kamal Mostafa Subject: [PATCH 3.13.y-ckt 58/80] perf: Tighten (and fix) the grouping condition Date: Thu, 19 Mar 2015 15:35:46 -0700 Message-Id: <1426804568-2907-59-git-send-email-kamal@canonical.com> In-Reply-To: <1426804568-2907-1-git-send-email-kamal@canonical.com> References: <1426804568-2907-1-git-send-email-kamal@canonical.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: 3.13.11-ckt17 -stable review patch. If anyone has any objections, please let me know. ------------------ From: Peter Zijlstra commit c3c87e770458aa004bd7ed3f29945ff436fd6511 upstream. The fix from 9fc81d87420d ("perf: Fix events installation during moving group") was incomplete in that it failed to recognise that creating a group with events for different CPUs is semantically broken -- they cannot be co-scheduled. Furthermore, it leads to real breakage where, when we create an event for CPU Y and then migrate it to form a group on CPU X, the code gets confused where the counter is programmed -- triggered in practice as well by me via the perf fuzzer. Fix this by tightening the rules for creating groups. Only allow grouping of counters that can be co-scheduled in the same context. This means for the same task and/or the same cpu. Fixes: 9fc81d87420d ("perf: Fix events installation during moving group") Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Link: http://lkml.kernel.org/r/20150123125834.090683288@infradead.org Signed-off-by: Ingo Molnar Signed-off-by: Kamal Mostafa --- include/linux/perf_event.h | 6 ------ kernel/events/core.c | 15 +++++++++++++-- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 2e069d1..01249d9 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -439,11 +439,6 @@ struct perf_event { #endif /* CONFIG_PERF_EVENTS */ }; -enum perf_event_context_type { - task_context, - cpu_context, -}; - /** * struct perf_event_context - event context structure * @@ -451,7 +446,6 @@ enum perf_event_context_type { */ struct perf_event_context { struct pmu *pmu; - enum perf_event_context_type type; /* * Protect the states of the events in the list, * nr_active, and the list: diff --git a/kernel/events/core.c b/kernel/events/core.c index 5f06486..68105f2 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -6499,7 +6499,6 @@ skip_type: __perf_event_init_context(&cpuctx->ctx); lockdep_set_class(&cpuctx->ctx.mutex, &cpuctx_mutex); lockdep_set_class(&cpuctx->ctx.lock, &cpuctx_lock); - cpuctx->ctx.type = cpu_context; cpuctx->ctx.pmu = pmu; __perf_cpu_hrtimer_init(cpuctx, cpu); @@ -7132,7 +7131,19 @@ SYSCALL_DEFINE5(perf_event_open, * task or CPU context: */ if (move_group) { - if (group_leader->ctx->type != ctx->type) + /* + * Make sure we're both on the same task, or both + * per-cpu events. + */ + if (group_leader->ctx->task != ctx->task) + goto err_context; + + /* + * Make sure we're both events for the same CPU; + * grouping events for different CPUs is broken; since + * you can never concurrently schedule them anyhow. + */ + if (group_leader->cpu != event->cpu) goto err_context; } else { if (group_leader->ctx != ctx) -- 1.9.1