* [merged mm-stable] memcg-move-memcg-private-id-refcount-to-objcg.patch removed from -mm tree
@ 2026-10-24 8:57 Andrew Morton
0 siblings, 0 replies; only message in thread
From: Andrew Morton @ 2026-10-24 8:57 UTC (permalink / raw)
To: mm-commits, yuanchu, weixugc, shakeel.butt, roman.gushchin,
qi.zheng, muchun.song, mhocko, ljs, kasong, hannes, david, david,
bfguo, baohua, axelrasmussen, bingfangguo, akpm
The quilt patch titled
Subject: memcg: move memcg private ID refcount to objcg
has been removed from the -mm tree. Its filename was
memcg-move-memcg-private-id-refcount-to-objcg.patch
This patch was dropped because it was merged into the mm-stable branch
of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
------------------------------------------------------
From: Bingfang Guo <bingfangguo@tencent.com>
Subject: memcg: move memcg private ID refcount to objcg
Date: Mon, 21 Sep 2026 14:16:27 +0800
The memcg private ID is used by objects that can't afford storing a whole
pointer and can outlive memcgs to track the memcg (notably swap entries).
The current design holds a refcount to the css, preventing the memcg from
being freed.
This patch unbinds the lifetime of memcgid from the memcg so it can be
freed. The idea is to move the refcount of memcgid to one of the memcg's
objcg. The objcg is stored in the global memcgid xarray instead and used
for retrieving the online memcg from it. So swapped out pages no longer
pin the dying memcg.
After the change, a memcgid can refer to a non present memcg. To handle
this situation, when trying to get the original memcg from the id, compare
the memcgid passed in with that of the memcg, and return NULL to indicate
its death if they differ. NULL checks are added for list_lru_walk_node(),
workingset_test_recent() to skip dead memcgs. For MGLRU recency test,
mem_cgroup_lruvec() will substitute NULL with root_mem_cgroup.
In the earlier patch, an extra xarray lookup was introduced in swap
uncharging path. Now that we have the objcg pointer in the function, the
extra overhead can be removed by using it for putting directly.
Link: https://lore.kernel.org/20260921-bingfangguo-memcgid-rework-v2-4-6c0637dc0edb@tencent.com
Signed-off-by: Bingfang Guo <bingfangguo@tencent.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: Muchun Song <muchun.song@linux.dev>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Shakeel Butt <shakeel.butt@linux.dev>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Qi Zheng <qi.zheng@linux.dev>
Cc: Kairui Song <kasong@tencent.com>
Cc: Barry Song <baohua@kernel.org>
Cc: Axel Rasmussen <axelrasmussen@google.com>
Cc: Yuanchu Xie <yuanchu@google.com>
Cc: Wei Xu <weixugc@google.com>
Cc: David Hildenbrand <david@kernel.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: Bingfang Guo <bfguo@icloud.com>
---
include/linux/memcontrol.h | 7 +--
mm/list_lru.c | 2
mm/memcontrol.c | 73 +++++++++++++++++++++++++----------
mm/workingset.c | 2
4 files changed, 60 insertions(+), 24 deletions(-)
--- a/include/linux/memcontrol.h~memcg-move-memcg-private-id-refcount-to-objcg
+++ a/include/linux/memcontrol.h
@@ -180,6 +180,7 @@ struct obj_cgroup {
struct percpu_ref refcnt;
struct mem_cgroup *memcg;
atomic_t nr_charged_bytes;
+ refcount_t private_id_ref;
union {
struct list_head list; /* protected by objcg_lock */
struct rcu_head rcu;
@@ -225,9 +226,6 @@ struct mem_cgroup {
/* vmpressure notifications. Written on every reclaim iteration. */
struct vmpressure vmpressure;
- /* Written on every swap charge and uncharge. */
- refcount_t private_id_ref;
-
#ifdef CONFIG_MEMCG_NMI_SAFETY_REQUIRES_ATOMIC
/* MEMCG_KMEM for nmi context */
atomic_t kmem_stat;
@@ -324,6 +322,9 @@ struct mem_cgroup {
unsigned long zswap_max;
#endif
+ /* The objcg holding private memcg ID. */
+ struct obj_cgroup *private_id_objcg;
+
/* Private memcg ID. Used to ID objects that outlive the cgroup */
int private_id;
--- a/mm/list_lru.c~memcg-move-memcg-private-id-refcount-to-objcg
+++ a/mm/list_lru.c
@@ -428,7 +428,7 @@ unsigned long list_lru_walk_node(struct
xa_for_each(&lru->xa, index, mlru) {
rcu_read_lock();
memcg = mem_cgroup_from_private_id(index);
- if (!mem_cgroup_tryget(memcg)) {
+ if (!memcg || !mem_cgroup_tryget(memcg)) {
rcu_read_unlock();
continue;
}
--- a/mm/memcontrol.c~memcg-move-memcg-private-id-refcount-to-objcg
+++ a/mm/memcontrol.c
@@ -4074,6 +4074,13 @@ static void memcg_wb_domain_size_changed
#define MEM_CGROUP_ID_MAX ((1UL << MEM_CGROUP_ID_SHIFT) - 1)
static DEFINE_XARRAY_ALLOC1(mem_cgroup_private_ids);
+static inline struct obj_cgroup *obj_cgroup_from_private_id(unsigned short id)
+{
+ lockdep_assert_once(rcu_read_lock_held());
+
+ return xa_load(&mem_cgroup_private_ids, id);
+}
+
static void mem_cgroup_private_id_remove(struct mem_cgroup *memcg)
{
if (memcg->private_id > 0) {
@@ -4082,34 +4089,44 @@ static void mem_cgroup_private_id_remove
}
}
-static void __mem_cgroup_private_id_put(struct mem_cgroup *memcg, unsigned int n)
+static void __mem_cgroup_private_id_put(struct obj_cgroup *objcg,
+ unsigned short id, unsigned int n)
{
- if (refcount_sub_and_test(n, &memcg->private_id_ref)) {
- mem_cgroup_private_id_remove(memcg);
+ struct obj_cgroup *objcg_free;
- /* Memcg ID pins CSS */
- css_put(&memcg->css);
+ if (refcount_sub_and_test(n, &objcg->private_id_ref)) {
+ objcg_free = xa_erase(&mem_cgroup_private_ids, id);
+ VM_WARN_ON(objcg_free != objcg);
+
+ /* Memcg ID pins the objcg */
+ obj_cgroup_put(objcg);
}
}
static inline void mem_cgroup_private_id_put(unsigned short id, unsigned int n)
{
- struct mem_cgroup *memcg;
+ struct obj_cgroup *objcg;
lockdep_assert_in_rcu_read_lock();
- memcg = mem_cgroup_from_private_id(id);
- __mem_cgroup_private_id_put(memcg, n);
+ objcg = obj_cgroup_from_private_id(id);
+ __mem_cgroup_private_id_put(objcg, id, n);
}
static void mem_cgroup_private_id_kill(struct mem_cgroup *memcg)
{
- __mem_cgroup_private_id_put(memcg, 1);
+ __mem_cgroup_private_id_put(memcg->private_id_objcg, memcg->private_id, 1);
}
unsigned short mem_cgroup_private_id_get(struct mem_cgroup *memcg, unsigned int n)
{
- while (!refcount_add_not_zero(n, &memcg->private_id_ref)) {
+ struct obj_cgroup *objcg;
+
+ lockdep_assert_once(rcu_read_lock_held());
+
+ objcg = memcg->private_id_objcg;
+
+ while (!refcount_add_not_zero(n, &objcg->private_id_ref)) {
/*
* The root cgroup cannot be destroyed, so it's refcount must
* always be >= 1.
@@ -4119,6 +4136,7 @@ unsigned short mem_cgroup_private_id_get
break;
}
memcg = parent_mem_cgroup(memcg);
+ objcg = memcg->private_id_objcg;
}
return mem_cgroup_private_id(memcg);
@@ -4129,11 +4147,25 @@ unsigned short mem_cgroup_private_id_get
* @id: the memcg id to look up
*
* Caller must hold rcu_read_lock().
+ *
+ * @return: the memcg, or NULL if the memcg referred to is already dead.
*/
struct mem_cgroup *mem_cgroup_from_private_id(unsigned short id)
{
+ struct obj_cgroup *objcg;
+ struct mem_cgroup *memcg;
+
WARN_ON_ONCE(!rcu_read_lock_held());
- return xa_load(&mem_cgroup_private_ids, id);
+
+ objcg = obj_cgroup_from_private_id(id);
+ if (!objcg)
+ return NULL;
+
+ memcg = obj_cgroup_memcg(objcg);
+ if (mem_cgroup_private_id(memcg) != id)
+ return NULL;
+
+ return memcg;
}
struct mem_cgroup *mem_cgroup_get_from_id(u64 id)
@@ -4380,9 +4412,10 @@ static int mem_cgroup_css_online(struct
FLUSH_TIME);
lru_gen_online_memcg(memcg);
- /* Online state pins memcg ID, memcg ID pins CSS */
- refcount_set(&memcg->private_id_ref, 1);
- css_get(css);
+ /* CSS pins memcg ID, memcg ID pins obj cgroup */
+ memcg->private_id_objcg = objcg;
+ refcount_set(&memcg->private_id_objcg->private_id_ref, 1);
+ obj_cgroup_get(memcg->private_id_objcg);
/*
* Ensure mem_cgroup_from_private_id() works once we're fully online.
@@ -4394,7 +4427,7 @@ static int mem_cgroup_css_online(struct
* publish it here at the end of onlining. This matches the
* regular ID destruction during offlining.
*/
- xa_store(&mem_cgroup_private_ids, memcg->private_id, memcg, GFP_KERNEL);
+ xa_store(&mem_cgroup_private_ids, memcg->private_id, memcg->private_id_objcg, GFP_KERNEL);
return 0;
free_objcg:
@@ -5832,8 +5865,6 @@ static void __init memcg_struct_check(vo
memory_events_local);
CACHELINE_ASSERT_GROUP_MEMBER(struct mem_cgroup, memcg_write_hot,
vmpressure);
- CACHELINE_ASSERT_GROUP_MEMBER(struct mem_cgroup, memcg_write_hot,
- private_id_ref);
#ifdef CONFIG_MEMCG_NMI_SAFETY_REQUIRES_ATOMIC
CACHELINE_ASSERT_GROUP_MEMBER(struct mem_cgroup, memcg_write_hot,
kmem_stat);
@@ -5879,6 +5910,8 @@ static void __init memcg_struct_check(vo
zswap_writeback);
#endif
CACHELINE_ASSERT_GROUP_MEMBER(struct mem_cgroup, memcg_read_mostly,
+ private_id_objcg);
+ CACHELINE_ASSERT_GROUP_MEMBER(struct mem_cgroup, memcg_read_mostly,
private_id);
CACHELINE_ASSERT_GROUP_MEMBER(struct mem_cgroup, memcg_read_mostly,
kmemcg_id);
@@ -6013,10 +6046,12 @@ int __mem_cgroup_try_charge_swap(struct
*/
void __mem_cgroup_uncharge_swap(unsigned short id, unsigned int nr_pages)
{
+ struct obj_cgroup *objcg;
struct mem_cgroup *memcg;
rcu_read_lock();
- memcg = mem_cgroup_from_private_id(id);
+ objcg = obj_cgroup_from_private_id(id);
+ memcg = obj_cgroup_memcg(objcg);
if (memcg) {
if (!mem_cgroup_private_id_is_root(id)) {
if (do_memsw_account())
@@ -6025,7 +6060,7 @@ void __mem_cgroup_uncharge_swap(unsigned
page_counter_uncharge(&memcg->swap, nr_pages);
}
mod_memcg_state(memcg, MEMCG_SWAP, -nr_pages);
- mem_cgroup_private_id_put(id, nr_pages);
+ __mem_cgroup_private_id_put(objcg, id, nr_pages);
}
rcu_read_unlock();
}
--- a/mm/workingset.c~memcg-move-memcg-private-id-refcount-to-objcg
+++ a/mm/workingset.c
@@ -470,7 +470,7 @@ bool workingset_test_recent(void *shadow
* configurations instead.
*/
eviction_memcg = mem_cgroup_from_private_id(memcgid);
- if (!mem_cgroup_tryget(eviction_memcg))
+ if (eviction_memcg && !mem_cgroup_tryget(eviction_memcg))
eviction_memcg = NULL;
rcu_read_unlock();
_
Patches currently in -mm which might be from bingfangguo@tencent.com are
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-10-24 8:57 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-24 8:57 [merged mm-stable] memcg-move-memcg-private-id-refcount-to-objcg.patch removed from -mm tree Andrew Morton
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.