[PATCH 2/4] mm/migrate_device: Apply the fault reference to the correct folio
Matthew Brost <[email protected]> Wed, 5 Aug 2026 04:33:36 -0700
| Newsgroups | gmane.linux.kernel.stable,gmane.comp.video.dri.devel,gmane.linux.kernel.mm,gmane.linux.kernel |
|---|---|
| Message-ID | <[email protected]> |
__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 <[email protected]>
Cc: David Hildenbrand <[email protected]>
Cc: Lorenzo Stoakes <[email protected]>
Cc: Zi Yan <[email protected]>
Cc: Baolin Wang <[email protected]>
Cc: Liam R. Howlett <[email protected]>
Cc: Nico Pache <[email protected]>
Cc: Ryan Roberts <[email protected]>
Cc: Dev Jain <[email protected]>
Cc: Barry Song <[email protected]>
Cc: Lance Yang <[email protected]>
Cc: Usama Arif <[email protected]>
Cc: Joshua Hahn <[email protected]>
Cc: Rakie Kim <[email protected]>
Cc: Byungchul Park <[email protected]>
Cc: Gregory Price <[email protected]>
Cc: Ying Huang <[email protected]>
Cc: Alistair Popple <[email protected]>
Cc: Balbir Singh <[email protected]>
Cc: Maarten Lankhorst <[email protected]>
Cc: Maxime Ripard <[email protected]>
Cc: Thomas Zimmermann <[email protected]>
Cc: David Airlie <[email protected]>
Cc: Simona Vetter <[email protected]>
Cc: Thomas Hellström <[email protected]>
Cc: Francois Dugast <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Assisted-by: GitHub Copilot:claude-opus-5
Signed-off-by: Matthew Brost <[email protected]>
---
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 d1d81bbbf795..65a6a15dba4d 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) {
@@ -1296,13 +1296,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