Commit d8a8cfc7 authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Ingo Molnar

perf/core: Better explain the inherit magic

While going through the event inheritance code Oleg got confused.

Add some comments to better explain the silent dissapearance of
orphaned events.

So what happens is that at perf_event_release_kernel() time; when an
event looses its connection to userspace (and ceases to exist from the
user's perspective) we can still have an arbitrary amount of inherited
copies of the event. We want to synchronously find and remove all
these child events.

Since that requires a bit of lock juggling, there is the possibility
that concurrent clone()s will create new child events. Therefore we
first mark the parent event as DEAD, which marks all the extant child
events as orphaned.

We then avoid copying orphaned events; in order to avoid getting more
of them.
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Vince Weaver <vincent.weaver@maine.edu>
Cc: fweisbec@gmail.com
Link: http://lkml.kernel.org/r/20170316125823.289567442@infradead.orgSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 15121c78
...@@ -4254,7 +4254,7 @@ int perf_event_release_kernel(struct perf_event *event) ...@@ -4254,7 +4254,7 @@ int perf_event_release_kernel(struct perf_event *event)
raw_spin_lock_irq(&ctx->lock); raw_spin_lock_irq(&ctx->lock);
/* /*
* Mark this even as STATE_DEAD, there is no external reference to it * Mark this event as STATE_DEAD, there is no external reference to it
* anymore. * anymore.
* *
* Anybody acquiring event->child_mutex after the below loop _must_ * Anybody acquiring event->child_mutex after the below loop _must_
...@@ -10468,7 +10468,12 @@ const struct perf_event_attr *perf_event_attrs(struct perf_event *event) ...@@ -10468,7 +10468,12 @@ const struct perf_event_attr *perf_event_attrs(struct perf_event *event)
} }
/* /*
* inherit a event from parent task to child task: * Inherit a event from parent task to child task.
*
* Returns:
* - valid pointer on success
* - NULL for orphaned events
* - IS_ERR() on error
*/ */
static struct perf_event * static struct perf_event *
inherit_event(struct perf_event *parent_event, inherit_event(struct perf_event *parent_event,
...@@ -10562,6 +10567,16 @@ inherit_event(struct perf_event *parent_event, ...@@ -10562,6 +10567,16 @@ inherit_event(struct perf_event *parent_event,
return child_event; return child_event;
} }
/*
* Inherits an event group.
*
* This will quietly suppress orphaned events; !inherit_event() is not an error.
* This matches with perf_event_release_kernel() removing all child events.
*
* Returns:
* - 0 on success
* - <0 on error
*/
static int inherit_group(struct perf_event *parent_event, static int inherit_group(struct perf_event *parent_event,
struct task_struct *parent, struct task_struct *parent,
struct perf_event_context *parent_ctx, struct perf_event_context *parent_ctx,
...@@ -10576,6 +10591,11 @@ static int inherit_group(struct perf_event *parent_event, ...@@ -10576,6 +10591,11 @@ static int inherit_group(struct perf_event *parent_event,
child, NULL, child_ctx); child, NULL, child_ctx);
if (IS_ERR(leader)) if (IS_ERR(leader))
return PTR_ERR(leader); return PTR_ERR(leader);
/*
* @leader can be NULL here because of is_orphaned_event(). In this
* case inherit_event() will create individual events, similar to what
* perf_group_detach() would do anyway.
*/
list_for_each_entry(sub, &parent_event->sibling_list, group_entry) { list_for_each_entry(sub, &parent_event->sibling_list, group_entry) {
child_ctr = inherit_event(sub, parent, parent_ctx, child_ctr = inherit_event(sub, parent, parent_ctx,
child, leader, child_ctx); child, leader, child_ctx);
...@@ -10585,6 +10605,17 @@ static int inherit_group(struct perf_event *parent_event, ...@@ -10585,6 +10605,17 @@ static int inherit_group(struct perf_event *parent_event,
return 0; return 0;
} }
/*
* Creates the child task context and tries to inherit the event-group.
*
* Clears @inherited_all on !attr.inherited or error. Note that we'll leave
* inherited_all set when we 'fail' to inherit an orphaned event; this is
* consistent with perf_event_release_kernel() removing all child events.
*
* Returns:
* - 0 on success
* - <0 on error
*/
static int static int
inherit_task_group(struct perf_event *event, struct task_struct *parent, inherit_task_group(struct perf_event *event, struct task_struct *parent,
struct perf_event_context *parent_ctx, struct perf_event_context *parent_ctx,
...@@ -10607,7 +10638,6 @@ inherit_task_group(struct perf_event *event, struct task_struct *parent, ...@@ -10607,7 +10638,6 @@ inherit_task_group(struct perf_event *event, struct task_struct *parent,
* First allocate and initialize a context for the * First allocate and initialize a context for the
* child. * child.
*/ */
child_ctx = alloc_perf_context(parent_ctx->pmu, child); child_ctx = alloc_perf_context(parent_ctx->pmu, child);
if (!child_ctx) if (!child_ctx)
return -ENOMEM; return -ENOMEM;
......
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