[PATCH v2 3/5] mm/migrate_device: Apply the fault reference to the correct folio
From: Matthew Brost
Date: Wed Aug 05 2026 - 15:37:51 EST
__migrate_device_pages() computed extra_cnt once, from the head page of
the source folio, and then passed the same value to
folio_migrate_mapping() for every one of the @nr sub-folios produced by
migrate_vma_split_unmapped_folio().
The extra reference the CPU fault holds only exists on the single folio
that ends up containing the fault page. Claiming it for all of them
makes folio_migrate_mapping() expect one reference too many on every
other sub-folio, so it returns -EAGAIN and MIGRATE_PFN_MIGRATE is
cleared for them. Only the fault page would migrate; the remaining
HPAGE_PMD_NR - 1 pages would be restored to device memory, and the
faulting access would immediately fault again.
Compute extra_cnt per sub-folio instead, comparing against the source
page for that entry.
While at it, use the sub-folio's own mapping rather than the mapping
that was read from the pre-split folio.
This has been latent so far because the split it depends on could never
succeed while the fault reference was held.
Fixes: 4265d67e405a ("mm/migrate_device: add THP splitting during migration")
Cc: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx>
Cc: David Hildenbrand <david@xxxxxxxxxx>
Cc: Lorenzo Stoakes <ljs@xxxxxxxxxx>
Cc: Zi Yan <ziy@xxxxxxxxxx>
Cc: Baolin Wang <baolin.wang@xxxxxxxxxxxxxxxxx>
Cc: Liam R. Howlett <liam@xxxxxxxxxxxxx>
Cc: Nico Pache <nico.pache@xxxxxxxxx>
Cc: Ryan Roberts <ryan.roberts@xxxxxxx>
Cc: Dev Jain <dev.jain@xxxxxxx>
Cc: Barry Song <baohua@xxxxxxxxxx>
Cc: Lance Yang <lance.yang@xxxxxxxxx>
Cc: Usama Arif <usama.arif@xxxxxxxxx>
Cc: Joshua Hahn <joshua.hahnjy@xxxxxxxxx>
Cc: Rakie Kim <rakie.kim@xxxxxx>
Cc: Byungchul Park <byungchul@xxxxxx>
Cc: Gregory Price <gourry@xxxxxxxxxx>
Cc: Ying Huang <ying.huang@xxxxxxxxxxxxxxxxx>
Cc: Alistair Popple <apopple@xxxxxxxxxx>
Cc: Balbir Singh <balbirs@xxxxxxxxxx>
Cc: Maarten Lankhorst <maarten.lankhorst@xxxxxxxxxxxxxxx>
Cc: Maxime Ripard <mripard@xxxxxxxxxx>
Cc: Thomas Zimmermann <tzimmermann@xxxxxxx>
Cc: David Airlie <airlied@xxxxxxxxx>
Cc: Simona Vetter <simona@xxxxxxxx>
Cc: Thomas Hellström <thomas.hellstrom@xxxxxxxxxxxxxxx>
Cc: Francois Dugast <francois.dugast@xxxxxxxxx>
Cc: dri-devel@xxxxxxxxxxxxxxxxxxxxx
Cc: linux-mm@xxxxxxxxx
Cc: linux-kernel@xxxxxxxxxxxxxxx
Cc: stable@xxxxxxxxxxxxxxx
Assisted-by: GitHub_Copilot:claude-opus-5
Signed-off-by: Matthew Brost <matthew.brost@xxxxxxxxx>
---
mm/migrate_device.c | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/mm/migrate_device.c b/mm/migrate_device.c
index 142920a464d8..4ee09801efe6 100644
--- a/mm/migrate_device.c
+++ b/mm/migrate_device.c
@@ -1191,7 +1191,7 @@ static void __migrate_device_pages(unsigned long *src_pfns,
struct page *page = migrate_pfn_to_page(src_pfns[i]);
struct address_space *mapping;
struct folio *newfolio, *folio;
- int r, extra_cnt = 0;
+ int r;
unsigned long nr = 1;
if (!newpage) {
@@ -1301,13 +1301,25 @@ static void __migrate_device_pages(unsigned long *src_pfns,
BUG_ON(folio_test_writeback(folio));
- if (migrate && migrate->fault_page == page)
- extra_cnt = 1;
for (j = 0; j < nr && i + j < npages; j++) {
- folio = page_folio(migrate_pfn_to_page(src_pfns[i+j]));
+ struct page *src_page = migrate_pfn_to_page(src_pfns[i+j]);
+ int extra_cnt = 0;
+
+ folio = page_folio(src_page);
newfolio = page_folio(migrate_pfn_to_page(dst_pfns[i+j]));
- r = folio_migrate_mapping(mapping, newfolio, folio, extra_cnt);
+ /*
+ * The CPU fault holds an extra reference on the folio
+ * containing the fault page. @folio may have been
+ * split above, so the fault page only accounts for an
+ * extra reference on the folio it actually ended up
+ * in, not on every folio of the original THP.
+ */
+ if (migrate && migrate->fault_page == src_page)
+ extra_cnt = 1;
+
+ r = folio_migrate_mapping(folio_mapping(folio), newfolio,
+ folio, extra_cnt);
if (r)
src_pfns[i+j] &= ~MIGRATE_PFN_MIGRATE;
else
--
2.34.1