diff options
Diffstat (limited to 'kernel')
| -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. |
