public inbox for linux-mm@kvack.org
 help / color / mirror / Atom feed
* [PATCH v3] mm: migrate: requeue destination folio on deferred split queue
@ 2026-03-12 10:47 Usama Arif
  2026-03-12 14:27 ` Johannes Weiner
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Usama Arif @ 2026-03-12 10:47 UTC (permalink / raw)
  To: Andrew Morton, npache, david, ziy, willy, linux-mm
  Cc: matthew.brost, joshua.hahnjy, hannes, rakie.kim, byungchul,
	gourry, ying.huang, apopple, linux-kernel, kernel-team,
	richard.weiyang, Usama Arif

During folio migration, __folio_migrate_mapping() removes the source
folio from the deferred split queue, but the destination folio is never
re-queued.  This causes underutilized THPs to escape the shrinker after
NUMA migration, since they silently drop off the deferred split list.

Fix this by recording whether the source folio was on the deferred split
queue and its partially mapped state before move_to_new_folio() unqueues
it, and re-queuing the destination folio after a successful migration if
it was.

By the time migrate_folio_move() runs, partially mapped folios without a
pin have already been split by migrate_pages_batch().  So only two cases
remain on the deferred list at this point:
  1. Partially mapped folios with a pin (split failed).
  2. Fully mapped but potentially underused folios.
The recorded partially_mapped state is forwarded to deferred_split_folio()
so that the destination folio is correctly re-queued in both cases.

Reported-by: Johannes Weiner <hannes@cmpxchg.org>
Fixes: dafff3f4c850 ("mm: split underused THPs")
Acked-by: Zi Yan <ziy@nvidia.com>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Usama Arif <usama.arif@linux.dev>
---
v2 -> v3:
- Remove redundant folio_test_large_rmappable() check (David).
- Check order > 1 (replaced folio_test_large()) (Wei Yang)
---
 mm/migrate.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/mm/migrate.c b/mm/migrate.c
index ece77ccb2ec0..f5169a9f8f24 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -1360,6 +1360,8 @@ static int migrate_folio_move(free_folio_t put_new_folio, unsigned long private,
 	int rc;
 	int old_page_state = 0;
 	struct anon_vma *anon_vma = NULL;
+	bool src_deferred_split = false;
+	bool src_partially_mapped = false;
 	struct list_head *prev;
 
 	__migrate_folio_extract(dst, &old_page_state, &anon_vma);
@@ -1373,6 +1375,12 @@ static int migrate_folio_move(free_folio_t put_new_folio, unsigned long private,
 		goto out_unlock_both;
 	}
 
+	if (folio_order(src) > 1 &&
+	    !data_race(list_empty(&src->_deferred_list))) {
+		src_deferred_split = true;
+		src_partially_mapped = folio_test_partially_mapped(src);
+	}
+
 	rc = move_to_new_folio(dst, src, mode);
 	if (rc)
 		goto out;
@@ -1393,6 +1401,15 @@ static int migrate_folio_move(free_folio_t put_new_folio, unsigned long private,
 	if (old_page_state & PAGE_WAS_MAPPED)
 		remove_migration_ptes(src, dst, 0);
 
+	/*
+	 * Requeue the destination folio on the deferred split queue if
+	 * the source was on the queue.  The source is unqueued in
+	 * __folio_migrate_mapping(), so we recorded the state from
+	 * before move_to_new_folio().
+	 */
+	if (src_deferred_split)
+		deferred_split_folio(dst, src_partially_mapped);
+
 out_unlock_both:
 	folio_unlock(dst);
 	folio_set_owner_migrate_reason(dst, reason);
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-03-20 11:41 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-12 10:47 [PATCH v3] mm: migrate: requeue destination folio on deferred split queue Usama Arif
2026-03-12 14:27 ` Johannes Weiner
2026-03-13  0:16 ` SeongJae Park
2026-03-13  0:52   ` Andrew Morton
2026-03-13 10:40     ` Usama Arif
2026-03-14 22:40       ` Andrew Morton
2026-03-15  0:05         ` SeongJae Park
2026-03-15  0:23           ` Andrew Morton
2026-03-20 11:41             ` David Hildenbrand (Arm)
2026-03-13  1:18 ` Wei Yang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox