From 811777d82038d4fd3f5d3bf986f682df463b6f21 Mon Sep 17 00:00:00 2001 From: "David Hildenbrand (Arm)" Date: Thu, 15 Oct 2026 18:07:13 +0200 Subject: [PATCH] mm/hugetlb: tolerate uffd bits set without uffd for PROT_NONE PTEs The whole uffd handling when a VMA is unregistered from UFFD is shaky: there are still some scenarios where we might have stale uffd PTE bits in VMAs no longer registered for UFFD, which confuses other code. Let's just tolerate that for now and simply clear the PTE bit. Add a TODO to really clean up any uffd leftovers when unregistering a VMA from userfaultfd. The handling is now more similar to what we have in handle_pte_fault(). Link: https://lore.kernel.org/20261015-urgent_fixes-v1-7-42796911043b@kernel.org Fixes: 2d427bb01639 ("mm/userfaultfd: add RWP fault delivery and expose UFFDIO_REGISTER_MODE_RWP") Signed-off-by: David Hildenbrand (Arm) Signed-off-by: Andrew Morton Acked-by: Lorenzo Stoakes (ARM) Reviewed-by: Lance Yang Acked-by: Kiryl Shutsemau (Meta) Cc: Liam R. Howlett Cc: Vlastimil Babka Cc: Jann Horn Cc: Pedro Falcato Cc: Muchun Song Cc: Oscar Salvador Cc: Miaohe Lin Cc: Naoya Horiguchi Cc: Adam Litke Cc: Mel Gorman Cc: Rik van Riel Cc: Peter Xu Cc: Mike Rapoport Cc: Josef Bacik Cc: --- mm/hugetlb.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index d3adafbea160..a4fede4be663 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -6169,16 +6169,20 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, * NUMA hinting), so let normal hugetlb fault handling proceed. */ if (pte_protnone(vmf.orig_pte) && vma_is_accessible(vma) && - userfaultfd_rwp(vma) && huge_pte_uffd(vmf.orig_pte)) { + huge_pte_uffd(vmf.orig_pte)) { spinlock_t *ptl; pte_t pte; /* Sync: drop hugetlb locks before blocking in handle_userfault() */ - if (!userfaultfd_rwp_async(vma)) + if (userfaultfd_rwp(vma) && !userfaultfd_rwp_async(vma)) return hugetlb_handle_userfault(&vmf, mapping, VM_UFFD_RWP); ptl = huge_pte_lock(h, mm, vmf.pte); pte = huge_ptep_get(mm, vmf.address, vmf.pte); + /* + * TODO: fix all cases where uffd PTE bits remain in VMAs that + * are no longer registered with uffd. + */ if (pte_protnone(pte) && huge_pte_uffd(pte)) { unsigned int shift = huge_page_shift(h);