diff options
| author | Peter Zijlstra <peterz@infradead.org> | 2015-01-23 11:19:48 +0100 |
|---|---|---|
| committer | Ben Hutchings <ben@decadent.org.uk> | 2017-11-11 13:34:31 +0000 |
| commit | 5f542f7740bc8db862b8078e6a621ee7a13427b8 (patch) | |
| tree | e092ef5326206f10a94b1e9b62c9e59abfc54771 /kernel | |
| parent | 5d093344a90a5a6bbe6fde90d2d23370f029df0c (diff) | |
| download | linux-5f542f7740bc8db862b8078e6a621ee7a13427b8.tar.gz linux-5f542f7740bc8db862b8078e6a621ee7a13427b8.tar.bz2 linux-5f542f7740bc8db862b8078e6a621ee7a13427b8.zip | |
perf: Tighten (and fix) the grouping condition
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) <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.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/events/core.c | 15 |
1 files changed, 13 insertions, 2 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c index 675b9684bb9f..68fb9489d1e8 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -6116,7 +6116,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; cpuctx->jiffies_interval = 1; INIT_LIST_HEAD(&cpuctx->rotation_list); @@ -6697,7 +6696,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) |
