aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/events/core.c49
1 files changed, 32 insertions, 17 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c
index f548f69c4299..39679f749500 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -8297,13 +8297,30 @@ SYSCALL_DEFINE5(perf_event_open,
8297 8297
8298 if (move_group) { 8298 if (move_group) {
8299 gctx = group_leader->ctx; 8299 gctx = group_leader->ctx;
8300 mutex_lock_double(&gctx->mutex, &ctx->mutex);
8301 } else {
8302 mutex_lock(&ctx->mutex);
8303 }
8304
8305 /*
8306 * Must be under the same ctx::mutex as perf_install_in_context(),
8307 * because we need to serialize with concurrent event creation.
8308 */
8309 if (!exclusive_event_installable(event, ctx)) {
8310 /* exclusive and group stuff are assumed mutually exclusive */
8311 WARN_ON_ONCE(move_group);
8312
8313 err = -EBUSY;
8314 goto err_locked;
8315 }
8300 8316
8317 WARN_ON_ONCE(ctx->parent_ctx);
8318
8319 if (move_group) {
8301 /* 8320 /*
8302 * See perf_event_ctx_lock() for comments on the details 8321 * See perf_event_ctx_lock() for comments on the details
8303 * of swizzling perf_event::ctx. 8322 * of swizzling perf_event::ctx.
8304 */ 8323 */
8305 mutex_lock_double(&gctx->mutex, &ctx->mutex);
8306
8307 perf_remove_from_context(group_leader, false); 8324 perf_remove_from_context(group_leader, false);
8308 8325
8309 list_for_each_entry(sibling, &group_leader->sibling_list, 8326 list_for_each_entry(sibling, &group_leader->sibling_list,
@@ -8311,13 +8328,7 @@ SYSCALL_DEFINE5(perf_event_open,
8311 perf_remove_from_context(sibling, false); 8328 perf_remove_from_context(sibling, false);
8312 put_ctx(gctx); 8329 put_ctx(gctx);
8313 } 8330 }
8314 } else {
8315 mutex_lock(&ctx->mutex);
8316 }
8317
8318 WARN_ON_ONCE(ctx->parent_ctx);
8319 8331
8320 if (move_group) {
8321 /* 8332 /*
8322 * Wait for everybody to stop referencing the events through 8333 * Wait for everybody to stop referencing the events through
8323 * the old lists, before installing it on new lists. 8334 * the old lists, before installing it on new lists.
@@ -8349,22 +8360,20 @@ SYSCALL_DEFINE5(perf_event_open,
8349 perf_event__state_init(group_leader); 8360 perf_event__state_init(group_leader);
8350 perf_install_in_context(ctx, group_leader, group_leader->cpu); 8361 perf_install_in_context(ctx, group_leader, group_leader->cpu);
8351 get_ctx(ctx); 8362 get_ctx(ctx);
8352 }
8353 8363
8354 if (!exclusive_event_installable(event, ctx)) { 8364 /*
8355 err = -EBUSY; 8365 * Now that all events are installed in @ctx, nothing
8356 mutex_unlock(&ctx->mutex); 8366 * references @gctx anymore, so drop the last reference we have
8357 fput(event_file); 8367 * on it.
8358 goto err_context; 8368 */
8369 put_ctx(gctx);
8359 } 8370 }
8360 8371
8361 perf_install_in_context(ctx, event, event->cpu); 8372 perf_install_in_context(ctx, event, event->cpu);
8362 perf_unpin_context(ctx); 8373 perf_unpin_context(ctx);
8363 8374
8364 if (move_group) { 8375 if (move_group)
8365 mutex_unlock(&gctx->mutex); 8376 mutex_unlock(&gctx->mutex);
8366 put_ctx(gctx);
8367 }
8368 mutex_unlock(&ctx->mutex); 8377 mutex_unlock(&ctx->mutex);
8369 8378
8370 put_online_cpus(); 8379 put_online_cpus();
@@ -8391,6 +8400,12 @@ SYSCALL_DEFINE5(perf_event_open,
8391 fd_install(event_fd, event_file); 8400 fd_install(event_fd, event_file);
8392 return event_fd; 8401 return event_fd;
8393 8402
8403err_locked:
8404 if (move_group)
8405 mutex_unlock(&gctx->mutex);
8406 mutex_unlock(&ctx->mutex);
8407/* err_file: */
8408 fput(event_file);
8394err_context: 8409err_context:
8395 perf_unpin_context(ctx); 8410 perf_unpin_context(ctx);
8396 put_ctx(ctx); 8411 put_ctx(ctx);