summaryrefslogtreecommitdiffstats
path: root/kernel/events
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2014-05-05 06:11:24 -0400
committerIngo Molnar <mingo@kernel.org>2014-05-07 07:44:19 -0400
commit683ede43dd412c6cad0d23578a018409ac9c683e (patch)
tree18a640da4a9355e3ef9b7944f62ab4303eed122d /kernel/events
parent63342411efd2d9350ad405205da036cd45ed1640 (diff)
perf: Rework free paths
Primarily make perf_event_release_kernel() into put_event(), this will allow kernel space to create per-task inherited events, and is safer in general. Also, document the free_event() assumptions. Signed-off-by: Peter Zijlstra <peterz@infradead.org> Cc: Arnaldo Carvalho de Melo <acme@kernel.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Vince Weaver <vincent.weaver@maine.edu> Cc: Stephane Eranian <eranian@google.com> Link: http://lkml.kernel.org/n/tip-rk9pvr6e1d0559lxstltbztc@git.kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel/events')
-rw-r--r--kernel/events/core.c66
1 files changed, 40 insertions, 26 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 0de199729f04..83505a35afba 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -3251,7 +3251,8 @@ static void __free_event(struct perf_event *event)
3251 3251
3252 call_rcu(&event->rcu_head, free_event_rcu); 3252 call_rcu(&event->rcu_head, free_event_rcu);
3253} 3253}
3254static void free_event(struct perf_event *event) 3254
3255static void _free_event(struct perf_event *event)
3255{ 3256{
3256 irq_work_sync(&event->pending); 3257 irq_work_sync(&event->pending);
3257 3258
@@ -3279,42 +3280,31 @@ static void free_event(struct perf_event *event)
3279 if (is_cgroup_event(event)) 3280 if (is_cgroup_event(event))
3280 perf_detach_cgroup(event); 3281 perf_detach_cgroup(event);
3281 3282
3282
3283 __free_event(event); 3283 __free_event(event);
3284} 3284}
3285 3285
3286int perf_event_release_kernel(struct perf_event *event) 3286/*
3287 * Used to free events which have a known refcount of 1, such as in error paths
3288 * where the event isn't exposed yet and inherited events.
3289 */
3290static void free_event(struct perf_event *event)
3287{ 3291{
3288 struct perf_event_context *ctx = event->ctx; 3292 if (WARN(atomic_long_cmpxchg(&event->refcount, 1, 0) != 1,
3289 3293 "unexpected event refcount: %ld; ptr=%p\n",
3290 WARN_ON_ONCE(ctx->parent_ctx); 3294 atomic_long_read(&event->refcount), event)) {
3291 /* 3295 /* leak to avoid use-after-free */
3292 * There are two ways this annotation is useful: 3296 return;
3293 * 3297 }
3294 * 1) there is a lock recursion from perf_event_exit_task
3295 * see the comment there.
3296 *
3297 * 2) there is a lock-inversion with mmap_sem through
3298 * perf_event_read_group(), which takes faults while
3299 * holding ctx->mutex, however this is called after
3300 * the last filedesc died, so there is no possibility
3301 * to trigger the AB-BA case.
3302 */
3303 mutex_lock_nested(&ctx->mutex, SINGLE_DEPTH_NESTING);
3304 perf_remove_from_context(event, true);
3305 mutex_unlock(&ctx->mutex);
3306
3307 free_event(event);
3308 3298
3309 return 0; 3299 _free_event(event);
3310} 3300}
3311EXPORT_SYMBOL_GPL(perf_event_release_kernel);
3312 3301
3313/* 3302/*
3314 * Called when the last reference to the file is gone. 3303 * Called when the last reference to the file is gone.
3315 */ 3304 */
3316static void put_event(struct perf_event *event) 3305static void put_event(struct perf_event *event)
3317{ 3306{
3307 struct perf_event_context *ctx = event->ctx;
3318 struct task_struct *owner; 3308 struct task_struct *owner;
3319 3309
3320 if (!atomic_long_dec_and_test(&event->refcount)) 3310 if (!atomic_long_dec_and_test(&event->refcount))
@@ -3353,9 +3343,33 @@ static void put_event(struct perf_event *event)
3353 put_task_struct(owner); 3343 put_task_struct(owner);
3354 } 3344 }
3355 3345
3356 perf_event_release_kernel(event); 3346 WARN_ON_ONCE(ctx->parent_ctx);
3347 /*
3348 * There are two ways this annotation is useful:
3349 *
3350 * 1) there is a lock recursion from perf_event_exit_task
3351 * see the comment there.
3352 *
3353 * 2) there is a lock-inversion with mmap_sem through
3354 * perf_event_read_group(), which takes faults while
3355 * holding ctx->mutex, however this is called after
3356 * the last filedesc died, so there is no possibility
3357 * to trigger the AB-BA case.
3358 */
3359 mutex_lock_nested(&ctx->mutex, SINGLE_DEPTH_NESTING);
3360 perf_remove_from_context(event, true);
3361 mutex_unlock(&ctx->mutex);
3362
3363 _free_event(event);
3357} 3364}
3358 3365
3366int perf_event_release_kernel(struct perf_event *event)
3367{
3368 put_event(event);
3369 return 0;
3370}
3371EXPORT_SYMBOL_GPL(perf_event_release_kernel);
3372
3359static int perf_release(struct inode *inode, struct file *file) 3373static int perf_release(struct inode *inode, struct file *file)
3360{ 3374{
3361 put_event(file->private_data); 3375 put_event(file->private_data);