Skip to content

Commit 4eabf53

Browse files
Peter ZijlstraIngo Molnar
authored andcommitted
perf/core: Detach 'struct perf_cpu_pmu_context' and 'struct pmu' lifetimes
In prepration for being able to unregister a PMU with existing events, it becomes important to detach struct perf_cpu_pmu_context lifetimes from that of struct pmu. Notably struct perf_cpu_pmu_context embeds a struct perf_event_pmu_context that can stay referenced until the last event goes. Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Signed-off-by: Ingo Molnar <[email protected]> Reviewed-by: Ravi Bangoria <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 0983593 commit 4eabf53

File tree

2 files changed

+49
-11
lines changed

2 files changed

+49
-11
lines changed

include/linux/perf_event.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ struct pmu {
343343
*/
344344
unsigned int scope;
345345

346-
struct perf_cpu_pmu_context __percpu *cpu_pmu_context;
346+
struct perf_cpu_pmu_context __percpu **cpu_pmu_context;
347347
atomic_t exclusive_cnt; /* < 0: cpu; > 0: tsk */
348348
int task_ctx_nr;
349349
int hrtimer_interval_ms;
@@ -922,7 +922,7 @@ struct perf_event_pmu_context {
922922
struct list_head pinned_active;
923923
struct list_head flexible_active;
924924

925-
/* Used to avoid freeing per-cpu perf_event_pmu_context */
925+
/* Used to identify the per-cpu perf_event_pmu_context */
926926
unsigned int embedded : 1;
927927

928928
unsigned int nr_events;

kernel/events/core.c

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,7 +1219,7 @@ static int perf_mux_hrtimer_restart_ipi(void *arg)
12191219

12201220
static __always_inline struct perf_cpu_pmu_context *this_cpc(struct pmu *pmu)
12211221
{
1222-
return this_cpu_ptr(pmu->cpu_pmu_context);
1222+
return *this_cpu_ptr(pmu->cpu_pmu_context);
12231223
}
12241224

12251225
void perf_pmu_disable(struct pmu *pmu)
@@ -5007,11 +5007,14 @@ find_get_pmu_context(struct pmu *pmu, struct perf_event_context *ctx,
50075007
*/
50085008
struct perf_cpu_pmu_context *cpc;
50095009

5010-
cpc = per_cpu_ptr(pmu->cpu_pmu_context, event->cpu);
5010+
cpc = *per_cpu_ptr(pmu->cpu_pmu_context, event->cpu);
50115011
epc = &cpc->epc;
50125012
raw_spin_lock_irq(&ctx->lock);
50135013
if (!epc->ctx) {
5014-
atomic_set(&epc->refcount, 1);
5014+
/*
5015+
* One extra reference for the pmu; see perf_pmu_free().
5016+
*/
5017+
atomic_set(&epc->refcount, 2);
50155018
epc->embedded = 1;
50165019
list_add(&epc->pmu_ctx_entry, &ctx->pmu_ctx_list);
50175020
epc->ctx = ctx;
@@ -5087,6 +5090,15 @@ static void get_pmu_ctx(struct perf_event_pmu_context *epc)
50875090
WARN_ON_ONCE(!atomic_inc_not_zero(&epc->refcount));
50885091
}
50895092

5093+
static void free_cpc_rcu(struct rcu_head *head)
5094+
{
5095+
struct perf_cpu_pmu_context *cpc =
5096+
container_of(head, typeof(*cpc), epc.rcu_head);
5097+
5098+
kfree(cpc->epc.task_ctx_data);
5099+
kfree(cpc);
5100+
}
5101+
50905102
static void free_epc_rcu(struct rcu_head *head)
50915103
{
50925104
struct perf_event_pmu_context *epc = container_of(head, typeof(*epc), rcu_head);
@@ -5121,8 +5133,10 @@ static void put_pmu_ctx(struct perf_event_pmu_context *epc)
51215133

51225134
raw_spin_unlock_irqrestore(&ctx->lock, flags);
51235135

5124-
if (epc->embedded)
5136+
if (epc->embedded) {
5137+
call_rcu(&epc->rcu_head, free_cpc_rcu);
51255138
return;
5139+
}
51265140

51275141
call_rcu(&epc->rcu_head, free_epc_rcu);
51285142
}
@@ -11752,7 +11766,7 @@ perf_event_mux_interval_ms_store(struct device *dev,
1175211766
cpus_read_lock();
1175311767
for_each_online_cpu(cpu) {
1175411768
struct perf_cpu_pmu_context *cpc;
11755-
cpc = per_cpu_ptr(pmu->cpu_pmu_context, cpu);
11769+
cpc = *per_cpu_ptr(pmu->cpu_pmu_context, cpu);
1175611770
cpc->hrtimer_interval = ns_to_ktime(NSEC_PER_MSEC * timer);
1175711771

1175811772
cpu_function_call(cpu, perf_mux_hrtimer_restart_ipi, cpc);
@@ -11925,7 +11939,25 @@ static void perf_pmu_free(struct pmu *pmu)
1192511939
device_del(pmu->dev);
1192611940
put_device(pmu->dev);
1192711941
}
11928-
free_percpu(pmu->cpu_pmu_context);
11942+
11943+
if (pmu->cpu_pmu_context) {
11944+
int cpu;
11945+
11946+
for_each_possible_cpu(cpu) {
11947+
struct perf_cpu_pmu_context *cpc;
11948+
11949+
cpc = *per_cpu_ptr(pmu->cpu_pmu_context, cpu);
11950+
if (!cpc)
11951+
continue;
11952+
if (cpc->epc.embedded) {
11953+
/* refcount managed */
11954+
put_pmu_ctx(&cpc->epc);
11955+
continue;
11956+
}
11957+
kfree(cpc);
11958+
}
11959+
free_percpu(pmu->cpu_pmu_context);
11960+
}
1192911961
}
1193011962

1193111963
DEFINE_FREE(pmu_unregister, struct pmu *, if (_T) perf_pmu_free(_T))
@@ -11964,14 +11996,20 @@ int perf_pmu_register(struct pmu *_pmu, const char *name, int type)
1196411996
return ret;
1196511997
}
1196611998

11967-
pmu->cpu_pmu_context = alloc_percpu(struct perf_cpu_pmu_context);
11999+
pmu->cpu_pmu_context = alloc_percpu(struct perf_cpu_pmu_context *);
1196812000
if (!pmu->cpu_pmu_context)
1196912001
return -ENOMEM;
1197012002

1197112003
for_each_possible_cpu(cpu) {
11972-
struct perf_cpu_pmu_context *cpc;
12004+
struct perf_cpu_pmu_context *cpc =
12005+
kmalloc_node(sizeof(struct perf_cpu_pmu_context),
12006+
GFP_KERNEL | __GFP_ZERO,
12007+
cpu_to_node(cpu));
12008+
12009+
if (!cpc)
12010+
return -ENOMEM;
1197312011

11974-
cpc = per_cpu_ptr(pmu->cpu_pmu_context, cpu);
12012+
*per_cpu_ptr(pmu->cpu_pmu_context, cpu) = cpc;
1197512013
__perf_init_event_pmu_context(&cpc->epc, pmu);
1197612014
__perf_mux_hrtimer_init(cpc, cpu);
1197712015
}

0 commit comments

Comments
 (0)