perf: Restructure perf syscall point of no return
The exclusive_event_installable() stuff only works because its exclusive with the grouping bits. Rework the code such that there is a sane place to error out before we go do things we cannot undo. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
parent
dfe1f3cb31
commit
f55fc2a57c
|
@ -8297,13 +8297,30 @@ SYSCALL_DEFINE5(perf_event_open,
|
|||
|
||||
if (move_group) {
|
||||
gctx = group_leader->ctx;
|
||||
mutex_lock_double(&gctx->mutex, &ctx->mutex);
|
||||
} else {
|
||||
mutex_lock(&ctx->mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be under the same ctx::mutex as perf_install_in_context(),
|
||||
* because we need to serialize with concurrent event creation.
|
||||
*/
|
||||
if (!exclusive_event_installable(event, ctx)) {
|
||||
/* exclusive and group stuff are assumed mutually exclusive */
|
||||
WARN_ON_ONCE(move_group);
|
||||
|
||||
err = -EBUSY;
|
||||
goto err_locked;
|
||||
}
|
||||
|
||||
WARN_ON_ONCE(ctx->parent_ctx);
|
||||
|
||||
if (move_group) {
|
||||
/*
|
||||
* See perf_event_ctx_lock() for comments on the details
|
||||
* of swizzling perf_event::ctx.
|
||||
*/
|
||||
mutex_lock_double(&gctx->mutex, &ctx->mutex);
|
||||
|
||||
perf_remove_from_context(group_leader, false);
|
||||
|
||||
list_for_each_entry(sibling, &group_leader->sibling_list,
|
||||
|
@ -8311,13 +8328,7 @@ SYSCALL_DEFINE5(perf_event_open,
|
|||
perf_remove_from_context(sibling, false);
|
||||
put_ctx(gctx);
|
||||
}
|
||||
} else {
|
||||
mutex_lock(&ctx->mutex);
|
||||
}
|
||||
|
||||
WARN_ON_ONCE(ctx->parent_ctx);
|
||||
|
||||
if (move_group) {
|
||||
/*
|
||||
* Wait for everybody to stop referencing the events through
|
||||
* the old lists, before installing it on new lists.
|
||||
|
@ -8349,22 +8360,20 @@ SYSCALL_DEFINE5(perf_event_open,
|
|||
perf_event__state_init(group_leader);
|
||||
perf_install_in_context(ctx, group_leader, group_leader->cpu);
|
||||
get_ctx(ctx);
|
||||
}
|
||||
|
||||
if (!exclusive_event_installable(event, ctx)) {
|
||||
err = -EBUSY;
|
||||
mutex_unlock(&ctx->mutex);
|
||||
fput(event_file);
|
||||
goto err_context;
|
||||
/*
|
||||
* Now that all events are installed in @ctx, nothing
|
||||
* references @gctx anymore, so drop the last reference we have
|
||||
* on it.
|
||||
*/
|
||||
put_ctx(gctx);
|
||||
}
|
||||
|
||||
perf_install_in_context(ctx, event, event->cpu);
|
||||
perf_unpin_context(ctx);
|
||||
|
||||
if (move_group) {
|
||||
if (move_group)
|
||||
mutex_unlock(&gctx->mutex);
|
||||
put_ctx(gctx);
|
||||
}
|
||||
mutex_unlock(&ctx->mutex);
|
||||
|
||||
put_online_cpus();
|
||||
|
@ -8391,6 +8400,12 @@ SYSCALL_DEFINE5(perf_event_open,
|
|||
fd_install(event_fd, event_file);
|
||||
return event_fd;
|
||||
|
||||
err_locked:
|
||||
if (move_group)
|
||||
mutex_unlock(&gctx->mutex);
|
||||
mutex_unlock(&ctx->mutex);
|
||||
/* err_file: */
|
||||
fput(event_file);
|
||||
err_context:
|
||||
perf_unpin_context(ctx);
|
||||
put_ctx(ctx);
|
||||
|
|
Loading…
Reference in New Issue