Skip to content

Commit 940b01f

Browse files
shakeelbakpm00
authored andcommitted
memcg: nmi safe memcg stats for specific archs
There are archs which have NMI but does not support this_cpu_* ops safely in the nmi context but they support safe atomic ops in nmi context. For such archs, let's add infra to use atomic ops for the memcg stats which can be updated in nmi. At the moment, the memcg stats which get updated in the objcg charging path are MEMCG_KMEM, NR_SLAB_RECLAIMABLE_B & NR_SLAB_UNRECLAIMABLE_B. Rather than adding support for all memcg stats to be nmi safe, let's just add infra to make these three stats nmi safe which this patch is doing. Link: https://lkml.kernel.org/r/20250519063142.111219-3-shakeel.butt@linux.dev Signed-off-by: Shakeel Butt <shakeel.butt@linux.dev> Acked-by: Vlastimil Babka <vbabka@suse.cz> Cc: Alexei Starovoitov <ast@kernel.org> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Cc: Michal Hocko <mhocko@kernel.org> Cc: Muchun Song <muchun.song@linux.dev> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Roman Gushchin <roman.gushchin@linux.dev> Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Cc: Tejun Heo <tj@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent 25352d2 commit 940b01f

3 files changed

Lines changed: 66 additions & 0 deletions

File tree

include/linux/memcontrol.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,12 @@ struct mem_cgroup_per_node {
113113
CACHELINE_PADDING(_pad2_);
114114
unsigned long lru_zone_size[MAX_NR_ZONES][NR_LRU_LISTS];
115115
struct mem_cgroup_reclaim_iter iter;
116+
117+
#ifdef CONFIG_MEMCG_NMI_SAFETY_REQUIRES_ATOMIC
118+
/* slab stats for nmi context */
119+
atomic_t slab_reclaimable;
120+
atomic_t slab_unreclaimable;
121+
#endif
116122
};
117123

118124
struct mem_cgroup_threshold {
@@ -236,6 +242,10 @@ struct mem_cgroup {
236242
atomic_long_t memory_events[MEMCG_NR_MEMORY_EVENTS];
237243
atomic_long_t memory_events_local[MEMCG_NR_MEMORY_EVENTS];
238244

245+
#ifdef CONFIG_MEMCG_NMI_SAFETY_REQUIRES_ATOMIC
246+
/* MEMCG_KMEM for nmi context */
247+
atomic_t kmem_stat;
248+
#endif
239249
/*
240250
* Hint of reclaim pressure for socket memroy management. Note
241251
* that this indicator should NOT be used in legacy cgroup mode

init/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,13 @@ config MEMCG_NMI_UNSAFE
10131013
depends on !ARCH_HAS_NMI_SAFE_THIS_CPU_OPS && !ARCH_HAVE_NMI_SAFE_CMPXCHG
10141014
default y
10151015

1016+
config MEMCG_NMI_SAFETY_REQUIRES_ATOMIC
1017+
bool
1018+
depends on MEMCG
1019+
depends on HAVE_NMI
1020+
depends on !ARCH_HAS_NMI_SAFE_THIS_CPU_OPS && ARCH_HAVE_NMI_SAFE_CMPXCHG
1021+
default y
1022+
10161023
config MEMCG_V1
10171024
bool "Legacy cgroup v1 memory controller"
10181025
depends on MEMCG

mm/memcontrol.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3966,6 +3966,53 @@ static void mem_cgroup_stat_aggregate(struct aggregate_control *ac)
39663966
}
39673967
}
39683968

3969+
#ifdef CONFIG_MEMCG_NMI_SAFETY_REQUIRES_ATOMIC
3970+
static void flush_nmi_stats(struct mem_cgroup *memcg, struct mem_cgroup *parent,
3971+
int cpu)
3972+
{
3973+
int nid;
3974+
3975+
if (atomic_read(&memcg->kmem_stat)) {
3976+
int kmem = atomic_xchg(&memcg->kmem_stat, 0);
3977+
int index = memcg_stats_index(MEMCG_KMEM);
3978+
3979+
memcg->vmstats->state[index] += kmem;
3980+
if (parent)
3981+
parent->vmstats->state_pending[index] += kmem;
3982+
}
3983+
3984+
for_each_node_state(nid, N_MEMORY) {
3985+
struct mem_cgroup_per_node *pn = memcg->nodeinfo[nid];
3986+
struct lruvec_stats *lstats = pn->lruvec_stats;
3987+
struct lruvec_stats *plstats = NULL;
3988+
3989+
if (parent)
3990+
plstats = parent->nodeinfo[nid]->lruvec_stats;
3991+
3992+
if (atomic_read(&pn->slab_reclaimable)) {
3993+
int slab = atomic_xchg(&pn->slab_reclaimable, 0);
3994+
int index = memcg_stats_index(NR_SLAB_RECLAIMABLE_B);
3995+
3996+
lstats->state[index] += slab;
3997+
if (plstats)
3998+
plstats->state_pending[index] += slab;
3999+
}
4000+
if (atomic_read(&pn->slab_unreclaimable)) {
4001+
int slab = atomic_xchg(&pn->slab_unreclaimable, 0);
4002+
int index = memcg_stats_index(NR_SLAB_UNRECLAIMABLE_B);
4003+
4004+
lstats->state[index] += slab;
4005+
if (plstats)
4006+
plstats->state_pending[index] += slab;
4007+
}
4008+
}
4009+
}
4010+
#else
4011+
static void flush_nmi_stats(struct mem_cgroup *memcg, struct mem_cgroup *parent,
4012+
int cpu)
4013+
{}
4014+
#endif
4015+
39694016
static void mem_cgroup_css_rstat_flush(struct cgroup_subsys_state *css, int cpu)
39704017
{
39714018
struct mem_cgroup *memcg = mem_cgroup_from_css(css);
@@ -3974,6 +4021,8 @@ static void mem_cgroup_css_rstat_flush(struct cgroup_subsys_state *css, int cpu)
39744021
struct aggregate_control ac;
39754022
int nid;
39764023

4024+
flush_nmi_stats(memcg, parent, cpu);
4025+
39774026
statc = per_cpu_ptr(memcg->vmstats_percpu, cpu);
39784027

39794028
ac = (struct aggregate_control) {

0 commit comments

Comments
 (0)