mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/4] memcg: move memcgid refcount to objcg to unpin dying memcgs
@ 2026-09-18  9:18 Bingfang Guo via B4 Relay
  2026-09-18  9:18 ` [PATCH 1/4] memcg: keep swap charging under RCU protection Bingfang Guo via B4 Relay
                   ` (3 more replies)
  0 siblings, 4 replies; 16+ messages in thread
From: Bingfang Guo via B4 Relay @ 2026-09-18  9:18 UTC (permalink / raw)
  To: Johannes Weiner, Michal Hocko, Roman Gushchin, Shakeel Butt,
	Muchun Song, Andrew Morton, Dave Chinner, Qi Zheng, Kairui Song,
	Barry Song, Axel Rasmussen, Yuanchu Xie, Wei Xu,
	David Hildenbrand, Lorenzo Stoakes, Bingfang Guo
  Cc: cgroups, linux-mm, linux-kernel, Bingfang Guo

Changes since RFC:
- Make the ID API symmetric: mem_cgroup_private_id_get() returns the ID
  and mem_cgroup_private_id_put() takes the ID. (Muchun Song)
- Drop the "take the ID only after the charge succeeded" and the
  dying-memcg walk-up in the swap charge path. (Muchun Song)
- Fold the list_lru / workingset / MGLRU NULL handling into the patch
  that moves the refcount, so the broken intermediate state is never
  introduced. (Muchun Song)
- Add obj_cgroup_from_private_id() and use it in the swap uncharge path,
  so the final put reuses the objcg that was already looked up instead
  of having the put helper return a memcg. (Muchun Song)
- Rename mem_cgroup->id_objcg to private_id_objcg, and make
  mem_cgroup->private_id an unsigned short. (Muchun Song)
- Require the caller to hold the RCU read lock in the ID helpers instead
  of taking it inside them. (Muchun Song)
- Add mem_cgroup_private_id_is_root() and decide whether a swap entry
  carries a counter charge from the ID's root status instead of the
  resolved memcg's, which keeps charge and uncharge symmetric after
  reparenting.
- Reorder and merge commits; the series is now four patches.
- Link to RFC v2: https://lore.kernel.org/r/20260901-bingfangguo-memcgid-rework-v2-0-8edd7f7a7251@tencent.com

Although the dying memcg problem caused by LRU pages is fixed, I can
still see many dying memcgs on some workloads that use shmem and those
pages are swapped out. For example, programs populating logs to tmpfs or
containers sharing data using shmem.  This series binds the memcgid
refcount to objcgs so dying memcgs can be freed normally in this case.

The memcg private ID identifies memcgs for objects that can outlive the
cgroup itself: swap entries and workingset shadows.  Today the ID's
refcount is embedded in the css, and every outstanding ID reference
(mostly swap entries) pins the css, keeping the entire memcg alive,
which brings a problem: A swapped-out page holds a memcgid reference
that pins the css, so the memcg cannot be freed until the page is
swapped back in and charged back to its online parent.

The work done by Muchun Song and Qi Zheng already charges folios to the
objcg, which is reparented to its parent when the memcg offlines.  This
series applies similar idea to the memcg private ID: the ID's refcount
moves from the css into the objcg, and the memcgid xarray holds a
reference to an objcg instead of pinning the css.  When the memcg
offlines, the objcg is reparented and any remaining memcgid references
resolve to the ancestor, so swapped-out pages no longer pin the dying
memcg and get the online parent naturally on swapin.

