diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2009-03-19 15:26:16 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-04-06 03:30:16 -0400 |
commit | f16009527595ee562308653bc3d0039166d2ab15 (patch) | |
tree | 1fc6f2e5632bd0b2c624ed106a047d6d2127e59c | |
parent | 4a0deca657f3dbb8a707b5dc8f173beec01e7ed2 (diff) |
perf_counter: fix up counter free paths
Impact: fix crash during perfcounters use
I found another counter free path, create a free_counter() call to
accomodate generic tear-down.
Fixes an RCU bug.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Orig-LKML-Reference: <20090319194233.652078652@chello.nl>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | kernel/perf_counter.c | 11 |
1 files changed, 8 insertions, 3 deletions
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 99d5930f0a52..97f891ffeb40 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c | |||
@@ -1150,6 +1150,11 @@ static void free_counter_rcu(struct rcu_head *head) | |||
1150 | kfree(counter); | 1150 | kfree(counter); |
1151 | } | 1151 | } |
1152 | 1152 | ||
1153 | static void free_counter(struct perf_counter *counter) | ||
1154 | { | ||
1155 | call_rcu(&counter->rcu_head, free_counter_rcu); | ||
1156 | } | ||
1157 | |||
1153 | /* | 1158 | /* |
1154 | * Called when the last reference to the file is gone. | 1159 | * Called when the last reference to the file is gone. |
1155 | */ | 1160 | */ |
@@ -1168,7 +1173,7 @@ static int perf_release(struct inode *inode, struct file *file) | |||
1168 | mutex_unlock(&counter->mutex); | 1173 | mutex_unlock(&counter->mutex); |
1169 | mutex_unlock(&ctx->mutex); | 1174 | mutex_unlock(&ctx->mutex); |
1170 | 1175 | ||
1171 | call_rcu(&counter->rcu_head, free_counter_rcu); | 1176 | free_counter(counter); |
1172 | put_context(ctx); | 1177 | put_context(ctx); |
1173 | 1178 | ||
1174 | return 0; | 1179 | return 0; |
@@ -2128,10 +2133,10 @@ __perf_counter_exit_task(struct task_struct *child, | |||
2128 | list_entry) { | 2133 | list_entry) { |
2129 | if (sub->parent) { | 2134 | if (sub->parent) { |
2130 | sync_child_counter(sub, sub->parent); | 2135 | sync_child_counter(sub, sub->parent); |
2131 | kfree(sub); | 2136 | free_counter(sub); |
2132 | } | 2137 | } |
2133 | } | 2138 | } |
2134 | kfree(child_counter); | 2139 | free_counter(child_counter); |
2135 | } | 2140 | } |
2136 | } | 2141 | } |
2137 | 2142 | ||