Re: [PATCH v3 3/7] perf: Simplify perf_event_free_task() wait

From: Ravi Bangoria
Date: Mon Mar 17 2025 - 02:49:31 EST


Hi Peter,

> @@ -1223,8 +1223,14 @@ static void put_ctx(struct perf_event_co
> if (refcount_dec_and_test(&ctx->refcount)) {
> if (ctx->parent_ctx)
> put_ctx(ctx->parent_ctx);
> - if (ctx->task && ctx->task != TASK_TOMBSTONE)
> - put_task_struct(ctx->task);
> + if (ctx->task) {
> + if (ctx->task == TASK_TOMBSTONE) {
> + smp_mb(); /* pairs with wait_var_event() */
> + wake_up_var(&ctx->refcount);

perf_event_free_task() waits on "ctx->refcount == 1". But moving
wake_up_var() under refcount_dec_and_test() will cause
perf_event_free_task() to wait indefinitely. Right? So, shouldn't
wake_up_var() be outside? something like:

--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -1281,15 +1281,14 @@ static void put_ctx(struct perf_event_context *ctx)
if (refcount_dec_and_test(&ctx->refcount)) {
if (ctx->parent_ctx)
put_ctx(ctx->parent_ctx);
- if (ctx->task) {
- if (ctx->task == TASK_TOMBSTONE) {
- smp_mb(); /* pairs with wait_var_event() */
- wake_up_var(&ctx->refcount);
- } else {
- put_task_struct(ctx->task);
- }
- }
+ if (ctx->task && ctx->task != TASK_TOMBSTONE)
+ put_task_struct(ctx->task);
call_rcu(&ctx->rcu_head, free_ctx);
+ } else {
+ if (ctx->task == TASK_TOMBSTONE) {
+ smp_mb(); /* pairs with wait_var_event() */
+ wake_up_var(&ctx->refcount);
+ }
}
}

Thanks,
Ravi