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 Suggested-by: Nhat Pham Signed-off-by: Alexandre Ghiti --- 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