--- x/kernel/events/core.c +++ y/kernel/events/core.c @@ -1172,7 +1172,7 @@ static void free_ctx(struct rcu_head *he static void put_ctx(struct perf_event_context *ctx) { - if (refcount_dec_and_test(&ctx->refcount)) { + if (ctx && refcount_dec_and_test(&ctx->refcount)) { if (ctx->parent_ctx) put_ctx(ctx->parent_ctx); if (ctx->task && ctx->task != TASK_TOMBSTONE) @@ -3910,6 +3910,10 @@ static void perf_event_context_sched_in( ctx = rcu_dereference(task->perf_event_ctxp); if (!ctx) goto rcu_unlock; + if (!refcount_inc_not_zero(&ctx->refcount)) { + ctx = NULL; + goto rcu_unlock; + } if (cpuctx->task_ctx == ctx) { perf_ctx_lock(cpuctx, ctx); @@ -3957,6 +3961,7 @@ unlock: perf_ctx_unlock(cpuctx, ctx); rcu_unlock: rcu_read_unlock(); + put_ctx(ctx); } /* @@ -4816,6 +4821,7 @@ find_get_pmu_context(struct pmu *pmu, st raw_spin_lock_irq(&ctx->lock); list_add(&epc->pmu_ctx_entry, &ctx->pmu_ctx_list); epc->ctx = ctx; + get_ctx(ctx); raw_spin_unlock_irq(&ctx->lock); } else { WARN_ON_ONCE(epc->ctx != ctx); @@ -4914,6 +4920,7 @@ static void put_pmu_ctx(struct perf_even list_del_init(&epc->pmu_ctx_entry); epc->ctx = NULL; raw_spin_unlock_irqrestore(&ctx->lock, flags); + put_ctx(ctx); } WARN_ON_ONCE(!list_empty(&epc->pinned_active));