Unbinding the ID from the memcg has three consequences the series has to
deal with:

  1. The ID stops pinning the memcg, so the paths that relied on the ID
     reference to keep the memcg alive have to hold the RCU read lock
     instead.  (Patch 1.)

  2. Charge and uncharge no longer necessarily happen on the same memcg:
     swapout charges the folio's memcg, while the slot free resolves the
     nearest live ancestor.  The counters are hierarchical, and the
     MEMCG_SWAP stat is either reparented at offline (v1) or not visible
     (v2), so nothing leaks.  But "does this entry carry a counter
     charge at all" can no longer be answered from the resolved memcg:
     root is skipped only because root's swap is not accounted, and a
     non-root ID whose memcg was reparented into root still carries a
     charge that must be released.  Patch 2 adds
     mem_cgroup_private_id_is_root() and makes all three swap paths
     decide on the ID's root status.

  3. An ID can now outlive the memcg it was allocated to, so the memcg
     resolved from an ID is not necessarily the memcg the ID was handed
     out for.  Callers that need exactly that memcg (list_lru, the
     workingset and MGLRU shadow tests) now get NULL and skip the entry,
     while the swap paths, which only need something to account to, get
     the nearest live ancestor.  (Patch 4.)

The series is now four patches:

  memcg: keep swap charging under RCU protection
  memcg: base swap charge accounting on memcgid root status
  memcg: manipulate memcg private ID references by ID
  memcg: move memcg private ID refcount to objcg

Only the last patch changes behavior.  The first three are preparation
that keeps today's semantics while the ID is still bound to the css.

RFC v1 contains some scripts and codes for reproducing the problem and
testing the fix.

** Changelogs **

Changes in RFC v2:
- Rework the logic to try to keep changes small.
- Change order of the commits to make it cleaner.
- Fix problems reported by sashiko.
- Reparent to mm-unstable.
- Link to RFC v1: https://lore.kernel.org/r/20260813-memcgid-objcg-v1-0-83d21c685b77@tencent.com

Signed-off-by: Bingfang Guo <bingfangguo@tencent.com>
---
Bingfang Guo (4):
      memcg: keep swap charging under RCU protection
      memcg: base swap charge accounting on memcgid root status
      memcg: manipulate memcg private ID references by ID
      memcg: move memcg private ID refcount to objcg

 include/linux/memcontrol.h |   9 ++--
 mm/list_lru.c              |   2 +-
 mm/memcontrol-v1.c         |  21 ++++-----
 mm/memcontrol-v1.h         |   8 +++-
 mm/memcontrol.c            | 111 ++++++++++++++++++++++++++++++++++-----------
 mm/workingset.c            |   5 +-
 6 files changed, 110 insertions(+), 46 deletions(-)
---
base-commit: 27e4e1835109ef599d72abe6c09711e0b1916033
change-id: 20260827-bingfangguo-memcgid-rework-938e25ecaba2

Best regards,
-- 
Bingfang Guo <bingfangguo@tencent.com>



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

end of thread, other threads:[~2026-09-19  3:32 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-18  9:18 [PATCH 0/4] memcg: move memcgid refcount to objcg to unpin dying memcgs Bingfang Guo via B4 Relay
2026-09-18  9:18 ` [PATCH 1/4] memcg: keep swap charging under RCU protection Bingfang Guo via B4 Relay
2026-09-18 12:07   ` Muchun Song
2026-09-18 16:46   ` Shakeel Butt
2026-09-18 17:51     ` Bingfang Guo
2026-09-18  9:18 ` [PATCH 2/4] memcg: base swap charge accounting on memcgid root status Bingfang Guo via B4 Relay
2026-09-19  2:56   ` Muchun Song
2026-09-18  9:18 ` [PATCH 3/4] memcg: manipulate memcg private ID references by ID Bingfang Guo via B4 Relay
2026-09-18 18:14   ` Shakeel Butt
2026-09-18 18:46     ` Bingfang Guo
2026-09-18 20:24       ` Shakeel Butt
2026-09-19  3:06   ` Muchun Song
2026-09-18  9:18 ` [PATCH 4/4] memcg: move memcg private ID refcount to objcg Bingfang Guo via B4 Relay
2026-09-18 18:19   ` Shakeel Butt
2026-09-18 19:14     ` Bingfang Guo
2026-09-19  3:32   ` Muchun Song

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®