[PATCH v2 3/3] mm: zswap: drop cold writeback folios via swap dropbehind

From: Alexandre Ghiti

Date: Mon Jul 27 2026 - 10:50:02 EST


zswap writeback decompresses an entry into a fresh swap cache folio and
writes it back. The folio is cold by construction, yet it is left on the
LRU for reclaim to find and free later, wasting a reclaim scan and keeping
cold memory resident longer than necessary.

Allocate the folio off the LRU and drop it as soon as writeback completes:
mark it PG_dropbehind so the swap dropbehind path frees it once writeback
ends. Synchronous-IO devices complete writeback in this context, so there
the folio is dropped inline instead.

Suggested-by: Johannes Weiner <hannes@xxxxxxxxxxx>
Suggested-by: Nhat Pham <nphamcs@xxxxxxxxx>
Signed-off-by: Alexandre Ghiti <alex@xxxxxxxx>
---
mm/zswap.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/mm/zswap.c b/mm/zswap.c
index 8163e6c5f76c..e37828e02938 100644
--- a/mm/zswap.c
+++ b/mm/zswap.c
@@ -992,6 +992,7 @@ static int zswap_writeback_entry(struct zswap_entry *entry,
struct folio *folio;
struct mempolicy *mpol;
struct swap_info_struct *si;
+ bool sync;
int ret = 0;

/* try to allocate swap cache folio */
@@ -999,6 +1000,8 @@ static int zswap_writeback_entry(struct zswap_entry *entry,
if (!si)
return -EEXIST;

+ sync = data_race(si->flags & SWP_SYNCHRONOUS_IO);
+
mpol = get_task_policy(current);
folio = __swap_cache_alloc_folio(swpentry, GFP_KERNEL, BIT(0), NULL, mpol,
NO_INTERLEAVE_INDEX);
@@ -1013,7 +1016,6 @@ static int zswap_writeback_entry(struct zswap_entry *entry,
*/
if (IS_ERR(folio))
return PTR_ERR(folio);
- folio_add_lru(folio);

/*
* folio is locked, and the swapcache is now secured against
@@ -1046,12 +1048,17 @@ static int zswap_writeback_entry(struct zswap_entry *entry,
/* folio is up to date */
folio_mark_uptodate(folio);

- /* move it to the tail of the inactive list after end_writeback */
- folio_set_reclaim(folio);
+ if (!sync)
+ folio_set_dropbehind(folio);

/* start writeback */
__swap_writepage(folio, NULL);

+ if (sync) {
+ swap_dropbehind_free_one_folio(folio);
+ return 0;
+ }
+
out:
if (ret) {
swap_cache_del_folio(folio);
--
2.53.0-Meta