From nobody Sun Feb 8 16:12:04 2026 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2D5D51FF602; Mon, 3 Mar 2025 12:29:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741004974; cv=none; b=JOMDuBKGED9rnGI9NZqApzNCUnSTLgydtJDXSLf4ostolCnp/EzVPJA45q3hIt0NXykeAfgtVp9VYw4cdtiwvqSnswxDUAKS2Zf+x7Aq4NtP9KLM6OtoMbIg0l1Jm1Q18t+W7SqIdXr7psPjuE6ao8zz2RudOv+4dkL++opdWF4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741004974; c=relaxed/simple; bh=29vKuSxFvBiNucjPfut9HKw36PNpgECcDRigNDSu8rQ=; h=Date:From:To:Subject:Cc:In-Reply-To:References:MIME-Version: Message-ID:Content-Type; b=Ij702eqzXDKJFmkkC1gkB29lkXM/RVR9jZoDxOXEslWsG4VOemHmEZsbEJMQlODrjvTsxD/DaP4xE3smG8Pg0SbqQ6SADPB2zXaKhdbgmimx6yL0rwKKwQMzpxMO47PzcCfZLFL37goghlqw8e5giLaFKtPoLuuKR9zHU0hl3UU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=31CVwZAa; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=oLzq2OcF; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="31CVwZAa"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="oLzq2OcF" Date: Mon, 03 Mar 2025 12:29:30 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1741004971; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Jrf4aZqmcHUA7SyBAF6oygLynG7+fZqWMGqGUVEioQk=; b=31CVwZAadzUUiRBbJor2mPkNmXFtG5W/V+ogUjUIbLzU63/GAry9BohJWL2NnBJNkzymYn ajuYvcBUd7pUyyxu1YNo0GELGPxtwWW/BDHv8/OWG3JKAtb0Uce8vv6fSS2Mxyd3Q+I0Ng u31ido2yQU9x6Lo4DoH4YPxwzSjQ9wxlh1ZkqgvhcgnO4OuMhS/mF1D5mfJFGaoF1N4WEc rgSAldNfC578ygZWX34soYdGusjuW0rfRIIipfBk3TFSm3lt4dwTghu25heOOnefBctEH9 vzQYTwARN3bwWv4CFFS791RzR6wZAr2f6DPTkoo5+pVNrAfLDSOAFUxRtaWIOQ== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1741004971; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Jrf4aZqmcHUA7SyBAF6oygLynG7+fZqWMGqGUVEioQk=; b=oLzq2OcFbIR4QeDhk5djILidvkPNxywbrVMuX4Mevr/PdFH2bhNb7ij5PGqFENK3d6/yLv a7H+ME130KIj2zAA== From: "tip-bot2 for Peter Zijlstra" Sender: tip-bot2@linutronix.de Reply-to: linux-kernel@vger.kernel.org To: linux-tip-commits@vger.kernel.org Subject: [tip: perf/core] perf/core: Detach 'struct perf_cpu_pmu_context' and 'struct pmu' lifetimes Cc: "Peter Zijlstra (Intel)" , Ingo Molnar , x86@kernel.org, linux-kernel@vger.kernel.org In-Reply-To: <20241104135518.760214287@infradead.org> References: <20241104135518.760214287@infradead.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-ID: <174100497060.10177.13409371343847213450.tip-bot2@tip-bot2> Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails Precedence: bulk Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable The following commit has been merged into the perf/core branch of tip: Commit-ID: f67d1ffd841f31bc4a1314bc7f0a973ba77f39a5 Gitweb: https://git.kernel.org/tip/f67d1ffd841f31bc4a1314bc7f0a973ba= 77f39a5 Author: Peter Zijlstra AuthorDate: Mon, 04 Nov 2024 14:39:20 +01:00 Committer: Ingo Molnar CommitterDate: Mon, 03 Mar 2025 13:24:12 +01:00 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) Signed-off-by: Ingo Molnar Link: https://lore.kernel.org/r/20241104135518.760214287@infradead.org --- include/linux/perf_event.h | 4 +-- kernel/events/core.c | 56 +++++++++++++++++++++++++++++++------ 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 5f293e6..76f4265 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -343,7 +343,7 @@ struct pmu { */ unsigned int scope; =20 - struct perf_cpu_pmu_context __percpu *cpu_pmu_context; + struct perf_cpu_pmu_context __percpu **cpu_pmu_context; atomic_t exclusive_cnt; /* < 0: cpu; > 0: tsk */ int task_ctx_nr; int hrtimer_interval_ms; @@ -922,7 +922,7 @@ struct perf_event_pmu_context { struct list_head pinned_active; struct list_head flexible_active; =20 - /* Used to avoid freeing per-cpu perf_event_pmu_context */ + /* Used to identify the per-cpu perf_event_pmu_context */ unsigned int embedded : 1; =20 unsigned int nr_events; diff --git a/kernel/events/core.c b/kernel/events/core.c index 773875a..8b2a8c3 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -1219,7 +1219,7 @@ static int perf_mux_hrtimer_restart_ipi(void *arg) =20 static __always_inline struct perf_cpu_pmu_context *this_cpc(struct pmu *p= mu) { - return this_cpu_ptr(pmu->cpu_pmu_context); + return *this_cpu_ptr(pmu->cpu_pmu_context); } =20 void perf_pmu_disable(struct pmu *pmu) @@ -5007,11 +5007,14 @@ find_get_pmu_context(struct pmu *pmu, struct perf_e= vent_context *ctx, */ struct perf_cpu_pmu_context *cpc; =20 - cpc =3D per_cpu_ptr(pmu->cpu_pmu_context, event->cpu); + cpc =3D *per_cpu_ptr(pmu->cpu_pmu_context, event->cpu); epc =3D &cpc->epc; raw_spin_lock_irq(&ctx->lock); if (!epc->ctx) { - atomic_set(&epc->refcount, 1); + /* + * One extra reference for the pmu; see perf_pmu_free(). + */ + atomic_set(&epc->refcount, 2); epc->embedded =3D 1; list_add(&epc->pmu_ctx_entry, &ctx->pmu_ctx_list); epc->ctx =3D ctx; @@ -5087,6 +5090,15 @@ static void get_pmu_ctx(struct perf_event_pmu_contex= t *epc) WARN_ON_ONCE(!atomic_inc_not_zero(&epc->refcount)); } =20 +static void free_cpc_rcu(struct rcu_head *head) +{ + struct perf_cpu_pmu_context *cpc =3D + container_of(head, typeof(*cpc), epc.rcu_head); + + kfree(cpc->epc.task_ctx_data); + kfree(cpc); +} + static void free_epc_rcu(struct rcu_head *head) { struct perf_event_pmu_context *epc =3D container_of(head, typeof(*epc), r= cu_head); @@ -5121,8 +5133,10 @@ static void put_pmu_ctx(struct perf_event_pmu_contex= t *epc) =20 raw_spin_unlock_irqrestore(&ctx->lock, flags); =20 - if (epc->embedded) + if (epc->embedded) { + call_rcu(&epc->rcu_head, free_cpc_rcu); return; + } =20 call_rcu(&epc->rcu_head, free_epc_rcu); } @@ -11752,7 +11766,7 @@ perf_event_mux_interval_ms_store(struct device *dev, cpus_read_lock(); for_each_online_cpu(cpu) { struct perf_cpu_pmu_context *cpc; - cpc =3D per_cpu_ptr(pmu->cpu_pmu_context, cpu); + cpc =3D *per_cpu_ptr(pmu->cpu_pmu_context, cpu); cpc->hrtimer_interval =3D ns_to_ktime(NSEC_PER_MSEC * timer); =20 cpu_function_call(cpu, perf_mux_hrtimer_restart_ipi, cpc); @@ -11925,7 +11939,25 @@ static void perf_pmu_free(struct pmu *pmu) device_del(pmu->dev); put_device(pmu->dev); } - free_percpu(pmu->cpu_pmu_context); + + if (pmu->cpu_pmu_context) { + int cpu; + + for_each_possible_cpu(cpu) { + struct perf_cpu_pmu_context *cpc; + + cpc =3D *per_cpu_ptr(pmu->cpu_pmu_context, cpu); + if (!cpc) + continue; + if (cpc->epc.embedded) { + /* refcount managed */ + put_pmu_ctx(&cpc->epc); + continue; + } + kfree(cpc); + } + free_percpu(pmu->cpu_pmu_context); + } } =20 DEFINE_FREE(pmu_unregister, struct pmu *, if (_T) perf_pmu_free(_T)) @@ -11964,14 +11996,20 @@ int perf_pmu_register(struct pmu *_pmu, const cha= r *name, int type) return ret; } =20 - pmu->cpu_pmu_context =3D alloc_percpu(struct perf_cpu_pmu_context); + pmu->cpu_pmu_context =3D alloc_percpu(struct perf_cpu_pmu_context *); if (!pmu->cpu_pmu_context) return -ENOMEM; =20 for_each_possible_cpu(cpu) { - struct perf_cpu_pmu_context *cpc; + struct perf_cpu_pmu_context *cpc =3D + kmalloc_node(sizeof(struct perf_cpu_pmu_context), + GFP_KERNEL | __GFP_ZERO, + cpu_to_node(cpu)); + + if (!cpc) + return -ENOMEM; =20 - cpc =3D per_cpu_ptr(pmu->cpu_pmu_context, cpu); + *per_cpu_ptr(pmu->cpu_pmu_context, cpu) =3D cpc; __perf_init_event_pmu_context(&cpc->epc, pmu); __perf_mux_hrtimer_init(cpc, cpu); }