aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/events
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2016-02-24 12:45:44 -0500
committerIngo Molnar <mingo@kernel.org>2016-02-25 02:42:33 -0500
commita69b0ca4ac3bf5427b571f11cbf33f0a32b728d5 (patch)
tree551099312337a9f3a435f1169d857385972d48b3 /kernel/events
parent6f932e5be1503ab0783699e843db325d44c2fabb (diff)
perf: Fix cloning
Alexander reported that when the 'original' context gets destroyed, no new clones happen. This can happen irrespective of the ctx switch optimization, any task can die, even the parent, and we want to continue monitoring the task hierarchy until we either close the event or no tasks are left in the hierarchy. perf_event_init_context() will attempt to pin the 'parent' context during clone(). At that point current is the parent, and since current cannot have exited while executing clone(), its context cannot have passed through perf_event_exit_task_context(). Therefore perf_pin_task_context() cannot observe ctx->task == TASK_TOMBSTONE. However, since inherit_event() does: if (parent_event->parent) parent_event = parent_event->parent; it looks at the 'original' event when it does: is_orphaned_event(). This can return true if the context that contains the this event has passed through perf_event_exit_task_context(). And thus we'll fail to clone the perf context. Fix this by adding a new state: STATE_DEAD, which is set by perf_release() to indicate that the filedesc (or kernel reference) is dead and there are no observers for our data left. Only for STATE_DEAD will is_orphaned_event() be true and inhibit cloning. STATE_EXIT is otherwise preserved such that is_event_hup() remains functional and will report when the observed task hierarchy becomes empty. Reported-by: Alexander Shishkin <alexander.shishkin@linux.intel.com> Tested-by: Alexander Shishkin <alexander.shishkin@linux.intel.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: dvyukov@google.com Cc: eranian@google.com Cc: oleg@redhat.com Cc: panand@redhat.com Cc: sasha.levin@oracle.com Cc: vince@deater.net Fixes: c6e5b73242d2 ("perf: Synchronously clean up child events") Link: http://lkml.kernel.org/r/20160224174947.919845295@infradead.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel/events')
-rw-r--r--kernel/events/core.c29
1 files changed, 14 insertions, 15 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 64698fbfad9f..92d6999a4f2f 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -1645,7 +1645,7 @@ out:
1645 1645
1646static bool is_orphaned_event(struct perf_event *event) 1646static bool is_orphaned_event(struct perf_event *event)
1647{ 1647{
1648 return event->state == PERF_EVENT_STATE_EXIT; 1648 return event->state == PERF_EVENT_STATE_DEAD;
1649} 1649}
1650 1650
1651static inline int pmu_filter_match(struct perf_event *event) 1651static inline int pmu_filter_match(struct perf_event *event)
@@ -1732,7 +1732,6 @@ group_sched_out(struct perf_event *group_event,
1732} 1732}
1733 1733
1734#define DETACH_GROUP 0x01UL 1734#define DETACH_GROUP 0x01UL
1735#define DETACH_STATE 0x02UL
1736 1735
1737/* 1736/*
1738 * Cross CPU call to remove a performance event 1737 * Cross CPU call to remove a performance event
@@ -1752,8 +1751,6 @@ __perf_remove_from_context(struct perf_event *event,
1752 if (flags & DETACH_GROUP) 1751 if (flags & DETACH_GROUP)
1753 perf_group_detach(event); 1752 perf_group_detach(event);
1754 list_del_event(event, ctx); 1753 list_del_event(event, ctx);
1755 if (flags & DETACH_STATE)
1756 event->state = PERF_EVENT_STATE_EXIT;
1757 1754
1758 if (!ctx->nr_events && ctx->is_active) { 1755 if (!ctx->nr_events && ctx->is_active) {
1759 ctx->is_active = 0; 1756 ctx->is_active = 0;
@@ -3772,22 +3769,24 @@ int perf_event_release_kernel(struct perf_event *event)
3772 3769
3773 ctx = perf_event_ctx_lock(event); 3770 ctx = perf_event_ctx_lock(event);
3774 WARN_ON_ONCE(ctx->parent_ctx); 3771 WARN_ON_ONCE(ctx->parent_ctx);
3775 perf_remove_from_context(event, DETACH_GROUP | DETACH_STATE); 3772 perf_remove_from_context(event, DETACH_GROUP);
3776 perf_event_ctx_unlock(event, ctx);
3777 3773
3774 raw_spin_lock_irq(&ctx->lock);
3778 /* 3775 /*
3779 * At this point we must have event->state == PERF_EVENT_STATE_EXIT, 3776 * Mark this even as STATE_DEAD, there is no external reference to it
3780 * either from the above perf_remove_from_context() or through 3777 * anymore.
3781 * perf_event_exit_event().
3782 * 3778 *
3783 * Therefore, anybody acquiring event->child_mutex after the below 3779 * Anybody acquiring event->child_mutex after the below loop _must_
3784 * loop _must_ also see this, most importantly inherit_event() which 3780 * also see this, most importantly inherit_event() which will avoid
3785 * will avoid placing more children on the list. 3781 * placing more children on the list.
3786 * 3782 *
3787 * Thus this guarantees that we will in fact observe and kill _ALL_ 3783 * Thus this guarantees that we will in fact observe and kill _ALL_
3788 * child events. 3784 * child events.
3789 */ 3785 */
3790 WARN_ON_ONCE(event->state != PERF_EVENT_STATE_EXIT); 3786 event->state = PERF_EVENT_STATE_DEAD;
3787 raw_spin_unlock_irq(&ctx->lock);
3788
3789 perf_event_ctx_unlock(event, ctx);
3791 3790
3792again: 3791again:
3793 mutex_lock(&event->child_mutex); 3792 mutex_lock(&event->child_mutex);
@@ -4000,7 +3999,7 @@ static bool is_event_hup(struct perf_event *event)
4000{ 3999{
4001 bool no_children; 4000 bool no_children;
4002 4001
4003 if (event->state != PERF_EVENT_STATE_EXIT) 4002 if (event->state > PERF_EVENT_STATE_EXIT)
4004 return false; 4003 return false;
4005 4004
4006 mutex_lock(&event->child_mutex); 4005 mutex_lock(&event->child_mutex);
@@ -8727,7 +8726,7 @@ perf_event_exit_event(struct perf_event *child_event,
8727 if (parent_event) 8726 if (parent_event)
8728 perf_group_detach(child_event); 8727 perf_group_detach(child_event);
8729 list_del_event(child_event, child_ctx); 8728 list_del_event(child_event, child_ctx);
8730 child_event->state = PERF_EVENT_STATE_EXIT; /* see perf_event_release_kernel() */ 8729 child_event->state = PERF_EVENT_STATE_EXIT; /* is_event_hup() */
8731 raw_spin_unlock_irq(&child_ctx->lock); 8730 raw_spin_unlock_irq(&child_ctx->lock);
8732 8731
8733 /* 8732 /*