[PATCH] mm/vmscan: skip lazyfree folios when demoting in shrink_folio_list()
From: Bing Jiao
Date: Tue Nov 03 2026 - 19:24:39 EST
shrink_folio_list() currently demotes lazyfree (MADV_FREE) folios to
lower-tier memory instead of discarding them. In the earlier patch
series [1] that commit 26aa2d199d6f ("mm/migrate: demote pages during
reclaim") was based on, demotion was inside the PageAnon(page) &&
PageSwapBacked(page) block with a comment to skip MADV_FREE pages. When
that commit moved do_demote_pass above the block to also demote file
pages, the PageSwapBacked check excluding lazyfree pages was dropped.
Demoting lazyfree folios during reclaim does not make sense. Userspace
already marked the contents as discardable under memory pressure. Even
if MADV_FREE is treated as a cache to avoid page allocation and zeroing,
folios in shrink_folio_list() have already aged to the tail of the
inactive LRU, and demoting them still allocates a new page on the lower
tier, copies stale data, and unmaps the PTE.
Skip folio_test_lazyfree(folio) in the do_demote_pass check so lazyfree
folios proceed to the normal reclaim path in shrink_folio_list().
Link: https://lore.kernel.org/r/1560468577-101178-6-git-send-email-yang.shi@xxxxxxxxxxxxxxxxx [1]
Signed-off-by: Bing Jiao <bingjiao@xxxxxxxxxx>
---
Note: An earlier RFC ("mm: Discard lazily freed pages when migrating",
https://lore.kernel.org/r/20200228033819.3857058-1-ying.huang@xxxxxxxxx)
proposed discarding clean MADV_FREE pages inside try_to_unmap_one() for
all migrate_pages() callers. Reviewers pushed back there because
non-reclaim migrations (compaction, move_pages(), NUMA balancing) happen
without memory pressure, when MADV_FREE pages are expected to stay
around for reuse. This patch leaves migrate_pages() alone and only skips
demotion in shrink_folio_list(), where the folio is already being
evicted.
mm/vmscan.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 7db6be53f3a9..47448c47fc04 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1347,8 +1347,9 @@ static unsigned int shrink_folio_list(struct list_head *folio_list,
/*
* Before reclaiming the folio, try to relocate
* its contents to another node.
+ * Skip lazyfree folios so they can be reclaimed directly.
*/
- if (do_demote_pass &&
+ if (do_demote_pass && !folio_test_lazyfree(folio) &&
(thp_migration_supported() || !folio_test_large(folio))) {
list_add(&folio->lru, &demote_folios);
folio_unlock(folio);
--
2.56.0.455.g6c5a503b38-goog