Re: [RESEND v7 11/29] mm: split PMD swap entries into PTE swap entries
From: David Hildenbrand (Arm)
Date: Tue Sep 22 2026 - 08:27:53 EST
On 9/16/26 17:08, Kiryl Shutsemau wrote:
> On Mon, Sep 14, 2026 at 05:28:01AM -0700, Usama Arif wrote:
>> Once a PMD can hold a swap entry, everything that splits a PMD - mprotect()
>> or munmap() over part of the range, MADV_FREE, a pagewalk with no PMD
>> handler - has to be able to split that entry too, or the callers that rely
>> on split_huge_pmd() to hand them a PTE table would find the PMD unchanged.
>>
>> No reference counting is needed: a swap entry pins no folio, and swap_map
>> is already one per slot, so the PTEs simply take over what the PMD held.
>>
>> The migration-only entry point cannot reach the new branch, because
>> page_vma_mapped_walk() never hands back a swap PMD for the folio being
>> migrated. Warn if that ever changes, and force the regular split anyway,
>> since the branch leaves folio and page uninitialised.
>>
>> Test the pre-split old_pmd rather than re-reading *pmd in the trailing
>> folio_remove_rmap_pmd() gate, so every entry-type test in the function
>> interrogates the same snapshot. That part is cosmetic: pmdp_invalidate()
>> leaves the PMD present as far as software is concerned.
>>
>> Signed-off-by: Usama Arif <usama.arif@xxxxxxxxx>
>> ---
>> mm/huge_memory.c | 36 +++++++++++++++++++++++++++++++++++-
>> 1 file changed, 35 insertions(+), 1 deletion(-)
>>
>> diff --git a/mm/huge_memory.c b/mm/huge_memory.c
>> index 873887aed0bc2..0e347a545588c 100644
>> --- a/mm/huge_memory.c
>> +++ b/mm/huge_memory.c
>> @@ -3304,6 +3304,21 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
>> folio_add_anon_rmap_ptes(folio, page, HPAGE_PMD_NR,
>> vma, haddr, rmap_flags);
>> }
>> + } else if (pmd_is_swap_entry(*pmd)) {
>> + /*
>> + * A PMD swap entry has no page, so it cannot be turned into
>> + * PTE migration entries. page_vma_mapped_walk() never hands
>> + * one back for the folio being migrated, so this should not
>> + * happen; warn, but also force the regular split so that a
>> + * broken invariant cannot make the code below dereference the
>> + * uninitialised folio and page.
>> + */
>
> The comment can be shorter.
>
>> + VM_WARN_ON_ONCE(use_migration_entries);
>> + use_migration_entries = false;
>> + old_pmd = *pmd;
>> + soft_dirty = pmd_swp_soft_dirty(old_pmd);
>> + uffd_wp = pmd_swp_uffd(old_pmd);
>> + anon_exclusive = pmd_swp_exclusive(old_pmd);
>
> The logic looks right to me, but __split_huge_pmd_locked() is getting
> awkward. It is close to 300 lines with two if-else chains that have to
> be kept in sync.
>
> Can we have a preparatory patch that moves the PTE-install loops into
> per-type helpers?
>
> split_pmd_into_migration_ptes(), split_pmd_into_device_private_ptes(),
> split_pmd_into_present_ptes().
There were recently patches about related cleanups:
https://lore.kernel.org/r/cover.1787941780.git.yintirui@xxxxxxxxx
I'm fine with cleaning this up later (I hope we can land this series in 7.4).
--
Cheers,
David