diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 27e8136b1815..da5d04edf7c1 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -4973,10 +4973,11 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, raw_write_seqcount_begin(&src->write_protect_seq); } else { /* - * For shared mappings the vma lock must be held before - * calling hugetlb_walk() in the src vma. Otherwise, the - * returned ptep could go away if part of a shared pmd and - * another thread calls huge_pmd_unshare. + * Shared mappings only need copying when we could have + * information stored in page tables (e.g., userfaultfd PTE + * bits or markers), which is incompatible with PMD sharing. + * Still take the hugetlb VMA lock for now to satisfy + * hugetlb_walk()'s locking requirements. */ hugetlb_vma_lock_read(src_vma); } @@ -4984,6 +4985,13 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, last_addr_mask = hugetlb_mask_last_page(h); for (addr = src_vma->vm_start; addr < src_vma->vm_end; addr += sz) { spinlock_t *src_ptl, *dst_ptl; + + if (WARN_ON_ONCE(want_pmd_share(src_vma, addr) || + want_pmd_share(dst_vma, addr))) { + ret = -EINVAL; + break; + } + src_pte = hugetlb_walk(src_vma, addr, sz); if (!src_pte) { addr |= last_addr_mask; @@ -4995,14 +5003,6 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, break; } -#ifdef CONFIG_HUGETLB_PMD_PAGE_TABLE_SHARING - /* If the pagetables are shared, there is nothing to do */ - if (ptdesc_pmd_is_shared(virt_to_ptdesc(dst_pte))) { - addr |= last_addr_mask; - continue; - } -#endif - dst_ptl = huge_pte_lock(h, dst, dst_pte); src_ptl = huge_pte_lockptr(h, src, src_pte); spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING); diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c index da67d35cd954..405f2d72f204 100644 --- a/mm/userfaultfd.c +++ b/mm/userfaultfd.c @@ -115,8 +115,7 @@ struct vm_area_struct *find_vma_and_prepare_anon(struct mm_struct *mm, vma = vma_lookup(mm, addr); if (!vma) vma = ERR_PTR(-ENOENT); - else if (!(vma->vm_flags & VM_SHARED) && - unlikely(anon_vma_prepare(vma))) + else if (vma_is_cow_mapping(vma) && unlikely(anon_vma_prepare(vma))) vma = ERR_PTR(-ENOMEM); return vma; @@ -145,7 +144,7 @@ static struct vm_area_struct *uffd_lock_vma(struct mm_struct *mm, * We know we're going to need an anon rmap, so check that * early. */ - if (!(vma->vm_flags & VM_SHARED) && unlikely(!vma_has_anon_rmap(vma))) + if (vma_is_cow_mapping(vma) && unlikely(!vma_has_anon_rmap(vma))) vma_end_read(vma); else return vma;