diff options
author | Peter Zijlstra <peterz@infradead.org> | 2015-01-23 05:19:48 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-01-28 07:17:35 -0500 |
commit | c3c87e770458aa004bd7ed3f29945ff436fd6511 (patch) | |
tree | 79074706175f54d333daf61cc0794aa9d76b1909 | |
parent | ef454caeb740ee4e1b89aeb7f7692d5ddffb6830 (diff) |
perf: Tighten (and fix) the grouping condition
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>
-rw-r--r-- | include/linux/perf_event.h | 6 | ||||
-rw-r--r-- | 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 4f7a61ca4b39..664de5a4ec46 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
@@ -450,11 +450,6 @@ struct perf_event { | |||
450 | #endif /* CONFIG_PERF_EVENTS */ | 450 | #endif /* CONFIG_PERF_EVENTS */ |
451 | }; | 451 | }; |
452 | 452 | ||
453 | enum perf_event_context_type { | ||
454 | task_context, | ||
455 | cpu_context, | ||
456 | }; | ||
457 | |||
458 | /** | 453 | /** |
459 | * struct perf_event_context - event context structure | 454 | * struct perf_event_context - event context structure |
460 | * | 455 | * |
@@ -462,7 +457,6 @@ enum perf_event_context_type { | |||
462 | */ | 457 | */ |
463 | struct perf_event_context { | 458 | struct perf_event_context { |
464 | struct pmu *pmu; | 459 | struct pmu *pmu; |
465 | enum perf_event_context_type type; | ||
466 | /* | 460 | /* |
467 | * Protect the states of the events in the list, | 461 | * Protect the states of the events in the list, |
468 | * nr_active, and the list: | 462 | * nr_active, and the list: |
diff --git a/kernel/events/core.c b/kernel/events/core.c index 882f835a0d85..19efcf13375a 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
@@ -6776,7 +6776,6 @@ skip_type: | |||
6776 | __perf_event_init_context(&cpuctx->ctx); | 6776 | __perf_event_init_context(&cpuctx->ctx); |
6777 | lockdep_set_class(&cpuctx->ctx.mutex, &cpuctx_mutex); | 6777 | lockdep_set_class(&cpuctx->ctx.mutex, &cpuctx_mutex); |
6778 | lockdep_set_class(&cpuctx->ctx.lock, &cpuctx_lock); | 6778 | lockdep_set_class(&cpuctx->ctx.lock, &cpuctx_lock); |
6779 | cpuctx->ctx.type = cpu_context; | ||
6780 | cpuctx->ctx.pmu = pmu; | 6779 | cpuctx->ctx.pmu = pmu; |
6781 | 6780 | ||
6782 | __perf_cpu_hrtimer_init(cpuctx, cpu); | 6781 | __perf_cpu_hrtimer_init(cpuctx, cpu); |
@@ -7420,7 +7419,19 @@ SYSCALL_DEFINE5(perf_event_open, | |||
7420 | * task or CPU context: | 7419 | * task or CPU context: |
7421 | */ | 7420 | */ |
7422 | if (move_group) { | 7421 | if (move_group) { |
7423 | if (group_leader->ctx->type != ctx->type) | 7422 | /* |
7423 | * Make sure we're both on the same task, or both | ||
7424 | * per-cpu events. | ||
7425 | */ | ||
7426 | if (group_leader->ctx->task != ctx->task) | ||
7427 | goto err_context; | ||
7428 | |||
7429 | /* | ||
7430 | * Make sure we're both events for the same CPU; | ||
7431 | * grouping events for different CPUs is broken; since | ||
7432 | * you can never concurrently schedule them anyhow. | ||
7433 | */ | ||
7434 | if (group_leader->cpu != event->cpu) | ||
7424 | goto err_context; | 7435 | goto err_context; |
7425 | } else { | 7436 | } else { |
7426 | if (group_leader->ctx != ctx) | 7437 | if (group_leader->ctx != ctx) |