diff options
-rw-r--r-- | kernel/events/core.c | 18 |
1 files changed, 17 insertions, 1 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c index c46b02bfe179..6b17ac1b0c2a 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
@@ -7486,7 +7486,7 @@ __perf_event_exit_task(struct perf_event *child_event, | |||
7486 | static void perf_event_exit_task_context(struct task_struct *child, int ctxn) | 7486 | static void perf_event_exit_task_context(struct task_struct *child, int ctxn) |
7487 | { | 7487 | { |
7488 | struct perf_event *child_event, *next; | 7488 | struct perf_event *child_event, *next; |
7489 | struct perf_event_context *child_ctx; | 7489 | struct perf_event_context *child_ctx, *parent_ctx; |
7490 | unsigned long flags; | 7490 | unsigned long flags; |
7491 | 7491 | ||
7492 | if (likely(!child->perf_event_ctxp[ctxn])) { | 7492 | if (likely(!child->perf_event_ctxp[ctxn])) { |
@@ -7511,6 +7511,15 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn) | |||
7511 | raw_spin_lock(&child_ctx->lock); | 7511 | raw_spin_lock(&child_ctx->lock); |
7512 | task_ctx_sched_out(child_ctx); | 7512 | task_ctx_sched_out(child_ctx); |
7513 | child->perf_event_ctxp[ctxn] = NULL; | 7513 | child->perf_event_ctxp[ctxn] = NULL; |
7514 | |||
7515 | /* | ||
7516 | * In order to avoid freeing: child_ctx->parent_ctx->task | ||
7517 | * under perf_event_context::lock, grab another reference. | ||
7518 | */ | ||
7519 | parent_ctx = child_ctx->parent_ctx; | ||
7520 | if (parent_ctx) | ||
7521 | get_ctx(parent_ctx); | ||
7522 | |||
7514 | /* | 7523 | /* |
7515 | * If this context is a clone; unclone it so it can't get | 7524 | * If this context is a clone; unclone it so it can't get |
7516 | * swapped to another process while we're removing all | 7525 | * swapped to another process while we're removing all |
@@ -7521,6 +7530,13 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn) | |||
7521 | raw_spin_unlock_irqrestore(&child_ctx->lock, flags); | 7530 | raw_spin_unlock_irqrestore(&child_ctx->lock, flags); |
7522 | 7531 | ||
7523 | /* | 7532 | /* |
7533 | * Now that we no longer hold perf_event_context::lock, drop | ||
7534 | * our extra child_ctx->parent_ctx reference. | ||
7535 | */ | ||
7536 | if (parent_ctx) | ||
7537 | put_ctx(parent_ctx); | ||
7538 | |||
7539 | /* | ||
7524 | * Report the task dead after unscheduling the events so that we | 7540 | * Report the task dead after unscheduling the events so that we |
7525 | * won't get any samples after PERF_RECORD_EXIT. We can however still | 7541 | * won't get any samples after PERF_RECORD_EXIT. We can however still |
7526 | * get a few PERF_RECORD_READ events. | 7542 | * get a few PERF_RECORD_READ events. |