mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [RFC PATCH 0/3] mm, memcg: isolate deprecated v1 state from struct mem_cgroup
@ 2026-09-16 12:57 Tao Cui
  2026-09-16 12:57 ` [PATCH 1/3] mm, memcg: introduce struct mem_cgroup_v1 Tao Cui
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Tao Cui @ 2026-09-16 12:57 UTC (permalink / raw)
  To: hannes, mhocko
  Cc: roman.gushchin, shakeel.butt, muchun.song, cgroups, linux-mm,
	linux-kernel, cui.tao, Tao Cui

From: Tao Cui <cuitao@kylinos.cn>

The legacy cgroup v1 memory controller has already been moved out of
the shared implementation at the file level (mm/memcontrol-v1.c) and at
the Kconfig level (CONFIG_MEMCG_V1, default n since 6.11).  Its
per-cgroup state, however, still sits as individual members inside
struct mem_cgroup, guarded by #ifdefs.

This series isolates the deprecated implementation from the shared hot
structure: all v1-only members are grouped into a dedicated
struct mem_cgroup_v1, and every access goes through memcg->v1.X.

With this in place the v1 implementation is self-contained: its
interface in mm/memcontrol-v1.c, its state in struct mem_cgroup_v1, and
its eventual removal becomes a localized deletion of this struct
together with mm/memcontrol-v1.c, instead of unwinding
ifdef-scattered members across the shared header.

Patch 1 introduces the substruct behind a transitional union whose
anonymous side preserves the historical layout, so the patch is
semantically empty.  Patch 2 converts the access sites and drops the
anonymous side.  Patch 3 documents the boundary.

This demonstrates one possible pattern for isolating deprecated cgroup
v1 implementation from shared structures.

As a validation detail, this does not regress the layout: the member
order is preserved, so offsetof(struct mem_cgroup, v1.swappiness) and
sizeof(struct mem_cgroup) are unchanged (verified with pahole), and the
generated code of hot paths such as mem_cgroup_swappiness() is
identical.  Build-tested with CONFIG_MEMCG_V1 both enabled and
disabled, and boot-tested with both a v1 and a v2 hierarchy.

Tao Cui (3):
  mm, memcg: introduce struct mem_cgroup_v1
  mm, memcg: move v1-only members into mem_cgroup_v1
  docs: cgroup-v1: note the v1 memory controller implementation boundary

 .../admin-guide/cgroup-v1/memory.rst          |   7 +
 include/linux/memcontrol.h                    |  74 +++++------
 include/net/sock.h                            |   2 +-
 mm/memcontrol-v1.c                            | 122 +++++++++---------
 mm/memcontrol-v1.h                            |   4 +-
 mm/memcontrol.c                               |  22 ++--
 mm/swap.h                                     |   2 +-
 7 files changed, 121 insertions(+), 112 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/3] mm, memcg: introduce struct mem_cgroup_v1
  2026-09-16 12:57 [RFC PATCH 0/3] mm, memcg: isolate deprecated v1 state from struct mem_cgroup Tao Cui
@ 2026-09-16 12:57 ` Tao Cui
  2026-09-16 12:57 ` [PATCH 2/3] mm, memcg: move v1-only members into mem_cgroup_v1 Tao Cui
  2026-09-16 12:57 ` [PATCH 3/3] docs: cgroup-v1: note the v1 memory controller implementation boundary Tao Cui
  2 siblings, 0 replies; 4+ messages in thread
From: Tao Cui @ 2026-09-16 12:57 UTC (permalink / raw)
  To: hannes, mhocko
  Cc: roman.gushchin, shakeel.butt, muchun.song, cgroups, linux-mm,
	linux-kernel, cui.tao, Tao Cui

From: Tao Cui <cuitao@kylinos.cn>

The legacy cgroup v1 memory controller keeps its state as individual
members guarded by CONFIG_MEMCG_V1 inside struct mem_cgroup.  While the
v1 implementation already lives in mm/memcontrol-v1.c and its interface
is behind CONFIG_MEMCG_V1, its data is still intermixed with the shared
layout of struct mem_cgroup.

Group the v1-only members into a dedicated struct mem_cgroup_v1 and
embed it via a union whose anonymous side reproduces the historical
layout.  All existing memcg->X accesses keep compiling and the binary
layout is unchanged.  The anonymous side is dropped by the next patch
once the access sites are converted.

No functional change.

Signed-off-by: Tao Cui <cuitao@kylinos.cn>
---
 include/linux/memcontrol.h | 97 ++++++++++++++++++++++++++++----------
 1 file changed, 71 insertions(+), 26 deletions(-)

diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 46bf724cae7a..beb68f39c321 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -193,6 +193,43 @@ struct obj_cgroup {
  * statistics based on the statistics developed by Rik Van Riel for clock-pro,
  * to help the administrator determine what knobs to tune.
  */
+/*
+ * Legacy cgroup v1 memory controller state, used only by the v1
+ * interface (mm/memcontrol-v1.c).
+ */
+struct mem_cgroup_v1 {
+	struct page_counter kmem;
+	struct page_counter tcpmem;
+
+	struct memcg1_events_percpu __percpu *events_percpu;
+
+	/* protected by memcg_oom_lock */
+	bool oom_lock;
+	int under_oom;
+
+	int oom_kill_disable;
+
+	struct mutex thresholds_lock;
+
+	/* RCU-protected */
+	struct mem_cgroup_thresholds thresholds;
+
+	/* RCU-protected */
+	struct mem_cgroup_thresholds memsw_thresholds;
+
+	/* For oom notifier event fd */
+	struct list_head oom_notify;
+
+	bool tcpmem_active;
+	int tcpmem_pressure;
+
+	/* List of events which userspace want to receive */
+	struct list_head event_list;
+	spinlock_t event_list_lock;
+
+	int swappiness;
+};
+
 struct mem_cgroup {
 	struct cgroup_subsys_state css;
 
@@ -271,42 +308,50 @@ struct mem_cgroup {
 	__cacheline_group_end_aligned(memcg_cold);
 
 #ifdef CONFIG_MEMCG_V1
-	/* v1 only. Not grouped: v1 is legacy, sorting it is not worth it. */
+	/*
+	 * Transitional: the anonymous struct reproduces the historical layout
+	 * so existing memcg->X accesses keep compiling; it is removed once the
+	 * access sites are converted to memcg->v1.X.
+	 */
+	union {
+		struct mem_cgroup_v1 v1;
+		struct {
+			/* Legacy consumer-oriented counters */
+			struct page_counter kmem;		/* v1 only */
+			struct page_counter tcpmem;		/* v1 only */
 
-	/* Legacy consumer-oriented counters */
-	struct page_counter kmem;		/* v1 only */
-	struct page_counter tcpmem;		/* v1 only */
+			struct memcg1_events_percpu __percpu *events_percpu;
 
-	struct memcg1_events_percpu __percpu *events_percpu;
+			/* protected by memcg_oom_lock */
+			bool oom_lock;
+			int under_oom;
 
-	/* protected by memcg_oom_lock */
-	bool oom_lock;
-	int under_oom;
+			/* OOM-Killer disable */
+			int oom_kill_disable;
 
-	/* OOM-Killer disable */
-	int oom_kill_disable;
+			/* protect arrays of thresholds */
+			struct mutex thresholds_lock;
 
-	/* protect arrays of thresholds */
-	struct mutex thresholds_lock;
+			/* thresholds for memory usage. RCU-protected */
+			struct mem_cgroup_thresholds thresholds;
 
-	/* thresholds for memory usage. RCU-protected */
-	struct mem_cgroup_thresholds thresholds;
-
-	/* thresholds for mem+swap usage. RCU-protected */
-	struct mem_cgroup_thresholds memsw_thresholds;
+			/* thresholds for mem+swap usage. RCU-protected */
+			struct mem_cgroup_thresholds memsw_thresholds;
 
-	/* For oom notifier event fd */
-	struct list_head oom_notify;
+			/* For oom notifier event fd */
+			struct list_head oom_notify;
 
-	/* Legacy tcp memory accounting */
-	bool tcpmem_active;
-	int tcpmem_pressure;
+			/* Legacy tcp memory accounting */
+			bool tcpmem_active;
+			int tcpmem_pressure;
 
-	/* List of events which userspace want to receive */
-	struct list_head event_list;
-	spinlock_t event_list_lock;
+			/* List of events which userspace want to receive */
+			struct list_head event_list;
+			spinlock_t event_list_lock;
 
-	int swappiness;
+			int swappiness;
+		};
+	};
 #endif /* CONFIG_MEMCG_V1 */
 
 	/*
-- 
2.43.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 2/3] mm, memcg: move v1-only members into mem_cgroup_v1
  2026-09-16 12:57 [RFC PATCH 0/3] mm, memcg: isolate deprecated v1 state from struct mem_cgroup Tao Cui
  2026-09-16 12:57 ` [PATCH 1/3] mm, memcg: introduce struct mem_cgroup_v1 Tao Cui
@ 2026-09-16 12:57 ` Tao Cui
  2026-09-16 12:57 ` [PATCH 3/3] docs: cgroup-v1: note the v1 memory controller implementation boundary Tao Cui
  2 siblings, 0 replies; 4+ messages in thread
From: Tao Cui @ 2026-09-16 12:57 UTC (permalink / raw)
  To: hannes, mhocko
  Cc: roman.gushchin, shakeel.butt, muchun.song, cgroups, linux-mm,
	linux-kernel, cui.tao, Tao Cui

From: Tao Cui <cuitao@kylinos.cn>

Convert all access sites of the v1-only members to go through the new
mem_cgroup_v1 substruct (memcg->v1.X) and drop the transitional
anonymous union side introduced by the previous patch.

The member order inside struct mem_cgroup_v1 is identical to the
historical order of these members inside struct mem_cgroup, so the
shared layout does not change: offsetof(struct mem_cgroup, v1.swappiness)
and the total size of struct mem_cgroup are unchanged, and the generated
code in the hot paths (e.g. mem_cgroup_swappiness) is the same.

No functional change.

Signed-off-by: Tao Cui <cuitao@kylinos.cn>
---
 include/linux/memcontrol.h |  45 +-------------
 include/net/sock.h         |   2 +-
 mm/memcontrol-v1.c         | 122 ++++++++++++++++++-------------------
 mm/memcontrol-v1.h         |   4 +-
 mm/memcontrol.c            |  22 +++----
 mm/swap.h                  |   2 +-
 6 files changed, 77 insertions(+), 120 deletions(-)

diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index beb68f39c321..4c113a260878 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -308,50 +308,7 @@ struct mem_cgroup {
 	__cacheline_group_end_aligned(memcg_cold);
 
 #ifdef CONFIG_MEMCG_V1
-	/*
-	 * Transitional: the anonymous struct reproduces the historical layout
-	 * so existing memcg->X accesses keep compiling; it is removed once the
-	 * access sites are converted to memcg->v1.X.
-	 */
-	union {
-		struct mem_cgroup_v1 v1;
-		struct {
-			/* Legacy consumer-oriented counters */
-			struct page_counter kmem;		/* v1 only */
-			struct page_counter tcpmem;		/* v1 only */
-
-			struct memcg1_events_percpu __percpu *events_percpu;
-
-			/* protected by memcg_oom_lock */
-			bool oom_lock;
-			int under_oom;
-
-			/* OOM-Killer disable */
-			int oom_kill_disable;
-
-			/* protect arrays of thresholds */
-			struct mutex thresholds_lock;
-
-			/* thresholds for memory usage. RCU-protected */
-			struct mem_cgroup_thresholds thresholds;
-
-			/* thresholds for mem+swap usage. RCU-protected */
-			struct mem_cgroup_thresholds memsw_thresholds;
-
-			/* For oom notifier event fd */
-			struct list_head oom_notify;
-
-			/* Legacy tcp memory accounting */
-			bool tcpmem_active;
-			int tcpmem_pressure;
-
-			/* List of events which userspace want to receive */
-			struct list_head event_list;
-			spinlock_t event_list_lock;
-
-			int swappiness;
-		};
-	};
+	struct mem_cgroup_v1 v1;
 #endif /* CONFIG_MEMCG_V1 */
 
 	/*
diff --git a/include/net/sock.h b/include/net/sock.h
index 67b743bab220..c3f6775f6942 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -2707,7 +2707,7 @@ static inline bool mem_cgroup_sk_under_memory_pressure(const struct sock *sk)
 
 #ifdef CONFIG_MEMCG_V1
 	if (!cgroup_subsys_on_dfl(memory_cgrp_subsys))
-		return !!memcg->tcpmem_pressure;
+		return !!memcg->v1.tcpmem_pressure;
 #endif /* CONFIG_MEMCG_V1 */
 
 	do {
diff --git a/mm/memcontrol-v1.c b/mm/memcontrol-v1.c
index bf2c7d53b01b..486df2d6a6f1 100644
--- a/mm/memcontrol-v1.c
+++ b/mm/memcontrol-v1.c
@@ -138,9 +138,9 @@ static void __mem_cgroup_threshold(struct mem_cgroup *memcg, bool swap)
 
 	rcu_read_lock();
 	if (!swap)
-		t = rcu_dereference(memcg->thresholds.primary);
+		t = rcu_dereference(memcg->v1.thresholds.primary);
 	else
-		t = rcu_dereference(memcg->memsw_thresholds.primary);
+		t = rcu_dereference(memcg->v1.memsw_thresholds.primary);
 
 	if (!t)
 		goto unlock;
@@ -215,7 +215,7 @@ static void memcg1_charge_statistics(struct mem_cgroup *memcg, int nr_pages)
 		nr_pages = -nr_pages; /* for event */
 	}
 
-	__this_cpu_add(memcg->events_percpu->nr_page_events, nr_pages);
+	__this_cpu_add(memcg->v1.events_percpu->nr_page_events, nr_pages);
 }
 
 #define THRESHOLDS_EVENTS_TARGET 128
@@ -224,11 +224,11 @@ static bool memcg1_event_ratelimit(struct mem_cgroup *memcg)
 {
 	unsigned long val, next;
 
-	val = __this_cpu_read(memcg->events_percpu->nr_page_events);
-	next = __this_cpu_read(memcg->events_percpu->threshold_target);
+	val = __this_cpu_read(memcg->v1.events_percpu->nr_page_events);
+	next = __this_cpu_read(memcg->v1.events_percpu->threshold_target);
 	/* from time_after() in jiffies.h */
 	if ((long)(next - val) < 0) {
-		__this_cpu_write(memcg->events_percpu->threshold_target,
+		__this_cpu_write(memcg->v1.events_percpu->threshold_target,
 				 val + THRESHOLDS_EVENTS_TARGET);
 		return true;
 	}
@@ -383,7 +383,7 @@ void memcg1_uncharge_batch(struct mem_cgroup *memcg, unsigned long pgpgout,
 
 	local_irq_save(flags);
 	count_memcg_events(memcg, PGPGOUT, pgpgout);
-	__this_cpu_add(memcg->events_percpu->nr_page_events, nr_memory);
+	__this_cpu_add(memcg->v1.events_percpu->nr_page_events, nr_memory);
 	memcg1_check_events(memcg);
 	local_irq_restore(flags);
 }
@@ -408,7 +408,7 @@ static void mem_cgroup_oom_notify_cb(struct mem_cgroup *memcg)
 
 	spin_lock(&memcg_oom_lock);
 
-	list_for_each_entry(ev, &memcg->oom_notify, list)
+	list_for_each_entry(ev, &memcg->v1.oom_notify, list)
 		eventfd_signal(ev->eventfd);
 
 	spin_unlock(&memcg_oom_lock);
@@ -435,13 +435,13 @@ static int __mem_cgroup_usage_register_event(struct mem_cgroup *memcg,
 	if (ret)
 		return ret;
 
-	mutex_lock(&memcg->thresholds_lock);
+	mutex_lock(&memcg->v1.thresholds_lock);
 
 	if (type == _MEM) {
-		thresholds = &memcg->thresholds;
+		thresholds = &memcg->v1.thresholds;
 		usage = mem_cgroup_usage(memcg, false);
 	} else if (type == _MEMSWAP) {
-		thresholds = &memcg->memsw_thresholds;
+		thresholds = &memcg->v1.memsw_thresholds;
 		usage = mem_cgroup_usage(memcg, true);
 	} else
 		BUG();
@@ -497,7 +497,7 @@ static int __mem_cgroup_usage_register_event(struct mem_cgroup *memcg,
 	synchronize_rcu();
 
 unlock:
-	mutex_unlock(&memcg->thresholds_lock);
+	mutex_unlock(&memcg->v1.thresholds_lock);
 
 	return ret;
 }
@@ -522,13 +522,13 @@ static void __mem_cgroup_usage_unregister_event(struct mem_cgroup *memcg,
 	unsigned long usage;
 	int i, j, size, entries;
 
-	mutex_lock(&memcg->thresholds_lock);
+	mutex_lock(&memcg->v1.thresholds_lock);
 
 	if (type == _MEM) {
-		thresholds = &memcg->thresholds;
+		thresholds = &memcg->v1.thresholds;
 		usage = mem_cgroup_usage(memcg, false);
 	} else if (type == _MEMSWAP) {
-		thresholds = &memcg->memsw_thresholds;
+		thresholds = &memcg->v1.memsw_thresholds;
 		usage = mem_cgroup_usage(memcg, true);
 	} else
 		BUG();
@@ -596,7 +596,7 @@ static void __mem_cgroup_usage_unregister_event(struct mem_cgroup *memcg,
 		thresholds->spare = NULL;
 	}
 unlock:
-	mutex_unlock(&memcg->thresholds_lock);
+	mutex_unlock(&memcg->v1.thresholds_lock);
 }
 
 static void mem_cgroup_usage_unregister_event(struct mem_cgroup *memcg,
@@ -623,10 +623,10 @@ static int mem_cgroup_oom_register_event(struct mem_cgroup *memcg,
 	spin_lock(&memcg_oom_lock);
 
 	event->eventfd = eventfd;
-	list_add(&event->list, &memcg->oom_notify);
+	list_add(&event->list, &memcg->v1.oom_notify);
 
 	/* already in OOM ? */
-	if (memcg->under_oom)
+	if (memcg->v1.under_oom)
 		eventfd_signal(eventfd);
 	spin_unlock(&memcg_oom_lock);
 
@@ -640,7 +640,7 @@ static void mem_cgroup_oom_unregister_event(struct mem_cgroup *memcg,
 
 	spin_lock(&memcg_oom_lock);
 
-	list_for_each_entry_safe(ev, tmp, &memcg->oom_notify, list) {
+	list_for_each_entry_safe(ev, tmp, &memcg->v1.oom_notify, list) {
 		if (ev->eventfd == eventfd) {
 			list_del(&ev->list);
 			kfree(ev);
@@ -709,7 +709,7 @@ static int memcg_event_wake(wait_queue_entry_t *wait, unsigned int mode,
 		 * side will require wqh->lock via remove_wait_queue(),
 		 * which we hold.
 		 */
-		spin_lock(&memcg->event_list_lock);
+		spin_lock(&memcg->v1.event_list_lock);
 		if (!list_empty(&event->list)) {
 			list_del_init(&event->list);
 			/*
@@ -718,7 +718,7 @@ static int memcg_event_wake(wait_queue_entry_t *wait, unsigned int mode,
 			 */
 			schedule_work(&event->remove);
 		}
-		spin_unlock(&memcg->event_list_lock);
+		spin_unlock(&memcg->v1.event_list_lock);
 	}
 
 	return 0;
@@ -868,9 +868,9 @@ static ssize_t memcg_write_event_control(struct kernfs_open_file *of,
 
 	vfs_poll(fd_file(efile), &event->pt);
 
-	spin_lock_irq(&memcg->event_list_lock);
-	list_add(&event->list, &memcg->event_list);
-	spin_unlock_irq(&memcg->event_list_lock);
+	spin_lock_irq(&memcg->v1.event_list_lock);
+	list_add(&event->list, &memcg->v1.event_list);
+	spin_unlock_irq(&memcg->v1.event_list_lock);
 	return nbytes;
 
 out_put_css:
@@ -884,10 +884,10 @@ static ssize_t memcg_write_event_control(struct kernfs_open_file *of,
 
 void memcg1_memcg_init(struct mem_cgroup *memcg)
 {
-	INIT_LIST_HEAD(&memcg->oom_notify);
-	mutex_init(&memcg->thresholds_lock);
-	INIT_LIST_HEAD(&memcg->event_list);
-	spin_lock_init(&memcg->event_list_lock);
+	INIT_LIST_HEAD(&memcg->v1.oom_notify);
+	mutex_init(&memcg->v1.thresholds_lock);
+	INIT_LIST_HEAD(&memcg->v1.event_list);
+	spin_lock_init(&memcg->v1.event_list_lock);
 }
 
 void memcg1_css_offline(struct mem_cgroup *memcg)
@@ -899,12 +899,12 @@ void memcg1_css_offline(struct mem_cgroup *memcg)
 	 * Notify userspace about cgroup removing only after rmdir of cgroup
 	 * directory to avoid race between userspace and kernelspace.
 	 */
-	spin_lock_irq(&memcg->event_list_lock);
-	list_for_each_entry_safe(event, tmp, &memcg->event_list, list) {
+	spin_lock_irq(&memcg->v1.event_list_lock);
+	list_for_each_entry_safe(event, tmp, &memcg->v1.event_list, list) {
 		list_del_init(&event->list);
 		schedule_work(&event->remove);
 	}
-	spin_unlock_irq(&memcg->event_list_lock);
+	spin_unlock_irq(&memcg->v1.event_list_lock);
 }
 
 /*
@@ -918,7 +918,7 @@ static bool mem_cgroup_oom_trylock(struct mem_cgroup *memcg)
 	spin_lock(&memcg_oom_lock);
 
 	for_each_mem_cgroup_tree(iter, memcg) {
-		if (iter->oom_lock) {
+		if (iter->v1.oom_lock) {
 			/*
 			 * this subtree of our hierarchy is already locked
 			 * so we cannot give a lock.
@@ -927,7 +927,7 @@ static bool mem_cgroup_oom_trylock(struct mem_cgroup *memcg)
 			mem_cgroup_iter_break(memcg, iter);
 			break;
 		}
-		iter->oom_lock = true;
+		iter->v1.oom_lock = true;
 	}
 
 	if (failed) {
@@ -940,7 +940,7 @@ static bool mem_cgroup_oom_trylock(struct mem_cgroup *memcg)
 				mem_cgroup_iter_break(memcg, iter);
 				break;
 			}
-			iter->oom_lock = false;
+			iter->v1.oom_lock = false;
 		}
 	} else
 		mutex_acquire(&memcg_oom_lock_dep_map, 0, 1, _RET_IP_);
@@ -957,7 +957,7 @@ static void mem_cgroup_oom_unlock(struct mem_cgroup *memcg)
 	spin_lock(&memcg_oom_lock);
 	mutex_release(&memcg_oom_lock_dep_map, _RET_IP_);
 	for_each_mem_cgroup_tree(iter, memcg)
-		iter->oom_lock = false;
+		iter->v1.oom_lock = false;
 	spin_unlock(&memcg_oom_lock);
 }
 
@@ -967,7 +967,7 @@ static void mem_cgroup_mark_under_oom(struct mem_cgroup *memcg)
 
 	spin_lock(&memcg_oom_lock);
 	for_each_mem_cgroup_tree(iter, memcg)
-		iter->under_oom++;
+		iter->v1.under_oom++;
 	spin_unlock(&memcg_oom_lock);
 }
 
@@ -981,8 +981,8 @@ static void mem_cgroup_unmark_under_oom(struct mem_cgroup *memcg)
 	 */
 	spin_lock(&memcg_oom_lock);
 	for_each_mem_cgroup_tree(iter, memcg)
-		if (iter->under_oom > 0)
-			iter->under_oom--;
+		if (iter->v1.under_oom > 0)
+			iter->v1.under_oom--;
 	spin_unlock(&memcg_oom_lock);
 }
 
@@ -1012,14 +1012,14 @@ static int memcg_oom_wake_function(wait_queue_entry_t *wait,
 void memcg1_oom_recover(struct mem_cgroup *memcg)
 {
 	/*
-	 * For the following lockless ->under_oom test, the only required
+	 * For the following lockless ->v1.under_oom test, the only required
 	 * guarantee is that it must see the state asserted by an OOM when
 	 * this function is called as a result of userland actions
 	 * triggered by the notification of the OOM.  This is trivially
 	 * achieved by invoking mem_cgroup_mark_under_oom() before
 	 * triggering notification.
 	 */
-	if (memcg && memcg->under_oom)
+	if (memcg && memcg->v1.under_oom)
 		__wake_up(&memcg_oom_waitq, TASK_NORMAL, 0, memcg);
 }
 
@@ -1100,7 +1100,7 @@ bool memcg1_oom_prepare(struct mem_cgroup *memcg, bool *locked)
 	 * Please note that mem_cgroup_out_of_memory might fail to find a
 	 * victim and then we have to bail out from the charge path.
 	 */
-	if (READ_ONCE(memcg->oom_kill_disable)) {
+	if (READ_ONCE(memcg->v1.oom_kill_disable)) {
 		if (current->in_user_fault) {
 			css_get(&memcg->css);
 			current->memcg_in_oom = memcg;
@@ -1576,10 +1576,10 @@ static u64 mem_cgroup_read_u64(struct cgroup_subsys_state *css,
 		counter = &memcg->memsw;
 		break;
 	case _KMEM:
-		counter = &memcg->kmem;
+		counter = &memcg->v1.kmem;
 		break;
 	case _TCP:
-		counter = &memcg->tcpmem;
+		counter = &memcg->v1.tcpmem;
 		break;
 	default:
 		BUG();
@@ -1619,11 +1619,11 @@ static int memcg_update_tcp_max(struct mem_cgroup *memcg, unsigned long max)
 
 	mutex_lock(&memcg_max_mutex);
 
-	ret = page_counter_set_max(&memcg->tcpmem, max);
+	ret = page_counter_set_max(&memcg->v1.tcpmem, max);
 	if (ret)
 		goto out;
 
-	if (!memcg->tcpmem_active) {
+	if (!memcg->v1.tcpmem_active) {
 		/*
 		 * The active flag needs to be written after the static_key
 		 * update. This is what guarantees that the socket activation
@@ -1641,7 +1641,7 @@ static int memcg_update_tcp_max(struct mem_cgroup *memcg, unsigned long max)
 		 * patched in yet.
 		 */
 		static_branch_inc(&memcg_sockets_enabled_key);
-		memcg->tcpmem_active = true;
+		memcg->v1.tcpmem_active = true;
 	}
 out:
 	mutex_unlock(&memcg_max_mutex);
@@ -1710,10 +1710,10 @@ static ssize_t mem_cgroup_reset(struct kernfs_open_file *of, char *buf,
 		counter = &memcg->memsw;
 		break;
 	case _KMEM:
-		counter = &memcg->kmem;
+		counter = &memcg->v1.kmem;
 		break;
 	case _TCP:
-		counter = &memcg->tcpmem;
+		counter = &memcg->v1.tcpmem;
 		break;
 	default:
 		BUG();
@@ -1976,7 +1976,7 @@ static int mem_cgroup_swappiness_write(struct cgroup_subsys_state *css,
 	if (!mem_cgroup_is_root(memcg)) {
 		pr_info_once("Per memcg swappiness does not exist in cgroup v2. "
 			     "See memory.reclaim or memory.swap.max there\n ");
-		WRITE_ONCE(memcg->swappiness, val);
+		WRITE_ONCE(memcg->v1.swappiness, val);
 	} else
 		WRITE_ONCE(vm_swappiness, val);
 
@@ -1987,8 +1987,8 @@ static int mem_cgroup_oom_control_read(struct seq_file *sf, void *v)
 {
 	struct mem_cgroup *memcg = mem_cgroup_from_seq(sf);
 
-	seq_printf(sf, "oom_kill_disable %d\n", READ_ONCE(memcg->oom_kill_disable));
-	seq_printf(sf, "under_oom %d\n", (bool)memcg->under_oom);
+	seq_printf(sf, "oom_kill_disable %d\n", READ_ONCE(memcg->v1.oom_kill_disable));
+	seq_printf(sf, "under_oom %d\n", (bool)memcg->v1.under_oom);
 	seq_printf(sf, "oom_kill %lu\n",
 		   atomic_long_read(&memcg->memory_events[MEMCG_OOM_KILL]));
 	return 0;
@@ -2007,7 +2007,7 @@ static int mem_cgroup_oom_control_write(struct cgroup_subsys_state *css,
 	if (mem_cgroup_is_root(memcg) || !((val == 0) || (val == 1)))
 		return -EINVAL;
 
-	WRITE_ONCE(memcg->oom_kill_disable, val);
+	WRITE_ONCE(memcg->v1.oom_kill_disable, val);
 	if (!val)
 		memcg1_oom_recover(memcg);
 
@@ -2183,9 +2183,9 @@ void memcg1_account_kmem(struct mem_cgroup *memcg, int nr_pages)
 {
 	if (!cgroup_subsys_on_dfl(memory_cgrp_subsys)) {
 		if (nr_pages > 0)
-			page_counter_charge(&memcg->kmem, nr_pages);
+			page_counter_charge(&memcg->v1.kmem, nr_pages);
 		else
-			page_counter_uncharge(&memcg->kmem, -nr_pages);
+			page_counter_uncharge(&memcg->v1.kmem, -nr_pages);
 	}
 }
 
@@ -2194,13 +2194,13 @@ bool memcg1_charge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages,
 {
 	struct page_counter *fail;
 
-	if (page_counter_try_charge(&memcg->tcpmem, nr_pages, &fail)) {
-		memcg->tcpmem_pressure = 0;
+	if (page_counter_try_charge(&memcg->v1.tcpmem, nr_pages, &fail)) {
+		memcg->v1.tcpmem_pressure = 0;
 		return true;
 	}
-	memcg->tcpmem_pressure = 1;
+	memcg->v1.tcpmem_pressure = 1;
 	if (gfp_mask & __GFP_NOFAIL) {
-		page_counter_charge(&memcg->tcpmem, nr_pages);
+		page_counter_charge(&memcg->v1.tcpmem, nr_pages);
 		return true;
 	}
 	return false;
@@ -2208,12 +2208,12 @@ bool memcg1_charge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages,
 
 bool memcg1_alloc_events(struct mem_cgroup *memcg)
 {
-	memcg->events_percpu = alloc_percpu_gfp(struct memcg1_events_percpu,
+	memcg->v1.events_percpu = alloc_percpu_gfp(struct memcg1_events_percpu,
 						GFP_KERNEL_ACCOUNT);
-	return !!memcg->events_percpu;
+	return !!memcg->v1.events_percpu;
 }
 
 void memcg1_free_events(struct mem_cgroup *memcg)
 {
-	free_percpu(memcg->events_percpu);
+	free_percpu(memcg->v1.events_percpu);
 }
diff --git a/mm/memcontrol-v1.h b/mm/memcontrol-v1.h
index b9a21f0fd2c3..5a71a7aae099 100644
--- a/mm/memcontrol-v1.h
+++ b/mm/memcontrol-v1.h
@@ -73,13 +73,13 @@ void reparent_memcg_lruvec_state_local(struct mem_cgroup *memcg,
 void memcg1_account_kmem(struct mem_cgroup *memcg, int nr_pages);
 static inline bool memcg1_tcpmem_active(struct mem_cgroup *memcg)
 {
-	return memcg->tcpmem_active;
+	return memcg->v1.tcpmem_active;
 }
 bool memcg1_charge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages,
 			 gfp_t gfp_mask);
 static inline void memcg1_uncharge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages)
 {
-	page_counter_uncharge(&memcg->tcpmem, nr_pages);
+	page_counter_uncharge(&memcg->v1.tcpmem, nr_pages);
 }
 
 extern struct cftype memsw_files[];
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 1460cba53588..d68d497c8fce 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -1867,8 +1867,8 @@ void mem_cgroup_print_oom_meminfo(struct mem_cgroup *memcg)
 			K((u64)page_counter_read(&memcg->memsw)),
 			K((u64)memcg->memsw.max), memcg->memsw.failcnt);
 		pr_info("kmem: usage %llukB, limit %llukB, failcnt %lu\n",
-			K((u64)page_counter_read(&memcg->kmem)),
-			K((u64)memcg->kmem.max), memcg->kmem.failcnt);
+			K((u64)page_counter_read(&memcg->v1.kmem)),
+			K((u64)memcg->v1.kmem.max), memcg->v1.kmem.failcnt);
 	}
 #endif
 
@@ -4285,13 +4285,13 @@ mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
 		page_counter_init(&memcg->memory, &parent->memory, memcg_on_dfl);
 		page_counter_init(&memcg->swap, &parent->swap, false);
 #ifdef CONFIG_MEMCG_V1
-		WRITE_ONCE(memcg->swappiness, mem_cgroup_swappiness(parent));
+		WRITE_ONCE(memcg->v1.swappiness, mem_cgroup_swappiness(parent));
 		memcg->memory.track_failcnt = !memcg_on_dfl;
 		memcg->memsw.track_failcnt = !memcg_on_dfl;
-		WRITE_ONCE(memcg->oom_kill_disable, READ_ONCE(parent->oom_kill_disable));
-		page_counter_init(&memcg->kmem, &parent->kmem, false);
-		page_counter_init(&memcg->tcpmem, &parent->tcpmem, false);
-		memcg->tcpmem.track_failcnt = !memcg_on_dfl;
+		WRITE_ONCE(memcg->v1.oom_kill_disable, READ_ONCE(parent->v1.oom_kill_disable));
+		page_counter_init(&memcg->v1.kmem, &parent->v1.kmem, false);
+		page_counter_init(&memcg->v1.tcpmem, &parent->v1.tcpmem, false);
+		memcg->v1.tcpmem.track_failcnt = !memcg_on_dfl;
 #endif
 	} else {
 		init_memcg_stats();
@@ -4299,8 +4299,8 @@ mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
 		page_counter_init(&memcg->memory, NULL, true);
 		page_counter_init(&memcg->swap, NULL, false);
 #ifdef CONFIG_MEMCG_V1
-		page_counter_init(&memcg->kmem, NULL, false);
-		page_counter_init(&memcg->tcpmem, NULL, false);
+		page_counter_init(&memcg->v1.kmem, NULL, false);
+		page_counter_init(&memcg->v1.tcpmem, NULL, false);
 #endif
 		root_mem_cgroup = memcg;
 		return &memcg->css;
@@ -4477,8 +4477,8 @@ static void mem_cgroup_css_reset(struct cgroup_subsys_state *css)
 	WRITE_ONCE(memcg->zswap_writeback, true);
 #endif
 #ifdef CONFIG_MEMCG_V1
-	page_counter_set_max(&memcg->kmem, PAGE_COUNTER_MAX);
-	page_counter_set_max(&memcg->tcpmem, PAGE_COUNTER_MAX);
+	page_counter_set_max(&memcg->v1.kmem, PAGE_COUNTER_MAX);
+	page_counter_set_max(&memcg->v1.tcpmem, PAGE_COUNTER_MAX);
 #endif
 	page_counter_set_min(&memcg->memory, 0);
 	page_counter_set_low(&memcg->memory, 0);
diff --git a/mm/swap.h b/mm/swap.h
index b3b54c28929a..d8f306c5152b 100644
--- a/mm/swap.h
+++ b/mm/swap.h
@@ -87,7 +87,7 @@ static inline int mem_cgroup_swappiness(struct mem_cgroup *memcg)
 #ifdef CONFIG_MEMCG_V1
 	if (!cgroup_subsys_on_dfl(memory_cgrp_subsys) &&
 	    !mem_cgroup_disabled() && !mem_cgroup_is_root(memcg))
-		return READ_ONCE(memcg->swappiness);
+		return READ_ONCE(memcg->v1.swappiness);
 #endif
 	return READ_ONCE(vm_swappiness);
 }
-- 
2.43.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 3/3] docs: cgroup-v1: note the v1 memory controller implementation boundary
  2026-09-16 12:57 [RFC PATCH 0/3] mm, memcg: isolate deprecated v1 state from struct mem_cgroup Tao Cui
  2026-09-16 12:57 ` [PATCH 1/3] mm, memcg: introduce struct mem_cgroup_v1 Tao Cui
  2026-09-16 12:57 ` [PATCH 2/3] mm, memcg: move v1-only members into mem_cgroup_v1 Tao Cui
@ 2026-09-16 12:57 ` Tao Cui
  2 siblings, 0 replies; 4+ messages in thread
From: Tao Cui @ 2026-09-16 12:57 UTC (permalink / raw)
  To: hannes, mhocko
  Cc: roman.gushchin, shakeel.butt, muchun.song, cgroups, linux-mm,
	linux-kernel, cui.tao, Tao Cui

From: Tao Cui <cuitao@kylinos.cn>

Document that the legacy memory controller is now isolated behind
CONFIG_MEMCG_V1, with its state in struct mem_cgroup_v1, and that new
functionality belongs to the v2 memory controller.

Signed-off-by: Tao Cui <cuitao@kylinos.cn>
---
 Documentation/admin-guide/cgroup-v1/memory.rst | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/Documentation/admin-guide/cgroup-v1/memory.rst b/Documentation/admin-guide/cgroup-v1/memory.rst
index 7d2a44af52c9..2eff1dc6e13b 100644
--- a/Documentation/admin-guide/cgroup-v1/memory.rst
+++ b/Documentation/admin-guide/cgroup-v1/memory.rst
@@ -8,6 +8,13 @@ Memory Resource Controller
       here but make sure to check the current code if you need a deeper
       understanding.
 
+.. note::
+      The legacy (v1) memory controller implementation is isolated behind
+      ``CONFIG_MEMCG_V1``: its interface lives in ``mm/memcontrol-v1.c`` and
+      its per-cgroup state in ``struct mem_cgroup_v1`` (see
+      ``include/linux/memcontrol.h``).  New functionality belongs to the
+      cgroup v2 memory controller.
+
 .. note::
       The Memory Resource Controller has generically been referred to as the
       memory controller in this document. Do not confuse memory controller
-- 
2.43.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-09-16 12:58 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-16 12:57 [RFC PATCH 0/3] mm, memcg: isolate deprecated v1 state from struct mem_cgroup Tao Cui
2026-09-16 12:57 ` [PATCH 1/3] mm, memcg: introduce struct mem_cgroup_v1 Tao Cui
2026-09-16 12:57 ` [PATCH 2/3] mm, memcg: move v1-only members into mem_cgroup_v1 Tao Cui
2026-09-16 12:57 ` [PATCH 3/3] docs: cgroup-v1: note the v1 memory controller implementation boundary Tao Cui

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®