Skip to content

make unused huge shrinker memcg aware

Qi Zheng linux-mm lkml 4 versions – Applied

Status from this message: [merged mm-stable] mm-shmem-make-unused-huge-shrinker-memcg-aware.patch removed from -mm tree

Get series with b4
b4 am [email protected]

Versions newest first · linked by author and title

  1. v4 Latest4 patches 12 repliesApplied 4/4
  2. v33 patches 10 repliesSuperseded
  3. v22 patches 5 repliesSuperseded
Earlier versions · 1
VersionPostedPatchesRepliesStatus
v11 patch8 repliesSuperseded

Changes in v4 from the cover letter

- add [PATCH v4 2/4] to make obj_cgroup_memcg() handle NULL objcg
- store obj_cgroup instead of mem_cgroup in shmem_inode_info to avoid pinning a dying memcg through a long-lived CSS reference (pointed by sashiko)
- fix is_shmem_unused_huge_match() to always check the NUMA node for shrinker reclaim, not only for non-root memcg reclaim (pointed by sashiko)
- collect Reviewed-by
- rebase onto the next-20260814

Patches in v4 All 4 applied

#Subject and filesSizeRepliesApplied
1/4fs: fix missed removal of super_fs_objects_eligible()fs/super.c+2 -167 repliesApplied
2/4mm: memcontrol: make obj_cgroup_memcg() handle NULL objcginclude/linux/memcontrol.h mm/page_owner.c mm/zswap.c+11 -192 repliesApplied
3/4mm: shmem: move unused huge shrinklist queuing past the truncation checkmm/shmem.c+27 -210 repliesApplied
4/4mm: shmem: make unused huge shrinker memcg awareinclude/linux/shmem_fs.h mm/shmem.c+289 -851 replyApplied

Reviews trailers per patch

All 4 patches have a Reviewed-by or Acked-by.

PatchBaolin WangShakeel ButtUsama Arif
1/4A-b
2/4A-b
3/4R-b
4/4R-b

Trailers given in replies are filled; those carried in the patches from earlier versions are outlined with dashes. Scroll the table sideways for all 3 reviewers.

Read the v4 thread

Cover letter [PATCH v4 0/4] make unused huge shrinker memcg aware

From: Qi Zheng <[email protected]>

Changes in v4:
- add [PATCH v4 2/4] to make obj_cgroup_memcg() handle NULL objcg
- store obj_cgroup instead of mem_cgroup in shmem_inode_info to avoid pinning a dying memcg through a long-lived CSS reference (pointed by sashiko)
- fix is_shmem_unused_huge_match() to always check the NUMA node for shrinker reclaim, not only for non-root memcg reclaim (pointed by sashiko)
- collect Reviewed-by
- rebase onto the next-20260814

Note: [PATCH v4 1/4] should ideally be folded into commit 0ef8faff490be ("fs: push nr_cached_objects memcg gating into individual filesystems") in linux-next.

Changes in v3:
- add a fix patch to fix missed removal of super_fs_objects_eligible()
- move the original shrinklist addition logic after all checks are completed, and split it into a separate patch. (suggested by Baolin)
- simplify the shmem_unused_huge_requeue() (suggested by Baolin)
- keep the move_back label in shmem_unused_huge_shrink() (suggested by Baolin)
- rebase onto the next-20260731

Changes in v2:
- temporarily add the dependent patch from Usama to the series for review convenience
- remove shrinklist_scan and shrinklist_isolated from struct shmem_inode_info, and re-implement the logic by resuing the same info->shrinklist (suggested by Baolin)
- add more comments (suggested by Andrew)
- fix missing initialization of info->shrinklist_memcg (pointed by sashiko)
- rebase onto the next-20260717

Hi all,

The shmem unused huge shrinker maintains a per-superblock list of inodes whose tail huge folio extends beyond i_size. Because this list is not memcg aware, reclaim triggered by memcg A can scan inodes across the entire superblock and split huge folios charged to unrelated memcg B, causing unexpected impact on it.

In the worst case, memcg A has no reclaimable shmem at all, making the reclaim entirely useless and incurring unnecessary latency. We observed this in production, where page lock contention during split caused multi-hundred-millisecond stalls:

tid 11340 comm scanner locked a page for 182264 us! kstack:

          unlock_page+1
          split_huge_page_to_list+3135
          shmem_unused_huge_shrink+767
          super_cache_scan+329
          do_shrink_slab+291
          shrink_slab+533
          shrink_node+400
          do_try_to_free_pages+206
          try_to_free_mem_cgroup_pages+262
          try_charge_memcg+591
          mem_cgroup_charge+136
          __handle_mm_fault+2431
          handle_mm_fault+194
          do_user_addr_fault+462
          __do_page_fault+176
          do_page_fault+48
          page_fault+62

Usama's recent patch [1] prevents the shmem unused shrinker from being invoked during memcg-level reclaim altogether, but this is overly
conservative: we can do better by reclaiming only the shmem charged to the reclaiming memcg.

This series converts the shrinker list to a memcg-aware list_lru, so that non-root memcg reclaim walks only candidates charged to the reclaiming memcg. Global reclaim, root memcg reclaim and shmem quota reclaim retain their existing global semantics.

To avoid pinning a dying memcg through a long-lived CSS reference, each inode stores an obj_cgroup reference instead of a mem_cgroup reference. The list_lru add/delete paths resolve the current memcg from the objcg under RCU, staying consistent with list_lru's own memcg migration on offline.

Thanks,
Qi

[1]. https://lore.kernel.org/all/[email protected]/

Qi Zheng (4):
fs: fix missed removal of super_fs_objects_eligible()
mm: memcontrol: make obj_cgroup_memcg() handle NULL objcg
mm: shmem: move unused huge shrinklist queuing past the truncation
check
mm: shmem: make unused huge shrinker memcg aware

 fs/super.c                 |  18 +-
 include/linux/memcontrol.h |  11 +-
 include/linux/shmem_fs.h   |  12 +-
 mm/page_owner.c            |   2 +-
 mm/shmem.c                 | 382 ++++++++++++++++++++++++++++---------
 mm/zswap.c                 |  17 +-
 6 files changed, 315 insertions(+), 127 deletions(-)
Signature · 1 line
2.54.0