aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-01-24 14:26:47 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2011-01-24 14:26:47 -0500
commit500d85ce39e4d21368fbcdfec6cf3052170aeec8 (patch)
treeee0fe5723ccf82a89df52c2dc58068c03164ae0d /kernel
parentce84d539ce47484ff3cbc9c67b3eb69ae88954f9 (diff)
parent00e99a49f6f3a6b5a84ba8bf8f632c9b974bea7a (diff)
Merge branch 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: perf tools: Fix time function double declaration with glibc perf tools: Fix build by checking if extra warnings are supported perf tools: Fix build when using gcc 3.4.6 perf tools: Add missing header, fixes build perf tools: Fix 64 bit integer format strings perf test: Fix build on older glibcs perf: perf_event_exit_task_context: s/rcu_dereference/rcu_dereference_raw/ perf test: Use cpu_map->[cpu] when setting affinity perf symbols: Fix annotation of thumb code perf: Annotate cpuctx->ctx.mutex to avoid a lockdep splat powerpc, perf: Fix frequency calculation for overflowing counters (FSL version) perf: Fix perf_event_init_task()/perf_event_free_task() interaction perf: Fix find_get_context() vs perf_event_exit_task() race
Diffstat (limited to 'kernel')
-rw-r--r--kernel/perf_event.c46
1 files changed, 27 insertions, 19 deletions
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index 84522c796987..126a302c481c 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -2201,13 +2201,6 @@ find_lively_task_by_vpid(pid_t vpid)
2201 if (!task) 2201 if (!task)
2202 return ERR_PTR(-ESRCH); 2202 return ERR_PTR(-ESRCH);
2203 2203
2204 /*
2205 * Can't attach events to a dying task.
2206 */
2207 err = -ESRCH;
2208 if (task->flags & PF_EXITING)
2209 goto errout;
2210
2211 /* Reuse ptrace permission checks for now. */ 2204 /* Reuse ptrace permission checks for now. */
2212 err = -EACCES; 2205 err = -EACCES;
2213 if (!ptrace_may_access(task, PTRACE_MODE_READ)) 2206 if (!ptrace_may_access(task, PTRACE_MODE_READ))
@@ -2268,14 +2261,27 @@ retry:
2268 2261
2269 get_ctx(ctx); 2262 get_ctx(ctx);
2270 2263
2271 if (cmpxchg(&task->perf_event_ctxp[ctxn], NULL, ctx)) { 2264 err = 0;
2272 /* 2265 mutex_lock(&task->perf_event_mutex);
2273 * We raced with some other task; use 2266 /*
2274 * the context they set. 2267 * If it has already passed perf_event_exit_task().
2275 */ 2268 * we must see PF_EXITING, it takes this mutex too.
2269 */
2270 if (task->flags & PF_EXITING)
2271 err = -ESRCH;
2272 else if (task->perf_event_ctxp[ctxn])
2273 err = -EAGAIN;
2274 else
2275 rcu_assign_pointer(task->perf_event_ctxp[ctxn], ctx);
2276 mutex_unlock(&task->perf_event_mutex);
2277
2278 if (unlikely(err)) {
2276 put_task_struct(task); 2279 put_task_struct(task);
2277 kfree(ctx); 2280 kfree(ctx);
2278 goto retry; 2281
2282 if (err == -EAGAIN)
2283 goto retry;
2284 goto errout;
2279 } 2285 }
2280 } 2286 }
2281 2287
@@ -5374,6 +5380,8 @@ free_dev:
5374 goto out; 5380 goto out;
5375} 5381}
5376 5382
5383static struct lock_class_key cpuctx_mutex;
5384
5377int perf_pmu_register(struct pmu *pmu, char *name, int type) 5385int perf_pmu_register(struct pmu *pmu, char *name, int type)
5378{ 5386{
5379 int cpu, ret; 5387 int cpu, ret;
@@ -5422,6 +5430,7 @@ skip_type:
5422 5430
5423 cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu); 5431 cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu);
5424 __perf_event_init_context(&cpuctx->ctx); 5432 __perf_event_init_context(&cpuctx->ctx);
5433 lockdep_set_class(&cpuctx->ctx.mutex, &cpuctx_mutex);
5425 cpuctx->ctx.type = cpu_context; 5434 cpuctx->ctx.type = cpu_context;
5426 cpuctx->ctx.pmu = pmu; 5435 cpuctx->ctx.pmu = pmu;
5427 cpuctx->jiffies_interval = 1; 5436 cpuctx->jiffies_interval = 1;
@@ -6127,7 +6136,7 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
6127 * scheduled, so we are now safe from rescheduling changing 6136 * scheduled, so we are now safe from rescheduling changing
6128 * our context. 6137 * our context.
6129 */ 6138 */
6130 child_ctx = child->perf_event_ctxp[ctxn]; 6139 child_ctx = rcu_dereference_raw(child->perf_event_ctxp[ctxn]);
6131 task_ctx_sched_out(child_ctx, EVENT_ALL); 6140 task_ctx_sched_out(child_ctx, EVENT_ALL);
6132 6141
6133 /* 6142 /*
@@ -6440,11 +6449,6 @@ int perf_event_init_context(struct task_struct *child, int ctxn)
6440 unsigned long flags; 6449 unsigned long flags;
6441 int ret = 0; 6450 int ret = 0;
6442 6451
6443 child->perf_event_ctxp[ctxn] = NULL;
6444
6445 mutex_init(&child->perf_event_mutex);
6446 INIT_LIST_HEAD(&child->perf_event_list);
6447
6448 if (likely(!parent->perf_event_ctxp[ctxn])) 6452 if (likely(!parent->perf_event_ctxp[ctxn]))
6449 return 0; 6453 return 0;
6450 6454
@@ -6533,6 +6537,10 @@ int perf_event_init_task(struct task_struct *child)
6533{ 6537{
6534 int ctxn, ret; 6538 int ctxn, ret;
6535 6539
6540 memset(child->perf_event_ctxp, 0, sizeof(child->perf_event_ctxp));
6541 mutex_init(&child->perf_event_mutex);
6542 INIT_LIST_HEAD(&child->perf_event_list);
6543
6536 for_each_task_context_nr(ctxn) { 6544 for_each_task_context_nr(ctxn) {
6537 ret = perf_event_init_context(child, ctxn); 6545 ret = perf_event_init_context(child, ctxn);
6538 if (ret) 6546 if (ret)