diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2009-05-29 08:25:58 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-05-29 10:21:52 -0400 |
commit | bbbee90829304d156c12b171c0ac7e6e1aba8b90 (patch) | |
tree | ec0a1a8c69a5c909a57227915734d1e55678eb5c /kernel/perf_counter.c | |
parent | 665c2142a94202881a3c11cbaee6506cb10ada2d (diff) |
perf_counter: Ammend cleanup in fork() fail
When fork() fails we cannot use perf_counter_exit_task() since that
assumes to operate on current. Write a new helper that cleans up
unused/clean contexts.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: John Kacur <jkacur@redhat.com>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/perf_counter.c')
-rw-r--r-- | kernel/perf_counter.c | 43 |
1 files changed, 40 insertions, 3 deletions
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 0c000d305e0e..79c3f26541d3 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c | |||
@@ -3538,8 +3538,7 @@ static void sync_child_counter(struct perf_counter *child_counter, | |||
3538 | } | 3538 | } |
3539 | 3539 | ||
3540 | static void | 3540 | static void |
3541 | __perf_counter_exit_task(struct task_struct *child, | 3541 | __perf_counter_exit_task(struct perf_counter *child_counter, |
3542 | struct perf_counter *child_counter, | ||
3543 | struct perf_counter_context *child_ctx) | 3542 | struct perf_counter_context *child_ctx) |
3544 | { | 3543 | { |
3545 | struct perf_counter *parent_counter; | 3544 | struct perf_counter *parent_counter; |
@@ -3605,7 +3604,7 @@ void perf_counter_exit_task(struct task_struct *child) | |||
3605 | again: | 3604 | again: |
3606 | list_for_each_entry_safe(child_counter, tmp, &child_ctx->counter_list, | 3605 | list_for_each_entry_safe(child_counter, tmp, &child_ctx->counter_list, |
3607 | list_entry) | 3606 | list_entry) |
3608 | __perf_counter_exit_task(child, child_counter, child_ctx); | 3607 | __perf_counter_exit_task(child_counter, child_ctx); |
3609 | 3608 | ||
3610 | /* | 3609 | /* |
3611 | * If the last counter was a group counter, it will have appended all | 3610 | * If the last counter was a group counter, it will have appended all |
@@ -3621,6 +3620,44 @@ again: | |||
3621 | } | 3620 | } |
3622 | 3621 | ||
3623 | /* | 3622 | /* |
3623 | * free an unexposed, unused context as created by inheritance by | ||
3624 | * init_task below, used by fork() in case of fail. | ||
3625 | */ | ||
3626 | void perf_counter_free_task(struct task_struct *task) | ||
3627 | { | ||
3628 | struct perf_counter_context *ctx = task->perf_counter_ctxp; | ||
3629 | struct perf_counter *counter, *tmp; | ||
3630 | |||
3631 | if (!ctx) | ||
3632 | return; | ||
3633 | |||
3634 | mutex_lock(&ctx->mutex); | ||
3635 | again: | ||
3636 | list_for_each_entry_safe(counter, tmp, &ctx->counter_list, list_entry) { | ||
3637 | struct perf_counter *parent = counter->parent; | ||
3638 | |||
3639 | if (WARN_ON_ONCE(!parent)) | ||
3640 | continue; | ||
3641 | |||
3642 | mutex_lock(&parent->child_mutex); | ||
3643 | list_del_init(&counter->child_list); | ||
3644 | mutex_unlock(&parent->child_mutex); | ||
3645 | |||
3646 | fput(parent->filp); | ||
3647 | |||
3648 | list_del_counter(counter, ctx); | ||
3649 | free_counter(counter); | ||
3650 | } | ||
3651 | |||
3652 | if (!list_empty(&ctx->counter_list)) | ||
3653 | goto again; | ||
3654 | |||
3655 | mutex_unlock(&ctx->mutex); | ||
3656 | |||
3657 | put_ctx(ctx); | ||
3658 | } | ||
3659 | |||
3660 | /* | ||
3624 | * Initialize the perf_counter context in task_struct | 3661 | * Initialize the perf_counter context in task_struct |
3625 | */ | 3662 | */ |
3626 | int perf_counter_init_task(struct task_struct *child) | 3663 | int perf_counter_init_task(struct task_struct *child) |