Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

mm: migrate: requeue destination folio on deferred split queue

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.

Because THPs are removed from the deferred_list, THP shinker cannot
split the underutilized THPs in time. As a result, users will show
less free memory than before.

Link: https://lkml.kernel.org/r/20260312104723.1351321-1-usama.arif@linux.dev
Fixes: dafff3f4c850 ("mm: split underused THPs")
Signed-off-by: Usama Arif <usama.arif@linux.dev>
Reported-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Zi Yan <ziy@nvidia.com>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Acked-by: SeongJae Park <sj@kernel.org>
Reviewed-by: Wei Yang <richard.weiyang@gmail.com>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Byungchul Park <byungchul@sk.com>
Cc: Gregory Price <gourry@gourry.net>
Cc: "Huang, Ying" <ying.huang@linux.alibaba.com>
Cc: Joshua Hahn <joshua.hahnjy@gmail.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Nico Pache <npache@redhat.com>
Cc: Rakie Kim <rakie.kim@sk.com>
Cc: Ying Huang <ying.huang@linux.alibaba.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Usama Arif and committed by
Andrew Morton
a2e0c066 2d028f3e

+17
+17
mm/migrate.c
··· 1358 1358 int rc; 1359 1359 int old_page_state = 0; 1360 1360 struct anon_vma *anon_vma = NULL; 1361 + bool src_deferred_split = false; 1362 + bool src_partially_mapped = false; 1361 1363 struct list_head *prev; 1362 1364 1363 1365 __migrate_folio_extract(dst, &old_page_state, &anon_vma); ··· 1371 1369 if (rc) 1372 1370 goto out; 1373 1371 goto out_unlock_both; 1372 + } 1373 + 1374 + if (folio_order(src) > 1 && 1375 + !data_race(list_empty(&src->_deferred_list))) { 1376 + src_deferred_split = true; 1377 + src_partially_mapped = folio_test_partially_mapped(src); 1374 1378 } 1375 1379 1376 1380 rc = move_to_new_folio(dst, src, mode); ··· 1398 1390 1399 1391 if (old_page_state & PAGE_WAS_MAPPED) 1400 1392 remove_migration_ptes(src, dst, 0); 1393 + 1394 + /* 1395 + * Requeue the destination folio on the deferred split queue if 1396 + * the source was on the queue. The source is unqueued in 1397 + * __folio_migrate_mapping(), so we recorded the state from 1398 + * before move_to_new_folio(). 1399 + */ 1400 + if (src_deferred_split) 1401 + deferred_split_folio(dst, src_partially_mapped); 1401 1402 1402 1403 out_unlock_both: 1403 1404 folio_unlock(dst);