aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/perf_event.c
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2010-05-11 05:51:53 -0400
committerIngo Molnar <mingo@elte.hu>2010-05-11 09:46:43 -0400
commit050735b08ca8a016bbace4445fa025b88fee770b (patch)
tree68ce73ebb40dfcb66c9c18db9d31bfdb82c2e795 /kernel/perf_event.c
parente3174cfd2a1e28fff774681f00a0eef3d31da970 (diff)
perf: Fix exit() vs PERF_FORMAT_GROUP
Both Stephane and Corey reported that PERF_FORMAT_GROUP didn't work as expected if the task the counters were attached to quit before the read() call. The cause is that we unconditionally destroy the grouping when we remove counters from their context. Fix this by splitting off the group destroy from the list removal such that perf_event_remove_from_context() does not do this and change perf_event_release() to do so. Reported-by: Corey Ashford <cjashfor@linux.vnet.ibm.com> Reported-by: Stephane Eranian <eranian@google.com> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Paul Mackerras <paulus@samba.org> Cc: <stable@kernel.org> # .34.x LKML-Reference: <1273571513.5605.3527.camel@twins> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/perf_event.c')
-rw-r--r--kernel/perf_event.c19
1 files changed, 16 insertions, 3 deletions
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index a9047463fd83..c97e82518403 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -308,8 +308,6 @@ list_add_event(struct perf_event *event, struct perf_event_context *ctx)
308static void 308static void
309list_del_event(struct perf_event *event, struct perf_event_context *ctx) 309list_del_event(struct perf_event *event, struct perf_event_context *ctx)
310{ 310{
311 struct perf_event *sibling, *tmp;
312
313 if (list_empty(&event->group_entry)) 311 if (list_empty(&event->group_entry))
314 return; 312 return;
315 ctx->nr_events--; 313 ctx->nr_events--;
@@ -333,6 +331,12 @@ list_del_event(struct perf_event *event, struct perf_event_context *ctx)
333 */ 331 */
334 if (event->state > PERF_EVENT_STATE_OFF) 332 if (event->state > PERF_EVENT_STATE_OFF)
335 event->state = PERF_EVENT_STATE_OFF; 333 event->state = PERF_EVENT_STATE_OFF;
334}
335
336static void
337perf_destroy_group(struct perf_event *event, struct perf_event_context *ctx)
338{
339 struct perf_event *sibling, *tmp;
336 340
337 /* 341 /*
338 * If this was a group event with sibling events then 342 * If this was a group event with sibling events then
@@ -1868,6 +1872,12 @@ int perf_event_release_kernel(struct perf_event *event)
1868{ 1872{
1869 struct perf_event_context *ctx = event->ctx; 1873 struct perf_event_context *ctx = event->ctx;
1870 1874
1875 /*
1876 * Remove from the PMU, can't get re-enabled since we got
1877 * here because the last ref went.
1878 */
1879 perf_event_disable(event);
1880
1871 WARN_ON_ONCE(ctx->parent_ctx); 1881 WARN_ON_ONCE(ctx->parent_ctx);
1872 /* 1882 /*
1873 * There are two ways this annotation is useful: 1883 * There are two ways this annotation is useful:
@@ -1882,7 +1892,10 @@ int perf_event_release_kernel(struct perf_event *event)
1882 * to trigger the AB-BA case. 1892 * to trigger the AB-BA case.
1883 */ 1893 */
1884 mutex_lock_nested(&ctx->mutex, SINGLE_DEPTH_NESTING); 1894 mutex_lock_nested(&ctx->mutex, SINGLE_DEPTH_NESTING);
1885 perf_event_remove_from_context(event); 1895 raw_spin_lock_irq(&ctx->lock);
1896 list_del_event(event, ctx);
1897 perf_destroy_group(event, ctx);
1898 raw_spin_unlock_irq(&ctx->lock);
1886 mutex_unlock(&ctx->mutex); 1899 mutex_unlock(&ctx->mutex);
1887 1900
1888 mutex_lock(&event->owner->perf_event_mutex); 1901 mutex_lock(&event->owner->perf_event_mutex);