Commit 08446eea authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Luis Henriques

perf: Tighten (and fix) the grouping condition

commit c3c87e77 upstream.

The fix from 9fc81d87 ("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: 9fc81d87 ("perf: Fix events installation during moving group")
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Link: http://lkml.kernel.org/r/20150123125834.090683288@infradead.orgSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
Signed-off-by: default avatarLuis Henriques <luis.henriques@canonical.com>
parent a2d1d5aa
...@@ -453,11 +453,6 @@ struct perf_event { ...@@ -453,11 +453,6 @@ struct perf_event {
#endif /* CONFIG_PERF_EVENTS */ #endif /* CONFIG_PERF_EVENTS */
}; };
enum perf_event_context_type {
task_context,
cpu_context,
};
/** /**
* struct perf_event_context - event context structure * struct perf_event_context - event context structure
* *
...@@ -465,7 +460,6 @@ enum perf_event_context_type { ...@@ -465,7 +460,6 @@ enum perf_event_context_type {
*/ */
struct perf_event_context { struct perf_event_context {
struct pmu *pmu; struct pmu *pmu;
enum perf_event_context_type type;
/* /*
* Protect the states of the events in the list, * Protect the states of the events in the list,
* nr_active, and the list: * nr_active, and the list:
......
...@@ -6633,7 +6633,6 @@ int perf_pmu_register(struct pmu *pmu, const char *name, int type) ...@@ -6633,7 +6633,6 @@ int perf_pmu_register(struct pmu *pmu, const char *name, int type)
__perf_event_init_context(&cpuctx->ctx); __perf_event_init_context(&cpuctx->ctx);
lockdep_set_class(&cpuctx->ctx.mutex, &cpuctx_mutex); lockdep_set_class(&cpuctx->ctx.mutex, &cpuctx_mutex);
lockdep_set_class(&cpuctx->ctx.lock, &cpuctx_lock); lockdep_set_class(&cpuctx->ctx.lock, &cpuctx_lock);
cpuctx->ctx.type = cpu_context;
cpuctx->ctx.pmu = pmu; cpuctx->ctx.pmu = pmu;
__perf_cpu_hrtimer_init(cpuctx, cpu); __perf_cpu_hrtimer_init(cpuctx, cpu);
...@@ -7275,7 +7274,19 @@ SYSCALL_DEFINE5(perf_event_open, ...@@ -7275,7 +7274,19 @@ SYSCALL_DEFINE5(perf_event_open,
* task or CPU context: * task or CPU context:
*/ */
if (move_group) { 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; goto err_context;
} else { } else {
if (group_leader->ctx != ctx) if (group_leader->ctx != ctx)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment