* [PATCH v3 0/4] mm: restore per-memcg reclaim for NONSLAB shrinkers under nokmem
@ 2026-09-10 8:07 Qinyun Tan
2026-09-10 8:07 ` [PATCH v3 1/4] mm: memcontrol: drop kmemcg_id and use mem_cgroup_id() for list_lru indexing Qinyun Tan
` (5 more replies)
0 siblings, 6 replies; 10+ messages in thread
From: Qinyun Tan @ 2026-09-10 8:07 UTC (permalink / raw)
To: Andrew Morton
Cc: Johannes Weiner, Michal Hocko, Roman Gushchin, Shakeel Butt,
Muchun Song, Michal Koutný,
David Hildenbrand, Zi Yan, Baolin Wang, Usama Arif, Dave Chinner,
Qi Zheng, Yosry Ahmed, Nhat Pham, Chengming Zhou, Xunlei Pang,
cgroups, linux-mm, linux-kernel, Qinyun Tan
With cgroup.memory=nokmem, the THP deferred split shrinker and the
zswap shrinker are degraded in two ways.
First, both shrinkers are missing the SHRINKER_NONSLAB flag, so
shrinker_memcg_alloc() demotes them to non-memcg-aware shrinkers:
limit-induced reclaim of a cgroup neither splits its partially
unmapped THPs nor writes back its zswapped pages. v1 of this series
[1] restored the flag to fix that.
However, as Sashiko's review of v1 pointed out [2], the flag alone
is not enough. __list_lru_init() also collapses every list_lru into
per-node lists under nokmem, so even with the flag restored, the
objects of all cgroups share one list per node: the per-memcg
shrinker bit is only set for whichever memcg happens to repopulate
the empty list, so pressure in other cgroups may not even trigger
the scan, and when it does, the scan walks everyone's objects.
Before commit fafaeceb89a5 ("mm: switch deferred split shrinker to
list_lru"), THP had fully per-memcg deferred split queues embedded
in struct mem_cgroup, working independently of kmem accounting.
nokmem only opts out of kernel slab accounting; THPs and zswapped
pages are user memory and remain charged to their cgroups, so
per-memcg reclaim is still what these shrinkers want.
This series keeps list_lrus backed by SHRINKER_NONSLAB shrinkers
memcg aware under nokmem:
Patch 1 drops the kmemcg_id copy, which is only assigned when kmem
accounting is enabled, and indexes the list_lru xarray with
mem_cgroup_id() instead, so the index works independently of kmem
accounting. The list_lru plumbing passes memcg pointers now, and
memcg_online_kmem()/memcg_offline_kmem() are inlined into the css
online/offline hooks. It also drops the nokmem early return from
the offline path so these lrus are reparented on offline.
Patch 2 keeps a list_lru memcg aware under nokmem when its backing
shrinker is registered SHRINKER_NONSLAB.
Patches 3 and 4 restore/add SHRINKER_NONSLAB on the THP deferred
split shrinker and the zswap shrinker.
The savings of nokmem are preserved: slab-backed lrus (e.g. the
superblock dentry/inode lrus) still fall back to per-node lists, and
the per-memcg lists are only allocated when a memcg actually holds
such objects.
Changes in v3:
- Index the list_lru xarray with mem_cgroup_id() (the cgroup ID)
instead of the private memcg ID, whose lifetime only covers
online groups, and pass memcg pointers through the list_lru
plumbing; inline memcg_online_kmem()/memcg_offline_kmem() into
the css online/offline hooks (patch 1, per Johannes's review of
v2 [3]).
- Describe in patch 3's changelog why fafaeceb89a5 dropped
SHRINKER_NONSLAB knowingly, per Johannes's pointer to the
original discussion [3].
- Collected review tags: Johannes's Reviewed-by on patches 2-4,
Nhat's and Yosry's Acked-by on patch 4.
[1] https://lore.kernel.org/lkml/20260904033503.4067283-1-qinyuntan@linux.alibaba.com/
[2] https://sashiko.dev/#/patchset/20260904033503.4067283-1-qinyuntan@linux.alibaba.com
[3] https://lore.kernel.org/lkml/20260907110111.2286932-1-qinyuntan@linux.alibaba.com/
Qinyun Tan (4):
mm: memcontrol: drop kmemcg_id and use mem_cgroup_id() for list_lru
indexing
mm: list_lru: keep per-memcg lists with nokmem for NONSLAB-backed lrus
mm: thp: restore SHRINKER_NONSLAB on the deferred split shrinker
mm: zswap: mark the zswap shrinker SHRINKER_NONSLAB
include/linux/memcontrol.h | 15 -------------
mm/huge_memory.c | 3 ++-
mm/list_lru.c | 31 ++++++++++++++-------------
mm/memcontrol.c | 43 +++++++-------------------------------
mm/zswap.c | 4 ++--
5 files changed, 29 insertions(+), 67 deletions(-)
--
2.43.7
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v3 1/4] mm: memcontrol: drop kmemcg_id and use mem_cgroup_id() for list_lru indexing 2026-09-10 8:07 [PATCH v3 0/4] mm: restore per-memcg reclaim for NONSLAB shrinkers under nokmem Qinyun Tan @ 2026-09-10 8:07 ` Qinyun Tan 2026-09-26 20:29 ` Kairui Song 2026-09-10 8:07 ` [PATCH v3 2/4] mm: list_lru: keep per-memcg lists with nokmem for NONSLAB-backed lrus Qinyun Tan ` (4 subsequent siblings) 5 siblings, 1 reply; 10+ messages in thread From: Qinyun Tan @ 2026-09-10 8:07 UTC (permalink / raw) To: Andrew Morton Cc: Johannes Weiner, Michal Hocko, Roman Gushchin, Shakeel Butt, Muchun Song, Michal Koutný, David Hildenbrand, Zi Yan, Baolin Wang, Usama Arif, Dave Chinner, Qi Zheng, Yosry Ahmed, Nhat Pham, Chengming Zhou, Xunlei Pang, cgroups, linux-mm, linux-kernel, Qinyun Tan kmemcg_id is a copy of the private memcg ID and serves no purpose other than indexing the per-memcg list_lru xarray. It is assigned when kmem accounting goes online, which never happens with cgroup.memory=nokmem, and the memcgs then all resolve to the per-node lists. The next patch needs the index to work under nokmem as well. Index the lists with mem_cgroup_id(). The cgroup ID is unique per memcg and is only recycled once the cgroup is destroyed, long after offlining has erased the xarray entries, so a recycled ID cannot resurrect a stale entry. The lookup now takes memcg pointers and routes root and NULL to the per-node lists itself. Also drop the nokmem early return from the offline path, so that the reparenting covers lrus that stay memcg aware without kmem accounting. memcg_online_kmem() and memcg_offline_kmem() are each down to a single statement now; inline them into the css online and offline hooks, dropping the root check, as css_offline() is never called for the root and a memcg that failed css_online() cannot have list_lru entries. Signed-off-by: Qinyun Tan <qinyuntan@linux.alibaba.com> --- include/linux/memcontrol.h | 15 ------------- mm/list_lru.c | 27 ++++++++++++------------ mm/memcontrol.c | 43 +++++++------------------------------- 3 files changed, 22 insertions(+), 63 deletions(-) diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index fdf4812e1d818..821dc0e32603a 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -254,7 +254,6 @@ struct mem_cgroup { #if BITS_PER_LONG < 64 seqlock_t socket_pressure_seqlock; #endif - int kmemcg_id; #ifdef CONFIG_CGROUP_WRITEBACK struct list_head cgwb_list; @@ -1774,15 +1773,6 @@ static inline void memcg_kmem_uncharge_page(struct page *page, int order) __memcg_kmem_uncharge_page(page, order); } -/* - * A helper for accessing memcg's kmem_id, used for getting - * corresponding LRU lists. - */ -static inline int memcg_kmem_id(struct mem_cgroup *memcg) -{ - return memcg ? memcg->kmemcg_id : -1; -} - struct mem_cgroup *mem_cgroup_from_virt(void *p); static inline void count_objcg_events(struct obj_cgroup *objcg, @@ -1850,11 +1840,6 @@ static inline bool memcg_kmem_online(void) return false; } -static inline int memcg_kmem_id(struct mem_cgroup *memcg) -{ - return -1; -} - static inline struct mem_cgroup *mem_cgroup_from_virt(void *p) { return NULL; diff --git a/mm/list_lru.c b/mm/list_lru.c index a4522ca93ebcb..9241d17de4388 100644 --- a/mm/list_lru.c +++ b/mm/list_lru.c @@ -72,10 +72,11 @@ static int lru_shrinker_id(struct list_lru *lru) } static inline struct list_lru_one * -list_lru_from_memcg_idx(struct list_lru *lru, int nid, int idx) +list_lru_from_memcg(struct list_lru *lru, int nid, struct mem_cgroup *memcg) { - if (list_lru_memcg_aware(lru) && idx >= 0) { - struct list_lru_memcg *mlru = xa_load(&lru->xa, idx); + if (list_lru_memcg_aware(lru) && memcg && !mem_cgroup_is_root(memcg)) { + struct list_lru_memcg *mlru = + xa_load(&lru->xa, mem_cgroup_id(memcg)); return mlru ? &mlru->node[nid] : NULL; } @@ -91,7 +92,7 @@ lock_list_lru_of_memcg(struct list_lru *lru, int nid, rcu_read_lock(); again: - l = list_lru_from_memcg_idx(lru, nid, memcg_kmem_id(*memcg)); + l = list_lru_from_memcg(lru, nid, *memcg); if (likely(l)) { lock_list_lru(l, irq, irq_flags); if (likely(READ_ONCE(l->nr_items) != LONG_MIN)) { @@ -132,7 +133,7 @@ static inline bool list_lru_memcg_aware(struct list_lru *lru) } static inline struct list_lru_one * -list_lru_from_memcg_idx(struct list_lru *lru, int nid, int idx) +list_lru_from_memcg(struct list_lru *lru, int nid, struct mem_cgroup *memcg) { return &lru->node[nid].lru; } @@ -313,7 +314,7 @@ unsigned long list_lru_count_one(struct list_lru *lru, long count; rcu_read_lock(); - l = list_lru_from_memcg_idx(lru, nid, memcg_kmem_id(memcg)); + l = list_lru_from_memcg(lru, nid, memcg); count = l ? READ_ONCE(l->nr_items) : 0; rcu_read_unlock(); @@ -502,11 +503,10 @@ static void memcg_reparent_list_lru_one(struct list_lru *lru, int nid, struct list_lru_one *src, struct mem_cgroup *dst_memcg) { - int dst_idx = dst_memcg->kmemcg_id; struct list_lru_one *dst; spin_lock_irq(&src->lock); - dst = list_lru_from_memcg_idx(lru, nid, dst_idx); + dst = list_lru_from_memcg(lru, nid, dst_memcg); spin_lock_nested(&dst->lock, SINGLE_DEPTH_NESTING); list_splice_init(&src->list, &dst->list); @@ -536,7 +536,7 @@ void memcg_reparent_list_lrus(struct mem_cgroup *memcg, struct mem_cgroup *paren * allocating a new mlru since CSS_DYING is already set for this * memcg a rcu grace period ago. */ - mlru = xa_load(&lru->xa, memcg->kmemcg_id); + mlru = xa_load(&lru->xa, mem_cgroup_id(memcg)); if (!mlru) continue; @@ -551,7 +551,7 @@ void memcg_reparent_list_lrus(struct mem_cgroup *memcg, struct mem_cgroup *paren for_each_node(i) memcg_reparent_list_lru_one(lru, i, &mlru->node[i], parent); - xa_erase_irq(&lru->xa, memcg->kmemcg_id); + xa_erase_irq(&lru->xa, mem_cgroup_id(memcg)); /* * Here all list_lrus corresponding to the cgroup are guaranteed @@ -566,9 +566,10 @@ void memcg_reparent_list_lrus(struct mem_cgroup *memcg, struct mem_cgroup *paren static inline bool memcg_list_lru_allocated(struct mem_cgroup *memcg, struct list_lru *lru) { - int idx = memcg->kmemcg_id; + if (!memcg || mem_cgroup_is_root(memcg)) + return true; - return idx < 0 || xa_load(&lru->xa, idx); + return xa_load(&lru->xa, mem_cgroup_id(memcg)); } static int __memcg_list_lru_alloc(struct mem_cgroup *memcg, @@ -602,7 +603,7 @@ static int __memcg_list_lru_alloc(struct mem_cgroup *memcg, if (!mlru) return -ENOMEM; } - xas_set(&xas, pos->kmemcg_id); + xas_set(&xas, mem_cgroup_id(pos)); do { xas_lock_irqsave(&xas, flags); if (!xas_load(&xas) && !css_is_dying(&pos->css)) { diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 7ce50bccf1264..aa010608fbff8 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -3771,33 +3771,6 @@ void folio_split_memcg_refs(struct folio *folio, unsigned old_order, obj_cgroup_get_many(folio_objcg(folio), new_refs); } -static void memcg_online_kmem(struct mem_cgroup *memcg) -{ - if (mem_cgroup_kmem_disabled()) - return; - - if (unlikely(mem_cgroup_is_root(memcg))) - return; - - static_branch_enable(&memcg_kmem_online_key); - - memcg->kmemcg_id = memcg->id.id; -} - -static void memcg_offline_kmem(struct mem_cgroup *memcg) -{ - struct mem_cgroup *parent; - - if (mem_cgroup_kmem_disabled()) - return; - - if (unlikely(mem_cgroup_is_root(memcg))) - return; - - parent = parent_mem_cgroup(memcg); - memcg_reparent_list_lrus(memcg, parent); -} - #ifdef CONFIG_CGROUP_WRITEBACK #include <trace/events/writeback.h> @@ -4225,7 +4198,6 @@ static struct mem_cgroup *mem_cgroup_alloc(struct mem_cgroup *parent) seqlock_init(&memcg->socket_pressure_seqlock); #endif memcg1_memcg_init(memcg); - memcg->kmemcg_id = -1; #ifdef CONFIG_CGROUP_WRITEBACK INIT_LIST_HEAD(&memcg->cgwb_list); for (i = 0; i < MEMCG_CGWB_FRN_CNT; i++) @@ -4299,7 +4271,8 @@ static int mem_cgroup_css_online(struct cgroup_subsys_state *css) struct obj_cgroup *objcg; int nid; - memcg_online_kmem(memcg); + if (!mem_cgroup_kmem_disabled() && likely(!mem_cgroup_is_root(memcg))) + static_branch_enable(&memcg_kmem_online_key); /* * A memcg must be visible for expand_shrinker_info() @@ -4307,7 +4280,7 @@ static int mem_cgroup_css_online(struct cgroup_subsys_state *css) * here, when mem_cgroup_iter() can't skip it. */ if (alloc_shrinker_info(memcg)) - goto offline_kmem; + goto reparent_lrus; for_each_node(nid) { objcg = obj_cgroup_alloc(); @@ -4364,8 +4337,8 @@ static int mem_cgroup_css_online(struct cgroup_subsys_state *css) } } free_shrinker_info(memcg); -offline_kmem: - memcg_offline_kmem(memcg); +reparent_lrus: + memcg_reparent_list_lrus(memcg, parent_mem_cgroup(memcg)); mem_cgroup_private_id_remove(memcg); return -ENOMEM; } @@ -4381,11 +4354,11 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css) zswap_memcg_offline_cleanup(memcg); - memcg_offline_kmem(memcg); + memcg_reparent_list_lrus(memcg, parent_mem_cgroup(memcg)); /* * The reparenting of objcg must be after the reparenting of - * the list_lru in memcg_offline_kmem(), which ensures that - * they will not mistakenly get the parent list_lru. + * the list_lru above, which ensures that they will not + * mistakenly get the parent list_lru. */ memcg_reparent_objcgs(memcg); reparent_shrinker_deferred(memcg); -- 2.43.7 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 1/4] mm: memcontrol: drop kmemcg_id and use mem_cgroup_id() for list_lru indexing 2026-09-10 8:07 ` [PATCH v3 1/4] mm: memcontrol: drop kmemcg_id and use mem_cgroup_id() for list_lru indexing Qinyun Tan @ 2026-09-26 20:29 ` Kairui Song 0 siblings, 0 replies; 10+ messages in thread From: Kairui Song @ 2026-09-26 20:29 UTC (permalink / raw) To: Qinyun Tan Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Roman Gushchin, Shakeel Butt, Muchun Song, Michal Koutný, David Hildenbrand, Zi Yan, Baolin Wang, Usama Arif, Dave Chinner, Qi Zheng, Yosry Ahmed, Nhat Pham, Chengming Zhou, Xunlei Pang, cgroups, linux-mm, linux-kernel On Thu, Sep 10, 2026 at 4:18 PM Qinyun Tan <qinyuntan@linux.alibaba.com> wrote: > > kmemcg_id is a copy of the private memcg ID and serves no purpose > other than indexing the per-memcg list_lru xarray. It is assigned > when kmem accounting goes online, which never happens with > cgroup.memory=nokmem, and the memcgs then all resolve to the > per-node lists. The next patch needs the index to work under nokmem > as well. > > Index the lists with mem_cgroup_id(). The cgroup ID is unique per > memcg and is only recycled once the cgroup is destroyed, long after > offlining has erased the xarray entries, so a recycled ID cannot > resurrect a stale entry. The lookup now takes memcg pointers and > routes root and NULL to the per-node lists itself. > > Also drop the nokmem early return from the offline path, so that the > reparenting covers lrus that stay memcg aware without kmem > accounting. memcg_online_kmem() and memcg_offline_kmem() are each > down to a single statement now; inline them into the css online and > offline hooks, dropping the root check, as css_offline() is never > called for the root and a memcg that failed css_online() cannot have > list_lru entries. > > Signed-off-by: Qinyun Tan <qinyuntan@linux.alibaba.com> > --- > include/linux/memcontrol.h | 15 ------------- > mm/list_lru.c | 27 ++++++++++++------------ > mm/memcontrol.c | 43 +++++++------------------------------- > 3 files changed, 22 insertions(+), 63 deletions(-) > > diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h > index fdf4812e1d818..821dc0e32603a 100644 > --- a/include/linux/memcontrol.h > +++ b/include/linux/memcontrol.h > @@ -254,7 +254,6 @@ struct mem_cgroup { > #if BITS_PER_LONG < 64 > seqlock_t socket_pressure_seqlock; > #endif > - int kmemcg_id; > > #ifdef CONFIG_CGROUP_WRITEBACK > struct list_head cgwb_list; > @@ -1774,15 +1773,6 @@ static inline void memcg_kmem_uncharge_page(struct page *page, int order) > __memcg_kmem_uncharge_page(page, order); > } > > -/* > - * A helper for accessing memcg's kmem_id, used for getting > - * corresponding LRU lists. > - */ > -static inline int memcg_kmem_id(struct mem_cgroup *memcg) > -{ > - return memcg ? memcg->kmemcg_id : -1; > -} > - > struct mem_cgroup *mem_cgroup_from_virt(void *p); > > static inline void count_objcg_events(struct obj_cgroup *objcg, > @@ -1850,11 +1840,6 @@ static inline bool memcg_kmem_online(void) > return false; > } > > -static inline int memcg_kmem_id(struct mem_cgroup *memcg) > -{ > - return -1; > -} > - > static inline struct mem_cgroup *mem_cgroup_from_virt(void *p) > { > return NULL; > diff --git a/mm/list_lru.c b/mm/list_lru.c > index a4522ca93ebcb..9241d17de4388 100644 > --- a/mm/list_lru.c > +++ b/mm/list_lru.c > @@ -72,10 +72,11 @@ static int lru_shrinker_id(struct list_lru *lru) > } > > static inline struct list_lru_one * > -list_lru_from_memcg_idx(struct list_lru *lru, int nid, int idx) > +list_lru_from_memcg(struct list_lru *lru, int nid, struct mem_cgroup *memcg) > { > - if (list_lru_memcg_aware(lru) && idx >= 0) { > - struct list_lru_memcg *mlru = xa_load(&lru->xa, idx); > + if (list_lru_memcg_aware(lru) && memcg && !mem_cgroup_is_root(memcg)) { > + struct list_lru_memcg *mlru = > + xa_load(&lru->xa, mem_cgroup_id(memcg)); > > return mlru ? &mlru->node[nid] : NULL; > } > @@ -91,7 +92,7 @@ lock_list_lru_of_memcg(struct list_lru *lru, int nid, > > rcu_read_lock(); > again: > - l = list_lru_from_memcg_idx(lru, nid, memcg_kmem_id(*memcg)); > + l = list_lru_from_memcg(lru, nid, *memcg); > if (likely(l)) { > lock_list_lru(l, irq, irq_flags); > if (likely(READ_ONCE(l->nr_items) != LONG_MIN)) { > @@ -132,7 +133,7 @@ static inline bool list_lru_memcg_aware(struct list_lru *lru) > } > > static inline struct list_lru_one * > -list_lru_from_memcg_idx(struct list_lru *lru, int nid, int idx) > +list_lru_from_memcg(struct list_lru *lru, int nid, struct mem_cgroup *memcg) > { > return &lru->node[nid].lru; > } > @@ -313,7 +314,7 @@ unsigned long list_lru_count_one(struct list_lru *lru, > long count; > > rcu_read_lock(); > - l = list_lru_from_memcg_idx(lru, nid, memcg_kmem_id(memcg)); > + l = list_lru_from_memcg(lru, nid, memcg); > count = l ? READ_ONCE(l->nr_items) : 0; > rcu_read_unlock(); > > @@ -502,11 +503,10 @@ static void memcg_reparent_list_lru_one(struct list_lru *lru, int nid, > struct list_lru_one *src, > struct mem_cgroup *dst_memcg) > { > - int dst_idx = dst_memcg->kmemcg_id; > struct list_lru_one *dst; > > spin_lock_irq(&src->lock); > - dst = list_lru_from_memcg_idx(lru, nid, dst_idx); > + dst = list_lru_from_memcg(lru, nid, dst_memcg); > spin_lock_nested(&dst->lock, SINGLE_DEPTH_NESTING); > > list_splice_init(&src->list, &dst->list); > @@ -536,7 +536,7 @@ void memcg_reparent_list_lrus(struct mem_cgroup *memcg, struct mem_cgroup *paren > * allocating a new mlru since CSS_DYING is already set for this > * memcg a rcu grace period ago. > */ > - mlru = xa_load(&lru->xa, memcg->kmemcg_id); > + mlru = xa_load(&lru->xa, mem_cgroup_id(memcg)); > if (!mlru) > continue; > > @@ -551,7 +551,7 @@ void memcg_reparent_list_lrus(struct mem_cgroup *memcg, struct mem_cgroup *paren > for_each_node(i) > memcg_reparent_list_lru_one(lru, i, &mlru->node[i], parent); > > - xa_erase_irq(&lru->xa, memcg->kmemcg_id); > + xa_erase_irq(&lru->xa, mem_cgroup_id(memcg)); > > /* > * Here all list_lrus corresponding to the cgroup are guaranteed > @@ -566,9 +566,10 @@ void memcg_reparent_list_lrus(struct mem_cgroup *memcg, struct mem_cgroup *paren > static inline bool memcg_list_lru_allocated(struct mem_cgroup *memcg, > struct list_lru *lru) > { > - int idx = memcg->kmemcg_id; > + if (!memcg || mem_cgroup_is_root(memcg)) > + return true; > > - return idx < 0 || xa_load(&lru->xa, idx); > + return xa_load(&lru->xa, mem_cgroup_id(memcg)); > } > > static int __memcg_list_lru_alloc(struct mem_cgroup *memcg, > @@ -602,7 +603,7 @@ static int __memcg_list_lru_alloc(struct mem_cgroup *memcg, > if (!mlru) > return -ENOMEM; > } > - xas_set(&xas, pos->kmemcg_id); > + xas_set(&xas, mem_cgroup_id(pos)); > do { > xas_lock_irqsave(&xas, flags); > if (!xas_load(&xas) && !css_is_dying(&pos->css)) { > diff --git a/mm/memcontrol.c b/mm/memcontrol.c > index 7ce50bccf1264..aa010608fbff8 100644 > --- a/mm/memcontrol.c > +++ b/mm/memcontrol.c > @@ -3771,33 +3771,6 @@ void folio_split_memcg_refs(struct folio *folio, unsigned old_order, > obj_cgroup_get_many(folio_objcg(folio), new_refs); > } > > -static void memcg_online_kmem(struct mem_cgroup *memcg) > -{ > - if (mem_cgroup_kmem_disabled()) > - return; > - > - if (unlikely(mem_cgroup_is_root(memcg))) > - return; > - > - static_branch_enable(&memcg_kmem_online_key); > - > - memcg->kmemcg_id = memcg->id.id; > -} > - > -static void memcg_offline_kmem(struct mem_cgroup *memcg) > -{ > - struct mem_cgroup *parent; > - > - if (mem_cgroup_kmem_disabled()) > - return; > - > - if (unlikely(mem_cgroup_is_root(memcg))) > - return; > - > - parent = parent_mem_cgroup(memcg); > - memcg_reparent_list_lrus(memcg, parent); > -} > - > #ifdef CONFIG_CGROUP_WRITEBACK > > #include <trace/events/writeback.h> > @@ -4225,7 +4198,6 @@ static struct mem_cgroup *mem_cgroup_alloc(struct mem_cgroup *parent) > seqlock_init(&memcg->socket_pressure_seqlock); > #endif > memcg1_memcg_init(memcg); > - memcg->kmemcg_id = -1; > #ifdef CONFIG_CGROUP_WRITEBACK > INIT_LIST_HEAD(&memcg->cgwb_list); > for (i = 0; i < MEMCG_CGWB_FRN_CNT; i++) > @@ -4299,7 +4271,8 @@ static int mem_cgroup_css_online(struct cgroup_subsys_state *css) > struct obj_cgroup *objcg; > int nid; > > - memcg_online_kmem(memcg); > + if (!mem_cgroup_kmem_disabled() && likely(!mem_cgroup_is_root(memcg))) > + static_branch_enable(&memcg_kmem_online_key); > > /* > * A memcg must be visible for expand_shrinker_info() > @@ -4307,7 +4280,7 @@ static int mem_cgroup_css_online(struct cgroup_subsys_state *css) > * here, when mem_cgroup_iter() can't skip it. > */ > if (alloc_shrinker_info(memcg)) > - goto offline_kmem; > + goto reparent_lrus; > > for_each_node(nid) { > objcg = obj_cgroup_alloc(); > @@ -4364,8 +4337,8 @@ static int mem_cgroup_css_online(struct cgroup_subsys_state *css) > } > } > free_shrinker_info(memcg); > -offline_kmem: > - memcg_offline_kmem(memcg); > +reparent_lrus: > + memcg_reparent_list_lrus(memcg, parent_mem_cgroup(memcg)); > mem_cgroup_private_id_remove(memcg); > return -ENOMEM; > } > @@ -4381,11 +4354,11 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css) > > zswap_memcg_offline_cleanup(memcg); > > - memcg_offline_kmem(memcg); > + memcg_reparent_list_lrus(memcg, parent_mem_cgroup(memcg)); > /* > * The reparenting of objcg must be after the reparenting of > - * the list_lru in memcg_offline_kmem(), which ensures that > - * they will not mistakenly get the parent list_lru. > + * the list_lru above, which ensures that they will not > + * mistakenly get the parent list_lru. > */ > memcg_reparent_objcgs(memcg); > reparent_shrinker_deferred(memcg); > -- > 2.43.7 > Hi Qinyun With this commit, my arm64 VM hangs at every boot with a 100%-reproducible infinite loop in xas_find(), driven by the dcache shrinker during the first remount of the root filesystem. Reverting this fixes the issue: CPU: 2 UID: 0 PID: 579 Comm: mount Not tainted 7.3.0-rc4.orig-00725-g09d9672a5d4f #33 PREEMPT(full) pc : xas_find+0x184/0x1c8 lr : xas_find+0x6c/0x1c8 Call trace: xas_find+0x184/0x1c8 xa_find_after+0x88/0x120 list_lru_walk_node+0xc0/0x2a0 shrink_dcache_sb+0x80/0x130 reconfigure_super+0xc0/0x1f8 vfs_fsconfig_locked+0xa8/0x120 __arm64_sys_fsconfig+0x280/0x33c Just for reference, this also fixed it: diff --git a/mm/list_lru.c b/mm/list_lru.c index 7dbb6125cb1d..42c48c3b9235 100644 --- a/mm/list_lru.c +++ b/mm/list_lru.c @@ -427,13 +427,13 @@ unsigned long list_lru_walk_node(struct list_lru *lru, int nid, unsigned long index; xa_for_each(&lru->xa, index, mlru) { - rcu_read_lock(); - memcg = mem_cgroup_from_private_id(index); - if (!memcg || !mem_cgroup_tryget(memcg)) { - rcu_read_unlock(); + memcg = mem_cgroup_get_from_id(index); + if (!memcg) continue; - } - rcu_read_unlock(); isolated += __list_lru_walk_one(lru, nid, memcg, isolate, cb_arg, nr_to_walk, false); === And BTW cgroup ID lookups seem much heavier, not sure about the performance impact. ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v3 2/4] mm: list_lru: keep per-memcg lists with nokmem for NONSLAB-backed lrus 2026-09-10 8:07 [PATCH v3 0/4] mm: restore per-memcg reclaim for NONSLAB shrinkers under nokmem Qinyun Tan 2026-09-10 8:07 ` [PATCH v3 1/4] mm: memcontrol: drop kmemcg_id and use mem_cgroup_id() for list_lru indexing Qinyun Tan @ 2026-09-10 8:07 ` Qinyun Tan 2026-09-10 8:07 ` [PATCH v3 3/4] mm: thp: restore SHRINKER_NONSLAB on the deferred split shrinker Qinyun Tan ` (3 subsequent siblings) 5 siblings, 0 replies; 10+ messages in thread From: Qinyun Tan @ 2026-09-10 8:07 UTC (permalink / raw) To: Andrew Morton Cc: Johannes Weiner, Michal Hocko, Roman Gushchin, Shakeel Butt, Muchun Song, Michal Koutný, David Hildenbrand, Zi Yan, Baolin Wang, Usama Arif, Dave Chinner, Qi Zheng, Yosry Ahmed, Nhat Pham, Chengming Zhou, Xunlei Pang, cgroups, linux-mm, linux-kernel, Qinyun Tan With cgroup.memory=nokmem, __list_lru_init() collapses every list_lru into per-node lists. That is fine for slab objects, which are not charged per memcg without kmem accounting. But a lru backed by a SHRINKER_NONSLAB shrinker, e.g. the THP deferred split queue or the zswap entries, holds user memory, which is charged regardless of nokmem. Collapsing such an lru loses the per-memcg view of its objects. Reclaim can no longer target just the cgroup under pressure. Keep such lrus memcg aware under nokmem when their backing shrinker is registered SHRINKER_NONSLAB. This leaves the savings of nokmem intact: slab-backed lrus (e.g. the superblock dentry/inode lrus) still fall back to the per-node lists, and the per-memcg lists are allocated only when a memcg actually holds such objects. Fixes: fafaeceb89a5 ("mm: switch deferred split shrinker to list_lru") Signed-off-by: Qinyun Tan <qinyuntan@linux.alibaba.com> Reviewed-by: Johannes Weiner <hannes@cmpxchg.org> --- mm/list_lru.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mm/list_lru.c b/mm/list_lru.c index 9241d17de4388..d20faa6de6c02 100644 --- a/mm/list_lru.c +++ b/mm/list_lru.c @@ -672,7 +672,9 @@ int __list_lru_init(struct list_lru *lru, bool memcg_aware, struct shrinker *shr else lru->shrinker_id = -1; - if (mem_cgroup_disabled() || mem_cgroup_kmem_disabled()) + if (mem_cgroup_disabled() || + (mem_cgroup_kmem_disabled() && + (!shrinker || !(shrinker->flags & SHRINKER_NONSLAB)))) memcg_aware = false; #endif -- 2.43.7 ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v3 3/4] mm: thp: restore SHRINKER_NONSLAB on the deferred split shrinker 2026-09-10 8:07 [PATCH v3 0/4] mm: restore per-memcg reclaim for NONSLAB shrinkers under nokmem Qinyun Tan 2026-09-10 8:07 ` [PATCH v3 1/4] mm: memcontrol: drop kmemcg_id and use mem_cgroup_id() for list_lru indexing Qinyun Tan 2026-09-10 8:07 ` [PATCH v3 2/4] mm: list_lru: keep per-memcg lists with nokmem for NONSLAB-backed lrus Qinyun Tan @ 2026-09-10 8:07 ` Qinyun Tan 2026-09-10 8:07 ` [PATCH v3 4/4] mm: zswap: mark the zswap shrinker SHRINKER_NONSLAB Qinyun Tan ` (2 subsequent siblings) 5 siblings, 0 replies; 10+ messages in thread From: Qinyun Tan @ 2026-09-10 8:07 UTC (permalink / raw) To: Andrew Morton Cc: Johannes Weiner, Michal Hocko, Roman Gushchin, Shakeel Butt, Muchun Song, Michal Koutný, David Hildenbrand, Zi Yan, Baolin Wang, Usama Arif, Dave Chinner, Qi Zheng, Yosry Ahmed, Nhat Pham, Chengming Zhou, Xunlei Pang, cgroups, linux-mm, linux-kernel, Qinyun Tan On a system booted with cgroup.memory=nokmem, the deferred split shrinker is demoted to a non-memcg-aware one. As a result, partially unmapped THPs are only split under global reclaim; memcg (limit-induced) reclaim never splits them, so a cgroup under memory pressure keeps its underused THPs intact. The shrinker has carried SHRINKER_NONSLAB since commit 0a432dcbeb32 ("mm: shrinker: make shrinker not depend on memcg kmem") precisely so it would keep working with kmem accounting disabled. Commit fafaeceb89a5 ("mm: switch deferred split shrinker to list_lru") dropped it knowingly: under nokmem the list_lru collapses into a shared per-node list while __list_lru_add() still sets the shrinker bit on whichever memcg happens to add the first item, and with the flag set the shrinker would run twice per reclaim cycle [1]. NONSLAB-backed lrus keep their per-memcg lists under nokmem now, so the shrinker bit identifies the owning memcg again. Restore the flag. This was noticed by Michal during review of the patch "mm/list_lru: don't copy stale shrinker id from non-memcg-aware shrinkers" [2]. [1] https://lore.kernel.org/all/ah9PGv12mqai84ES@cmpxchg.org/ [2] https://lore.kernel.org/lkml/697713c4-0857-485b-aba7-c74f37a3c8b4@linux.alibaba.com/ Fixes: fafaeceb89a5 ("mm: switch deferred split shrinker to list_lru") Suggested-by: Michal Koutný <mkoutny@suse.com> Signed-off-by: Qinyun Tan <qinyuntan@linux.alibaba.com> Acked-by: Zi Yan <ziy@nvidia.com> Acked-by: David Hildenbrand (Arm) <david@kernel.org> Acked-by: Usama Arif <usama.arif@linux.dev> Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com> Reviewed-by: Johannes Weiner <hannes@cmpxchg.org> --- mm/huge_memory.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index c5d11147b69ae..87c9fc48b7cfd 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -1064,7 +1064,8 @@ int folio_memcg_alloc_deferred(struct folio *folio) static int __init thp_shrinker_init(void) { deferred_split_shrinker = shrinker_alloc(SHRINKER_NUMA_AWARE | - SHRINKER_MEMCG_AWARE, + SHRINKER_MEMCG_AWARE | + SHRINKER_NONSLAB, "thp-deferred_split"); if (!deferred_split_shrinker) return -ENOMEM; -- 2.43.7 ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v3 4/4] mm: zswap: mark the zswap shrinker SHRINKER_NONSLAB 2026-09-10 8:07 [PATCH v3 0/4] mm: restore per-memcg reclaim for NONSLAB shrinkers under nokmem Qinyun Tan ` (2 preceding siblings ...) 2026-09-10 8:07 ` [PATCH v3 3/4] mm: thp: restore SHRINKER_NONSLAB on the deferred split shrinker Qinyun Tan @ 2026-09-10 8:07 ` Qinyun Tan 2026-09-10 22:34 ` [PATCH v3 0/4] mm: restore per-memcg reclaim for NONSLAB shrinkers under nokmem Andrew Morton 2026-09-23 1:35 ` Andrew Morton 5 siblings, 0 replies; 10+ messages in thread From: Qinyun Tan @ 2026-09-10 8:07 UTC (permalink / raw) To: Andrew Morton Cc: Johannes Weiner, Michal Hocko, Roman Gushchin, Shakeel Butt, Muchun Song, Michal Koutný, David Hildenbrand, Zi Yan, Baolin Wang, Usama Arif, Dave Chinner, Qi Zheng, Yosry Ahmed, Nhat Pham, Chengming Zhou, Xunlei Pang, cgroups, linux-mm, linux-kernel, Qinyun Tan With kmem accounting disabled (cgroup.memory=nokmem), memcg reclaim never invokes the zswap shrinker: a cgroup under memory pressure does not write back its own zswapped pages to make room; they are only written back by global reclaim or once the global pool limit kicks in. The zswap shrinker is registered memcg-aware but without SHRINKER_NONSLAB, so under nokmem it is treated as a slab shrinker: before commit 03375203e1da ("mm: do not allocate shrinker info with cgroup.memory=nokmem") it was skipped by the !memcg_kmem_online() check in shrink_slab_memcg(); since that commit it is demoted to non-memcg-aware at registration. But the zswap shrinker is not a slab shrinker: it tracks zswap entries and resolves the owning memcg from the folio's objcg, independent of kmem accounting. This was noticed by Michal during review of the patch "mm/list_lru: don't copy stale shrinker id from non-memcg-aware shrinkers" [1]. Mark it SHRINKER_NONSLAB so it keeps its memcg awareness and runs under memcg reclaim with nokmem. [1] https://lore.kernel.org/lkml/697713c4-0857-485b-aba7-c74f37a3c8b4@linux.alibaba.com/ Fixes: b5ba474f3f51 ("zswap: shrink zswap pool based on memory pressure") Suggested-by: Michal Koutný <mkoutny@suse.com> Signed-off-by: Qinyun Tan <qinyuntan@linux.alibaba.com> Acked-by: Usama Arif <usama.arif@linux.dev> Acked-by: Nhat Pham <nphamcs@gmail.com> Acked-by: Yosry Ahmed <yosry@kernel.org> Reviewed-by: Johannes Weiner <hannes@cmpxchg.org> --- mm/zswap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm/zswap.c b/mm/zswap.c index f3ae3c81e48ea..032136942c172 100644 --- a/mm/zswap.c +++ b/mm/zswap.c @@ -1252,8 +1252,8 @@ static struct shrinker *zswap_alloc_shrinker(void) { struct shrinker *shrinker; - shrinker = - shrinker_alloc(SHRINKER_NUMA_AWARE | SHRINKER_MEMCG_AWARE, "mm-zswap"); + shrinker = shrinker_alloc(SHRINKER_NUMA_AWARE | SHRINKER_MEMCG_AWARE | + SHRINKER_NONSLAB, "mm-zswap"); if (!shrinker) return NULL; -- 2.43.7 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 0/4] mm: restore per-memcg reclaim for NONSLAB shrinkers under nokmem 2026-09-10 8:07 [PATCH v3 0/4] mm: restore per-memcg reclaim for NONSLAB shrinkers under nokmem Qinyun Tan ` (3 preceding siblings ...) 2026-09-10 8:07 ` [PATCH v3 4/4] mm: zswap: mark the zswap shrinker SHRINKER_NONSLAB Qinyun Tan @ 2026-09-10 22:34 ` Andrew Morton 2026-09-22 9:52 ` Qinyun Tan 2026-09-23 1:35 ` Andrew Morton 5 siblings, 1 reply; 10+ messages in thread From: Andrew Morton @ 2026-09-10 22:34 UTC (permalink / raw) To: Qinyun Tan Cc: Johannes Weiner, Michal Hocko, Roman Gushchin, Shakeel Butt, Muchun Song, Michal Koutný, David Hildenbrand, Zi Yan, Baolin Wang, Usama Arif, Dave Chinner, Qi Zheng, Yosry Ahmed, Nhat Pham, Chengming Zhou, Xunlei Pang, cgroups, linux-mm, linux-kernel On Thu, 10 Sep 2026 16:07:18 +0800 Qinyun Tan <qinyuntan@linux.alibaba.com> wrote: > With cgroup.memory=nokmem, the THP deferred split shrinker and the > zswap shrinker are degraded in two ways. > > First, both shrinkers are missing the SHRINKER_NONSLAB flag, so > shrinker_memcg_alloc() demotes them to non-memcg-aware shrinkers: > limit-induced reclaim of a cgroup neither splits its partially > unmapped THPs nor writes back its zswapped pages. v1 of this series > [1] restored the flag to fix that. > > However, as Sashiko's review of v1 pointed out [2], the flag alone > is not enough. __list_lru_init() also collapses every list_lru into > per-node lists under nokmem, so even with the flag restored, the > objects of all cgroups share one list per node: the per-memcg > shrinker bit is only set for whichever memcg happens to repopulate > the empty list, so pressure in other cgroups may not even trigger > the scan, and when it does, the scan walks everyone's objects. > > Before commit fafaeceb89a5 ("mm: switch deferred split shrinker to > list_lru"), THP had fully per-memcg deferred split queues embedded > in struct mem_cgroup, working independently of kmem accounting. > nokmem only opts out of kernel slab accounting; THPs and zswapped > pages are user memory and remain charged to their cgroups, so > per-memcg reclaim is still what these shrinkers want. > > This series keeps list_lrus backed by SHRINKER_NONSLAB shrinkers > memcg aware under nokmem: Thanks. It seems that Sashiko still doesn't understand that memory allocations in __init code are considered "can't fail". https://sashiko.dev/#/patchset/20260910080722.3961351-1-qinyuntan@linux.alibaba.com otoh, failures in the functiond which hugepage_init() calls might be caused by things other than ENOMEM so I guess we shouldn't zap all that cleanup code. Anyway, that's unrelated to your changes. I'll save this patchset away for later and shall await reviewer input. Please poke me in a week or so if there hasn't been any, Things are crazy lately. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 0/4] mm: restore per-memcg reclaim for NONSLAB shrinkers under nokmem 2026-09-10 22:34 ` [PATCH v3 0/4] mm: restore per-memcg reclaim for NONSLAB shrinkers under nokmem Andrew Morton @ 2026-09-22 9:52 ` Qinyun Tan 0 siblings, 0 replies; 10+ messages in thread From: Qinyun Tan @ 2026-09-22 9:52 UTC (permalink / raw) To: Andrew Morton Cc: Johannes Weiner, Michal Hocko, Roman Gushchin, Shakeel Butt, Muchun Song, Michal Koutný, David Hildenbrand, Zi Yan, Baolin Wang, Usama Arif, Dave Chinner, Qi Zheng, Yosry Ahmed, Nhat Pham, Chengming Zhou, Xunlei Pang, cgroups, linux-mm, linux-kernel On 9/11/26 6:34 AM, Andrew Morton wrote: > On Thu, 10 Sep 2026 16:07:18 +0800 Qinyun Tan <qinyuntan@linux.alibaba.com> wrote: > >> With cgroup.memory=nokmem, the THP deferred split shrinker and the >> zswap shrinker are degraded in two ways. >> >> First, both shrinkers are missing the SHRINKER_NONSLAB flag, so >> shrinker_memcg_alloc() demotes them to non-memcg-aware shrinkers: >> limit-induced reclaim of a cgroup neither splits its partially >> unmapped THPs nor writes back its zswapped pages. v1 of this series >> [1] restored the flag to fix that. >> >> However, as Sashiko's review of v1 pointed out [2], the flag alone >> is not enough. __list_lru_init() also collapses every list_lru into >> per-node lists under nokmem, so even with the flag restored, the >> objects of all cgroups share one list per node: the per-memcg >> shrinker bit is only set for whichever memcg happens to repopulate >> the empty list, so pressure in other cgroups may not even trigger >> the scan, and when it does, the scan walks everyone's objects. >> >> Before commit fafaeceb89a5 ("mm: switch deferred split shrinker to >> list_lru"), THP had fully per-memcg deferred split queues embedded >> in struct mem_cgroup, working independently of kmem accounting. >> nokmem only opts out of kernel slab accounting; THPs and zswapped >> pages are user memory and remain charged to their cgroups, so >> per-memcg reclaim is still what these shrinkers want. >> >> This series keeps list_lrus backed by SHRINKER_NONSLAB shrinkers >> memcg aware under nokmem: > > Thanks. > > It seems that Sashiko still doesn't understand that memory allocations > in __init code are considered "can't fail". > > https://sashiko.dev/#/patchset/20260910080722.3961351-1-qinyuntan@linux.alibaba.com > > otoh, failures in the functiond which hugepage_init() calls might be > caused by things other than ENOMEM so I guess we shouldn't zap all that > cleanup code. > > Anyway, that's unrelated to your changes. > > I'll save this patchset away for later and shall await reviewer input. > Please poke me in a week or so if there hasn't been any, Things are > crazy lately. Hi Andrew, Thanks for your time looking into this series. A gentle ping, as you suggested. Please let me know if anything else is needed from my side. Thanks, Qinyun Tan ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 0/4] mm: restore per-memcg reclaim for NONSLAB shrinkers under nokmem 2026-09-10 8:07 [PATCH v3 0/4] mm: restore per-memcg reclaim for NONSLAB shrinkers under nokmem Qinyun Tan ` (4 preceding siblings ...) 2026-09-10 22:34 ` [PATCH v3 0/4] mm: restore per-memcg reclaim for NONSLAB shrinkers under nokmem Andrew Morton @ 2026-09-23 1:35 ` Andrew Morton 2026-09-23 12:40 ` Michal Koutný 5 siblings, 1 reply; 10+ messages in thread From: Andrew Morton @ 2026-09-23 1:35 UTC (permalink / raw) To: Qinyun Tan Cc: Johannes Weiner, Michal Hocko, Roman Gushchin, Shakeel Butt, Muchun Song, Michal Koutný, David Hildenbrand, Zi Yan, Baolin Wang, Usama Arif, Dave Chinner, Qi Zheng, Yosry Ahmed, Nhat Pham, Chengming Zhou, Xunlei Pang, cgroups, linux-mm, linux-kernel On Thu, 10 Sep 2026 16:07:18 +0800 Qinyun Tan <qinyuntan@linux.alibaba.com> wrote: > With cgroup.memory=nokmem, the THP deferred split shrinker and the > zswap shrinker are degraded in two ways. Obvious question which may have recently been addressed: Why are we keeping nokmem around? How useful are its memory savings and is anyone actually using it? Clearly it isn't well tested and it increases our testing space (beyond out testing resources, apparently). If the right answer here is "kill it" then this patchset is introducing risk into the main codepaths in order to fix codepaths which shouldn't be there anyway, yes? ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 0/4] mm: restore per-memcg reclaim for NONSLAB shrinkers under nokmem 2026-09-23 1:35 ` Andrew Morton @ 2026-09-23 12:40 ` Michal Koutný 0 siblings, 0 replies; 10+ messages in thread From: Michal Koutný @ 2026-09-23 12:40 UTC (permalink / raw) To: Andrew Morton Cc: Qinyun Tan, Johannes Weiner, Michal Hocko, Roman Gushchin, Shakeel Butt, Muchun Song, David Hildenbrand, Zi Yan, Baolin Wang, Usama Arif, Dave Chinner, Qi Zheng, Yosry Ahmed, Nhat Pham, Chengming Zhou, Xunlei Pang, cgroups, linux-mm, linux-kernel [-- Attachment #1: Type: text/plain, Size: 831 bytes --] On Tue, Sep 22, 2026 at 06:35:47PM -0700, Andrew Morton <akpm@linux-foundation.org> wrote: > On Thu, 10 Sep 2026 16:07:18 +0800 Qinyun Tan <qinyuntan@linux.alibaba.com> wrote: > > > With cgroup.memory=nokmem, the THP deferred split shrinker and the > > zswap shrinker are degraded in two ways. > > Obvious question which may have recently been addressed: > > Why are we keeping nokmem around? How useful are its memory savings > and is anyone actually using it? Besides (not so significant) memory savings, there are also runtime savings (not spending time with accounting of each kernel allocation) and environmnents where shared (not)accounting of kernel objects is preferred (as other resources than memory are shared anyways). The above are IMO justifiable reasons and I know such users. HTH, Michal [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 265 bytes --] ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-09-26 20:30 UTC | newest] Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-09-10 8:07 [PATCH v3 0/4] mm: restore per-memcg reclaim for NONSLAB shrinkers under nokmem Qinyun Tan 2026-09-10 8:07 ` [PATCH v3 1/4] mm: memcontrol: drop kmemcg_id and use mem_cgroup_id() for list_lru indexing Qinyun Tan 2026-09-26 20:29 ` Kairui Song 2026-09-10 8:07 ` [PATCH v3 2/4] mm: list_lru: keep per-memcg lists with nokmem for NONSLAB-backed lrus Qinyun Tan 2026-09-10 8:07 ` [PATCH v3 3/4] mm: thp: restore SHRINKER_NONSLAB on the deferred split shrinker Qinyun Tan 2026-09-10 8:07 ` [PATCH v3 4/4] mm: zswap: mark the zswap shrinker SHRINKER_NONSLAB Qinyun Tan 2026-09-10 22:34 ` [PATCH v3 0/4] mm: restore per-memcg reclaim for NONSLAB shrinkers under nokmem Andrew Morton 2026-09-22 9:52 ` Qinyun Tan 2026-09-23 1:35 ` Andrew Morton 2026-09-23 12:40 ` Michal Koutný
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®