[PATCH v2] mm: vmscan: don't count per-node proactive reclaim as memory pressure

From: Vernon Yang

Date: Sun Oct 11 2026 - 22:29:50 EST


From: Vernon Yang <yanglincheng@xxxxxxxxxx>

When the cgroup has no memory pressure at all, writing to
/sys/devices/system/nodeX/reclaim triggers proactive reclaim on
NUMA node, causing increase in the writer cgroup's memory PSI.

Due to this reclaim is performed in the context of the write(),
accounted as memory pressure on the writer, like
commit e22c6ed90aa9 ("mm: memcontrol: don't count limit-setting reclaim
as memory pressure"). This is unexpected, the similar scenarios (e.g.
senpai) will continue to occur, only this time it is for the
/sys/devices/system/nodeX/reclaim knob.

The Documentation/ABI/stable/sysfs-devices-node documentation also
notes that "This interface is equivalent to the memcg variant."

This patch unifies the semantics of the memcg and node interfaces:
per-node proactive reclaim is no longer counted as memory pressure,
and the per-node proactive reclaim interface no longer produces
phantom pressure.

I ran demo[1] that performs per-node proactive reclaim 10000 times
in qemu, writer cgroup memory.pressure as follows:

without patch:

some avg10=31.53 avg60=13.42 avg300=3.31 total=10602985
full avg10=31.53 avg60=13.42 avg300=3.31 total=10602985

with patch:

some avg10=9.59 avg60=3.41 avg300=0.81 total=2686221
full avg10=9.59 avg60=3.41 avg300=0.81 total=2686221

[1] https://github.com/vernon2gh/app_and_module/tree/main/reclaim_node_psi

Fixes: b980077899ea ("mm: introduce per-node proactive reclaim interface")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Vernon Yang <yanglincheng@xxxxxxxxxx>
---
V1 -> V2:
- Check `sc->proactive` to differentiate between proactive reclaim or
page allocation. (Thanks Barry)

V1 : https://lore.kernel.org/linux-mm/20261005062236.564210-1-vernon2gm@xxxxxxxxx/
---
mm/vmscan.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/mm/vmscan.c b/mm/vmscan.c
index 91295070ca33..2e9ca5e4c741 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -7994,7 +7994,8 @@ static unsigned long __node_reclaim(struct pglist_data *pgdat,
sc->gfp_mask);

cond_resched();
- psi_memstall_enter(&pflags);
+ if (!sc->proactive)
+ psi_memstall_enter(&pflags);
delayacct_freepages_start();
fs_reclaim_acquire(sc->gfp_mask);
/*
@@ -8011,7 +8012,8 @@ static unsigned long __node_reclaim(struct pglist_data *pgdat,
memalloc_noreclaim_restore(noreclaim_flag);
fs_reclaim_release(sc->gfp_mask);
delayacct_freepages_end();
- psi_memstall_leave(&pflags);
+ if (!sc->proactive)
+ psi_memstall_leave(&pflags);

trace_mm_vmscan_node_reclaim_end(sc->nr_reclaimed, NULL);

--
2.53.0