[PATCH v3 4/4] memcg-v1: bail out reclaim when memcg is dying
From: Jiayuan Chen
Date: Thu Jul 02 2026 - 08:14:33 EST
From: Jiayuan Chen <jiayuan.chen@xxxxxxxxxx>
The legacy memory.limit_in_bytes and memory.memsw.limit_in_bytes writers
retry page_counter_set_max() by reclaiming synchronously in the writer
context. memory.force_empty similarly loops in synchronous reclaim until
the cgroup is empty or reclaim stops making progress.
These writes hold a kernfs active reference on the file. If cgroup removal
starts in parallel, the remover sets CSS_DYING and then waits in
kernfs_drain() under cgroup_mutex for the active reference to drain.
Continuing reclaim after the memcg is dying can therefore delay cgroup
removal and keep cgroup_mutex held for a long time.
Stop the v1 reclaim loops once the memcg is dying. For limit resizing,
keep the existing -EBUSY semantics when the new limit could not be
installed. For memory.force_empty, keep the existing best-effort success
semantics.
Cc: Jiayuan Chen <jiayuan.chen@xxxxxxxxx>
Reported-by: Zhou Yingfu <yingfu.zhou@xxxxxxxxxx>
Acked-by: Johannes Weiner <hannes@xxxxxxxxxxx>
Signed-off-by: Jiayuan Chen <jiayuan.chen@xxxxxxxxxx>
---
mm/memcontrol-v1.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/mm/memcontrol-v1.c b/mm/memcontrol-v1.c
index 765069211567..b868a58c52b8 100644
--- a/mm/memcontrol-v1.c
+++ b/mm/memcontrol-v1.c
@@ -1513,6 +1513,10 @@ static int mem_cgroup_resize_max(struct mem_cgroup *memcg,
if (!ret)
break;
+ /* cgroup_rmdir() waits for us with cgroup_mutex held. */
+ if (memcg_is_dying(memcg))
+ break;
+
if (!drained) {
drain_all_stock(memcg);
drained = true;
@@ -1551,6 +1555,10 @@ static int mem_cgroup_force_empty(struct mem_cgroup *memcg)
if (signal_pending(current))
return -EINTR;
+ /* cgroup_rmdir() waits for us with cgroup_mutex held. */
+ if (memcg_is_dying(memcg))
+ break;
+
if (!try_to_free_mem_cgroup_pages(memcg, 1, GFP_KERNEL,
MEMCG_RECLAIM_MAY_SWAP, NULL))
nr_retries--;
--
2.43.0