From nobody Fri Dec 19 20:32:33 2025 Received: from out-189.mta1.migadu.com (out-189.mta1.migadu.com [95.215.58.189]) (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 A3DB92882AD for ; Wed, 14 May 2025 18:42:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.189 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747248144; cv=none; b=pbTAxuB57yWFb7+lqagK/CekFmXimyvLnyqMJ0BQj10BAdOekzRndFycf0ek2liPkdgKUjQwE34MGULu8n61P+/fCBnLmgA3x0GITfBvhtuUFRTKZOnbX+FN6q3njAPdyyocB54yBZfo2AjxevitsE+ZDUIP+nkIGoVP4xP/wbk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747248144; c=relaxed/simple; bh=3Fr0cQ+G90nKuUSZg94me3gC2Oyt2UO3Hef1WWjs74U=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=bz/sJnw7RY74a1msRCDFvW2q6mqCpIZO6sGfRe8HkDzmGtv3ETrhM3eK4hYCdBS/ezcCblbCL/nWw/O/I3cQFUus18+XJQjpmja3GDgwssBEnC3criZPDn0s9snZTQ2UzUSSqkqQXAcqj5FhffwQx93jpvAc3KkJhMiAAr2cYIk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=L9zMuLin; arc=none smtp.client-ip=95.215.58.189 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="L9zMuLin" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1747248139; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=I1JZROuIroIvEzIUKiaMX+NW2Feg9mUr1VdRm7ju+Rc=; b=L9zMuLin+KdSVhzEN0SGMJKsSLDXu2kWmM+sbQ2yv1PrTje8O/eF0Gy1pQg2iugldzHZ+T M7psiGTwbuAYe7PTX0V1VJcEOxef1/R4hP0pUoImfGXbfRl58KPC0yIkyYMzoNlqhdjxFf e8EZzcrUZShSAZ0loYLOk0N7rzBcYl8= From: Shakeel Butt To: Andrew Morton Cc: Johannes Weiner , Michal Hocko , Roman Gushchin , Muchun Song , Vlastimil Babka , Alexei Starovoitov , Sebastian Andrzej Siewior , Harry Yoo , Yosry Ahmed , bpf@vger.kernel.org, linux-mm@kvack.org, cgroups@vger.kernel.org, linux-kernel@vger.kernel.org, Meta kernel team Subject: [PATCH v2 1/7] memcg: memcg_rstat_updated re-entrant safe against irqs Date: Wed, 14 May 2025 11:41:52 -0700 Message-ID: <20250514184158.3471331-2-shakeel.butt@linux.dev> In-Reply-To: <20250514184158.3471331-1-shakeel.butt@linux.dev> References: <20250514184158.3471331-1-shakeel.butt@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" The function memcg_rstat_updated() is used to track the memcg stats updates for optimizing the flushes. At the moment, it is not re-entrant safe and the callers disabled irqs before calling. However to achieve the goal of updating memcg stats without irqs, memcg_rstat_updated() needs to be re-entrant safe against irqs. This patch makes memcg_rstat_updated() re-entrant safe using this_cpu_* ops. On archs with CONFIG_ARCH_HAS_NMI_SAFE_THIS_CPU_OPS, this patch is also making memcg_rstat_updated() nmi safe. Signed-off-by: Shakeel Butt Reviewed-by: Vlastimil Babka Tested-by: Alexei Starovoitov --- mm/memcontrol.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 89476a71a18d..2464a58fbf17 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -505,8 +505,8 @@ struct memcg_vmstats_percpu { unsigned int stats_updates; =20 /* Cached pointers for fast iteration in memcg_rstat_updated() */ - struct memcg_vmstats_percpu *parent; - struct memcg_vmstats *vmstats; + struct memcg_vmstats_percpu __percpu *parent_pcpu; + struct memcg_vmstats *vmstats; =20 /* The above should fit a single cacheline for memcg_rstat_updated() */ =20 @@ -588,16 +588,21 @@ static bool memcg_vmstats_needs_flush(struct memcg_vm= stats *vmstats) =20 static inline void memcg_rstat_updated(struct mem_cgroup *memcg, int val) { + struct memcg_vmstats_percpu __percpu *statc_pcpu; struct memcg_vmstats_percpu *statc; - int cpu =3D smp_processor_id(); + int cpu; unsigned int stats_updates; =20 if (!val) return; =20 + /* Don't assume callers have preemption disabled. */ + cpu =3D get_cpu(); + cgroup_rstat_updated(memcg->css.cgroup, cpu); - statc =3D this_cpu_ptr(memcg->vmstats_percpu); - for (; statc; statc =3D statc->parent) { + statc_pcpu =3D memcg->vmstats_percpu; + for (; statc_pcpu; statc_pcpu =3D statc->parent_pcpu) { + statc =3D this_cpu_ptr(statc_pcpu); /* * If @memcg is already flushable then all its ancestors are * flushable as well and also there is no need to increase @@ -606,14 +611,15 @@ static inline void memcg_rstat_updated(struct mem_cgr= oup *memcg, int val) if (memcg_vmstats_needs_flush(statc->vmstats)) break; =20 - stats_updates =3D READ_ONCE(statc->stats_updates) + abs(val); - WRITE_ONCE(statc->stats_updates, stats_updates); + stats_updates =3D this_cpu_add_return(statc_pcpu->stats_updates, + abs(val)); if (stats_updates < MEMCG_CHARGE_BATCH) continue; =20 + stats_updates =3D this_cpu_xchg(statc_pcpu->stats_updates, 0); atomic64_add(stats_updates, &statc->vmstats->stats_updates); - WRITE_ONCE(statc->stats_updates, 0); } + put_cpu(); } =20 static void __mem_cgroup_flush_stats(struct mem_cgroup *memcg, bool force) @@ -3691,7 +3697,7 @@ static void mem_cgroup_free(struct mem_cgroup *memcg) =20 static struct mem_cgroup *mem_cgroup_alloc(struct mem_cgroup *parent) { - struct memcg_vmstats_percpu *statc, *pstatc; + struct memcg_vmstats_percpu *statc, __percpu *pstatc_pcpu; struct mem_cgroup *memcg; int node, cpu; int __maybe_unused i; @@ -3722,9 +3728,9 @@ static struct mem_cgroup *mem_cgroup_alloc(struct mem= _cgroup *parent) =20 for_each_possible_cpu(cpu) { if (parent) - pstatc =3D per_cpu_ptr(parent->vmstats_percpu, cpu); + pstatc_pcpu =3D parent->vmstats_percpu; statc =3D per_cpu_ptr(memcg->vmstats_percpu, cpu); - statc->parent =3D parent ? pstatc : NULL; + statc->parent_pcpu =3D parent ? pstatc_pcpu : NULL; statc->vmstats =3D memcg->vmstats; } =20 --=20 2.47.1