Re: [RESEND v7 11/29] mm: split PMD swap entries into PTE swap entries
From: Usama Arif
Date: Tue Sep 22 2026 - 09:52:53 EST
On 22/09/2026 12:46, David Hildenbrand (Arm) wrote:
> 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).
>
Will follow Davids advice and cleanup later if no one has done it.
Too much cleanup already :)