Device memory migration has two call sites that split huge PMDs: migrate_vma_split_unmapped_folio(): Called from migrate_vma_pages() when migrating a PMD-mapped THP to a destination that doesn't support compound pages. It splits the PMD then splits the folio via folio_split_unmapped().
If the PMD split fails, folio_split_unmapped() would operate on an unsplit folio with inconsistent page table state. Propagate -ENOMEM to skip this page's migration. This is safe as folio_split_unmapped failure would be propagated in a similar way. migrate_vma_insert_page(): Called from migrate_vma_pages() when inserting a page into a VMA during migration back from device memory. If a huge zero PMD exists at the target address, it must be split before PTE insertion. If the split fails, the subsequent pte_alloc() and set_pte_at() would operate on a PMD slot still occupied by the huge zero entry. Use goto abort, consistent with other allocation failures in this function. Signed-off-by: Usama Arif <[email protected]> --- mm/migrate_device.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/mm/migrate_device.c b/mm/migrate_device.c index 78c7acf024615..bc53e06fd9735 100644 --- a/mm/migrate_device.c +++ b/mm/migrate_device.c @@ -909,7 +909,13 @@ static int migrate_vma_split_unmapped_folio(struct migrate_vma *migrate, int ret = 0; folio_get(folio); - split_huge_pmd_address(migrate->vma, addr, true); + /* + * If PMD split fails, folio_split_unmapped would operate on an + * unsplit folio with inconsistent page table state. + */ + ret = split_huge_pmd_address(migrate->vma, addr, true); + if (ret) + return ret; ret = folio_split_unmapped(folio, 0); if (ret) return ret; @@ -1005,7 +1011,13 @@ static void migrate_vma_insert_page(struct migrate_vma *migrate, if (pmd_trans_huge(*pmdp)) { if (!is_huge_zero_pmd(*pmdp)) goto abort; - split_huge_pmd(vma, pmdp, addr); + /* + * If split fails, the huge zero PMD remains and + * pte_alloc/PTE insertion that follows would be + * incorrect. + */ + if (split_huge_pmd(vma, pmdp, addr)) + goto abort; } else if (pmd_leaf(*pmdp)) goto abort; } -- 2.47.3
