include/linux/zswap.h | 2 ++ mm/filemap.c | 20 +++++++++++++ mm/swap.h | 3 +- mm/swap_state.c | 17 +++++++---- mm/zswap.c | 66 +++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 98 insertions(+), 10 deletions(-)
When zswap writes an entry back, it allocates an order-0 swap cache folio,
decompresses into it, and issues the write. The folio is cold by
construction, yet today it is left on the LRU for page reclaim to find and
free later. That wastes a reclaim scan and keeps cold memory resident
longer than necessary.
Free the folio as soon as writeback completes instead:
Patch 1 - synchronous-IO devices (zram, brd, pmem, ...) complete writeback
in the calling context, so the folio is freed directly there.
Patch 2 - asynchronous block devices and filesystem-backed swap complete
writeback in IRQ/softirq context, where the folio cannot be
freed (that needs the folio and swap cluster locks and may
sleep). Allocate the folio off the LRU and defer the free to a
workqueue, which folio_end_writeback() hands it off to.
Results
-------
Paired baseline vs series on async swap (NVMe, Patch 2 deferred path). Each
workload runs confined to a memory cgroup (memory.max) small enough to force
zswap shrinker writeback.
Kernel build (defconfig, make -j4; memory.max = 600M):
metric baseline series delta
pgrotated 441028 2521 -99.4%
pgsteal_direct 3524343 2869004 -18.6%
pgscan_direct 8393791 7765008 -7.5%
zswpwb 705129 699019 -0.9%
build time (s) 1155 1114 -3.6%
Of the 699019 folios written back, 698990 (99.996%) were freed promptly on
writeback completion; only 28 fell back to reclaim.
MySQL/OLTP (sysbench, 10 tables x 1M rows, 512M buffer pool, 8 threads, 300s;
memory.max = 256M):
metric baseline series delta
transactions/s 153.87 163.30 +6.1%
p95 latency (ms) 157.42 145.82 -7.4%
avg latency (ms) 52.09 49.05 -5.9%
pgrotated 743738 22460 -97.0%
pgsteal_direct 6886490 5445278 -20.9%
pgscan_direct 13462510 10820730 -19.6%
Alexandre Ghiti (2):
mm: zswap: free synchronous-IO writeback folios directly
mm: zswap: deferred dropbehind free of writeback folios
include/linux/zswap.h | 2 ++
mm/filemap.c | 20 +++++++++++++
mm/swap.h | 3 +-
mm/swap_state.c | 17 +++++++----
mm/zswap.c | 66 +++++++++++++++++++++++++++++++++++++++++--
5 files changed, 98 insertions(+), 10 deletions(-)
base-commit: 626acb37cd445144f321f1b64cac9a93760fa716
--
2.53.0-Meta
On Sat, Jul 18, 2026 at 2:37 AM Alexandre Ghiti <alex@ghiti.fr> wrote: > > When zswap writes an entry back, it allocates an order-0 swap cache folio, > decompresses into it, and issues the write. The folio is cold by > construction, yet today it is left on the LRU for page reclaim to find and > free later. That wastes a reclaim scan and keeps cold memory resident > longer than necessary. > > Free the folio as soon as writeback completes instead: > > Patch 1 - synchronous-IO devices (zram, brd, pmem, ...) complete writeback > in the calling context, so the folio is freed directly there. > > Patch 2 - asynchronous block devices and filesystem-backed swap complete > writeback in IRQ/softirq context, where the folio cannot be > freed (that needs the folio and swap cluster locks and may > sleep). Allocate the folio off the LRU and defer the free to a > workqueue, which folio_end_writeback() hands it off to. I took a quick look through the patches and the implementation seems too zswap-specific. I am not super familiar with how the drop-behind mechanism works in general, but it seems like it's currently intended for file pages and not swap-backed pages. From a high-level perspective, it seems like we should add support for swap dropbehind in general first (regardless of zswap), e.g. by making folio_end_dropbehind() properly handle them, and then have zswap opt into this? I guess one of the challenges is that folio_end_dropbehind() only frees folios in task context while we need to support interrupt context, but this also doesn't seem like something that should be handled in zswap. In theory, there may be a use case for doing dropbehind for swap in general, right?
Hi Yosry, On Mon, Jul 20, 2026 at 8:26 PM Yosry Ahmed <yosry@kernel.org> wrote: > > > > On Sat, Jul 18, 2026 at 2:37 AM Alexandre Ghiti <alex@ghiti.fr> wrote: > > > > When zswap writes an entry back, it allocates an order-0 swap cache folio, > > decompresses into it, and issues the write. The folio is cold by > > construction, yet today it is left on the LRU for page reclaim to find and > > free later. That wastes a reclaim scan and keeps cold memory resident > > longer than necessary. > > > > Free the folio as soon as writeback completes instead: > > > > Patch 1 - synchronous-IO devices (zram, brd, pmem, ...) complete writeback > > in the calling context, so the folio is freed directly there. > > > > Patch 2 - asynchronous block devices and filesystem-backed swap complete > > writeback in IRQ/softirq context, where the folio cannot be > > freed (that needs the folio and swap cluster locks and may > > sleep). Allocate the folio off the LRU and defer the free to a > > workqueue, which folio_end_writeback() hands it off to. > > I took a quick look through the patches and the implementation seems > too zswap-specific. > > I am not super familiar with how the drop-behind mechanism works in > general, but it seems like it's currently intended for file pages and > not swap-backed pages. From a high-level perspective, it seems like we > should add support for swap dropbehind in general first (regardless of > zswap), e.g. by making folio_end_dropbehind() properly handle them, > and then have zswap opt into this? > > I guess one of the challenges is that folio_end_dropbehind() only > frees folios in task context while we need to support interrupt > context, but this also doesn't seem like something that should be > handled in zswap. > > In theory, there may be a use case for doing dropbehind for swap in > general, right? > Yes, you're right, I have been focused on zswap here but that should be extended to swap in general. I only have performance numbers for zswap though, so I need to verify the impact on swap in general first. Thanks, Alex
© 2016 - 2026 Red Hat, Inc.