[PATCH mm-new v1 0/2] mm: vmscan: skip anon folios zswap would refuse when writeback is off

From: Jiayuan Chen

Date: Fri Oct 30 2026 - 05:54:38 EST


memory.zswap.writeback=0 is what we set for latency sensitive services:
their cold anon pages may go to zswap, but never to disk, a swapin
from disk is a latency spike they cannot afford. Such a memcg can only
swap into zswap. When zswap stops taking its pages, because the pool
hit max_pool_percent or the memcg hit memory.zswap.max, reclaim still
goes through the motions on its anon LRU: every folio it picks gets a
swap slot, is unmapped, is refused by zswap_store() and is activated
again. Nothing is freed, the folio now sits in the swap cache holding
a slot, and the owner takes a minor fault on the next access.

memory.reclaim below is just the easiest way to trigger it. The same
loop runs whenever the memcg is reclaimed: when it hits memory.max, or
when kswapd walks it under node pressure. Neither is something the
service can opt out of.

Patch 1 is a refactor so the memcg zswap check can be reused from
reclaim. Patch 2 adds the check to shrink_folio_list(). It cannot go
into can_reclaim_anon_pages(): zero-filled folios never reach zswap
and must stay reclaimable.

Numbers from a 16-CPU, 32G QEMU guest on mm-new, zswap with
max_pool_percent=2 (~640M), a memcg with memory.zswap.writeback=0
holding 3G of 2:1 compressible anon. The pool fills up after ~300k
pages. Then 5 x "echo 512M > memory.reclaim", and the task walks its
3G once:

minor faults on the walk
MGLRU classic LRU
before 786,454 786,452
after 301,168 301,158

The ~300k after the patch are the pages that really are in zswap
(stored_pages was 301,133 / 301,165), swapped back in once each. The
other ~485k before the patch are pages zswap refused: unmapped, left
in the swap cache, mapped again on the next touch.

Jiayuan Chen (2):
mm: memcontrol: split mem_cgroup_may_zswap() out of
obj_cgroup_may_zswap()
mm: vmscan: skip anon folios zswap would refuse when writeback is off

include/linux/memcontrol.h | 5 +++++
include/linux/zswap.h | 5 +++++
mm/memcontrol.c | 26 ++++++++++++++++++--------
mm/page_io.c | 15 ++++++++++++++-
mm/swap.h | 12 ++++++++++++
mm/vmscan.c | 17 +++++++++++++++++
mm/zswap.c | 11 +++++++++++
7 files changed, 82 insertions(+), 9 deletions(-)

--
2.43.0