aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/perf_counter.h4
-rw-r--r--kernel/fork.c6
-rw-r--r--kernel/perf_counter.c20
3 files changed, 19 insertions, 11 deletions
diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h
index b1f2bac09f97..d3e85de9bf1e 100644
--- a/include/linux/perf_counter.h
+++ b/include/linux/perf_counter.h
@@ -566,7 +566,7 @@ extern void perf_counter_task_sched_in(struct task_struct *task, int cpu);
566extern void perf_counter_task_sched_out(struct task_struct *task, 566extern void perf_counter_task_sched_out(struct task_struct *task,
567 struct task_struct *next, int cpu); 567 struct task_struct *next, int cpu);
568extern void perf_counter_task_tick(struct task_struct *task, int cpu); 568extern void perf_counter_task_tick(struct task_struct *task, int cpu);
569extern void perf_counter_init_task(struct task_struct *child); 569extern int perf_counter_init_task(struct task_struct *child);
570extern void perf_counter_exit_task(struct task_struct *child); 570extern void perf_counter_exit_task(struct task_struct *child);
571extern void perf_counter_do_pending(void); 571extern void perf_counter_do_pending(void);
572extern void perf_counter_print_debug(void); 572extern void perf_counter_print_debug(void);
@@ -631,7 +631,7 @@ perf_counter_task_sched_out(struct task_struct *task,
631 struct task_struct *next, int cpu) { } 631 struct task_struct *next, int cpu) { }
632static inline void 632static inline void
633perf_counter_task_tick(struct task_struct *task, int cpu) { } 633perf_counter_task_tick(struct task_struct *task, int cpu) { }
634static inline void perf_counter_init_task(struct task_struct *child) { } 634static inline int perf_counter_init_task(struct task_struct *child) { }
635static inline void perf_counter_exit_task(struct task_struct *child) { } 635static inline void perf_counter_exit_task(struct task_struct *child) { }
636static inline void perf_counter_do_pending(void) { } 636static inline void perf_counter_do_pending(void) { }
637static inline void perf_counter_print_debug(void) { } 637static inline void perf_counter_print_debug(void) { }
diff --git a/kernel/fork.c b/kernel/fork.c
index 675e01e9072a..c07c3335ceac 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1095,7 +1095,10 @@ static struct task_struct *copy_process(unsigned long clone_flags,
1095 1095
1096 /* Perform scheduler related setup. Assign this task to a CPU. */ 1096 /* Perform scheduler related setup. Assign this task to a CPU. */
1097 sched_fork(p, clone_flags); 1097 sched_fork(p, clone_flags);
1098 perf_counter_init_task(p); 1098
1099 retval = perf_counter_init_task(p);
1100 if (retval)
1101 goto bad_fork_cleanup_policy;
1099 1102
1100 if ((retval = audit_alloc(p))) 1103 if ((retval = audit_alloc(p)))
1101 goto bad_fork_cleanup_policy; 1104 goto bad_fork_cleanup_policy;
@@ -1295,6 +1298,7 @@ bad_fork_cleanup_semundo:
1295bad_fork_cleanup_audit: 1298bad_fork_cleanup_audit:
1296 audit_free(p); 1299 audit_free(p);
1297bad_fork_cleanup_policy: 1300bad_fork_cleanup_policy:
1301 perf_counter_exit_task(p);
1298#ifdef CONFIG_NUMA 1302#ifdef CONFIG_NUMA
1299 mpol_put(p->mempolicy); 1303 mpol_put(p->mempolicy);
1300bad_fork_cleanup_cgroup: 1304bad_fork_cleanup_cgroup:
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c
index 217dbcce2ebd..7a7a144870ef 100644
--- a/kernel/perf_counter.c
+++ b/kernel/perf_counter.c
@@ -3434,18 +3434,23 @@ again:
3434/* 3434/*
3435 * Initialize the perf_counter context in task_struct 3435 * Initialize the perf_counter context in task_struct
3436 */ 3436 */
3437void perf_counter_init_task(struct task_struct *child) 3437int perf_counter_init_task(struct task_struct *child)
3438{ 3438{
3439 struct perf_counter_context *child_ctx, *parent_ctx; 3439 struct perf_counter_context *child_ctx, *parent_ctx;
3440 struct perf_counter *counter; 3440 struct perf_counter *counter;
3441 struct task_struct *parent = current; 3441 struct task_struct *parent = current;
3442 int inherited_all = 1; 3442 int inherited_all = 1;
3443 int ret = 0;
3443 3444
3444 child->perf_counter_ctxp = NULL; 3445 child->perf_counter_ctxp = NULL;
3445 3446
3446 mutex_init(&child->perf_counter_mutex); 3447 mutex_init(&child->perf_counter_mutex);
3447 INIT_LIST_HEAD(&child->perf_counter_list); 3448 INIT_LIST_HEAD(&child->perf_counter_list);
3448 3449
3450 parent_ctx = parent->perf_counter_ctxp;
3451 if (likely(!parent_ctx || !parent_ctx->nr_counters))
3452 return 0;
3453
3449 /* 3454 /*
3450 * This is executed from the parent task context, so inherit 3455 * This is executed from the parent task context, so inherit
3451 * counters that have been marked for cloning. 3456 * counters that have been marked for cloning.
@@ -3454,11 +3459,7 @@ void perf_counter_init_task(struct task_struct *child)
3454 3459
3455 child_ctx = kmalloc(sizeof(struct perf_counter_context), GFP_KERNEL); 3460 child_ctx = kmalloc(sizeof(struct perf_counter_context), GFP_KERNEL);
3456 if (!child_ctx) 3461 if (!child_ctx)
3457 return; 3462 return -ENOMEM;
3458
3459 parent_ctx = parent->perf_counter_ctxp;
3460 if (likely(!parent_ctx || !parent_ctx->nr_counters))
3461 return;
3462 3463
3463 __perf_counter_init_context(child_ctx, child); 3464 __perf_counter_init_context(child_ctx, child);
3464 child->perf_counter_ctxp = child_ctx; 3465 child->perf_counter_ctxp = child_ctx;
@@ -3482,8 +3483,9 @@ void perf_counter_init_task(struct task_struct *child)
3482 continue; 3483 continue;
3483 } 3484 }
3484 3485
3485 if (inherit_group(counter, parent, 3486 ret = inherit_group(counter, parent, parent_ctx,
3486 parent_ctx, child, child_ctx)) { 3487 child, child_ctx);
3488 if (ret) {
3487 inherited_all = 0; 3489 inherited_all = 0;
3488 break; 3490 break;
3489 } 3491 }
@@ -3505,6 +3507,8 @@ void perf_counter_init_task(struct task_struct *child)
3505 } 3507 }
3506 3508
3507 mutex_unlock(&parent_ctx->mutex); 3509 mutex_unlock(&parent_ctx->mutex);
3510
3511 return ret;
3508} 3512}
3509 3513
3510static void __cpuinit perf_counter_init_cpu(int cpu) 3514static void __cpuinit perf_counter_init_cpu(int cpu)