[PATCH] mm: list_lru: clear shrinker id when disabling memcg awareness

Wentao Guan posted 1 patch 3 weeks ago
mm/list_lru.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
[PATCH] mm: list_lru: clear shrinker id when disabling memcg awareness
Posted by Wentao Guan 3 weeks ago
When cgroup.memory=nokmem is in effect, __list_lru_init() disables
memcg awareness for the list_lru, but it leaves lru->shrinker_id copied
from the supplied shrinker.

This used to be mostly harmless for memcg-aware slab list_lrus because,
with kmem accounting disabled, slab objects are not charged to memcgs and
list_lru_add_obj() passes NULL memcgs. The THP deferred split conversion
changed that: it initializes a memcg-aware list_lru with the THP shrinker
and later adds anon THPs with the folio memcg, even when kmem accounting
is disabled. The list_lru itself has been collapsed to plain per-node
lists, but the stale shrinker id still makes __list_lru_add() call
set_shrinker_bit().

This was reproduced on a kernel with CONFIG_MEMCG=y and
CONFIG_TRANSPARENT_HUGEPAGE=y, booted with kernel memory accounting
disabled. The same condition can be reproduced by booting with:

  cgroup.memory=nokmem

and then faulting in anonymous THPs so that they are queued on the THP
deferred split list_lru. The warning showed that the memcg had no kmem id
and no memcg shrinker bitmap capacity, while the list_lru still carried a
valid shrinker id:

  set_shrinker_bit: memcg=ffff8d23cbe60000 css_id=31 kmem_id=-1 \
    dying=0 nid=0 shrinker_id=0 shrinker_nr_max=0 map_nr_max=0 \
    info=ffff8d23d68c60c0
  WARNING: mm/shrinker.c:218 at set_shrinker_bit+0xdb/0x100

The stack was:

  set_shrinker_bit
  __list_lru_add
  deferred_split_folio
  map_anon_folio_pmd_nopf
  map_anon_folio_pmd_pf
  __do_huge_pmd_anonymous_page
  do_huge_pmd_anonymous_page
  __handle_mm_fault
  handle_mm_fault
  do_user_addr_fault
  exc_page_fault
  asm_exc_page_fault

The list_lru code already uses shrinker_id == -1 as the sentinel that
prevents set_shrinker_bit() from doing any memcg bitmap operation. Keep
that invariant when memcg awareness is forced off due to disabled kmem
accounting.

This is related to the cgroup_disable=memory case fixed by Qinyun Tan,
where __list_lru_init() also needs to collapse list_lrus to plain
per-node lists when the memory controller is disabled entirely. That
patch makes the memcg awareness decision complete; this patch keeps the
shrinker id in sync with that decision.

Link: https://lore.kernel.org/linux-mm/20260902093202.609559-1-qinyuntan@linux.alibaba.com/
Fixes: fafaeceb89a5 ("mm: switch deferred split shrinker to list_lru")
Assisted-by: atomcode:gpt-5.5-medium
Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
---
 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 36662d02ff963..c08a5e2367106 100644
--- a/mm/list_lru.c
+++ b/mm/list_lru.c
@@ -671,8 +671,10 @@ int __list_lru_init(struct list_lru *lru, bool memcg_aware, struct shrinker *shr
 	else
 		lru->shrinker_id = -1;
 
-	if (mem_cgroup_kmem_disabled())
+	if (mem_cgroup_kmem_disabled()) {
 		memcg_aware = false;
+		lru->shrinker_id = -1;
+	}
 #endif
 
 	lru->node = kzalloc_objs(*lru->node, nr_node_ids);
-- 
2.30.2
Re: [PATCH] mm: list_lru: clear shrinker id when disabling memcg awareness
Posted by Wentao Guan 3 weeks ago
Hi All,

I never noticed the patch in maillist
("mm/list_lru: don't copy stale shrinker id from non-memcg-aware shrinkers")
before, the patch is better than me, so just ignore the patch.

Link: https://lore.kernel.org/linux-mm/20260901115104.2944996-1-qinyuntan@linux.alibaba.com/

BRs
Wentao Guan