Re: VM_BUG_ON_VMA in split_huge_pmd_locked: huge PMD doesn't cover full VMA range

From: David Hildenbrand (Arm)

Date: Wed Feb 25 2026 - 15:33:20 EST


> The suspected race window is:
>
>   1. VMA [A, A+2MB) has a THP. Migration starts, PMD becomes a migration
>      entry.
>
>   2. Concurrently, __split_vma() runs under mmap_write_lock. It calls
>      vma_adjust_trans_huge() which acquires the PMD lock, splits the PMD
>      migration entry into 512 PTE migration entries, and releases the PMD
>      lock. Then VMA boundaries are modified (e.g., vma->vm_start = A+X).

split_huge_pmd_locked() will call __split_huge_pmd_locked() either for
* pmd_trans_huge(): Present PMD
* pmd_is_valid_softleaf(): Migration PMDs (for our purpose)

__split_huge_pmd_locked() will remap either, resulting in a PTE table.


>
>   3. remove_migration_ptes() runs via rmap_walk_anon() WITHOUT mmap_lock
>      (only the anon_vma lock). page_vma_mapped_walk() acquires the PMD
>      lock. If it wins the lock BEFORE step 2's split, it finds the PMD
>      migration entry still intact and returns with pvmw->pte == NULL.
If 2. runs after 3, 2. would simply split the (present) PMD.
If 2. runs before 3, 2. would simply split the migration PMD.

And both should sync on the PMD table lock.

exit() cannot run before 2. completed.


Wondering if it's instead some missed vma_adjust_trans_huge() case. I
see a call from commit_merge(), so maybe some odd corner cases with VMA
merging.

--
Cheers,

David