The patch titled Subject: mm/shmem: take care of UFFDIO_COPY_MODE_WP has been added to the -mm tree. Its filename is mm-shmem-take-care-of-uffdio_copy_mode_wp.patch This patch should soon appear at https://ozlabs.org/~akpm/mmots/broken-out/mm-shmem-take-care-of-uffdio_copy_mode_wp.patch and later at https://ozlabs.org/~akpm/mmotm/broken-out/mm-shmem-take-care-of-uffdio_copy_mode_wp.patch Before you just go and hit "reply", please: a) Consider who else should be cc'ed b) Prefer to cc a suitable mailing list as well c) Ideally: find the original patch on the mailing list and do a reply-to-all to that, adding suitable additional cc's *** Remember to use Documentation/process/submit-checklist.rst when testing your code *** The -mm tree is included into linux-next and is updated there every 3-4 working days ------------------------------------------------------ From: Peter Xu <peterx@xxxxxxxxxx> Subject: mm/shmem: take care of UFFDIO_COPY_MODE_WP Pass wp_copy into shmem_mfill_atomic_pte() through the stack, then apply the UFFD_WP bit properly when the UFFDIO_COPY on shmem is with UFFDIO_COPY_MODE_WP. wp_copy lands mfill_atomic_install_pte() finally. Note: we must do pte_wrprotect() if !writable in mfill_atomic_install_pte(), as mk_pte() could return a writable pte (e.g., when VM_SHARED on a shmem file). Link: https://lkml.kernel.org/r/20220405014841.14185-1-peterx@xxxxxxxxxx Signed-off-by: Peter Xu <peterx@xxxxxxxxxx> Cc: Alistair Popple <apopple@xxxxxxxxxx> Cc: Andrea Arcangeli <aarcange@xxxxxxxxxx> Cc: Axel Rasmussen <axelrasmussen@xxxxxxxxxx> Cc: David Hildenbrand <david@xxxxxxxxxx> Cc: Hugh Dickins <hughd@xxxxxxxxxx> Cc: Jerome Glisse <jglisse@xxxxxxxxxx> Cc: "Kirill A . Shutemov" <kirill@xxxxxxxxxxxxx> Cc: Matthew Wilcox <willy@xxxxxxxxxxxxx> Cc: Mike Kravetz <mike.kravetz@xxxxxxxxxx> Cc: Mike Rapoport <rppt@xxxxxxxxxxxxxxxxxx> Cc: Nadav Amit <nadav.amit@xxxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> --- include/linux/shmem_fs.h | 4 ++-- mm/shmem.c | 4 ++-- mm/userfaultfd.c | 23 ++++++++++++++++++----- 3 files changed, 22 insertions(+), 9 deletions(-) --- a/include/linux/shmem_fs.h~mm-shmem-take-care-of-uffdio_copy_mode_wp +++ a/include/linux/shmem_fs.h @@ -145,11 +145,11 @@ extern int shmem_mfill_atomic_pte(struct struct vm_area_struct *dst_vma, unsigned long dst_addr, unsigned long src_addr, - bool zeropage, + bool zeropage, bool wp_copy, struct page **pagep); #else /* !CONFIG_SHMEM */ #define shmem_mfill_atomic_pte(dst_mm, dst_pmd, dst_vma, dst_addr, \ - src_addr, zeropage, pagep) ({ BUG(); 0; }) + src_addr, zeropage, wp_copy, pagep) ({ BUG(); 0; }) #endif /* CONFIG_SHMEM */ #endif /* CONFIG_USERFAULTFD */ --- a/mm/shmem.c~mm-shmem-take-care-of-uffdio_copy_mode_wp +++ a/mm/shmem.c @@ -2313,7 +2313,7 @@ int shmem_mfill_atomic_pte(struct mm_str struct vm_area_struct *dst_vma, unsigned long dst_addr, unsigned long src_addr, - bool zeropage, + bool zeropage, bool wp_copy, struct page **pagep) { struct inode *inode = file_inode(dst_vma->vm_file); @@ -2386,7 +2386,7 @@ int shmem_mfill_atomic_pte(struct mm_str goto out_release; ret = mfill_atomic_install_pte(dst_mm, dst_pmd, dst_vma, dst_addr, - page, true, false); + page, true, wp_copy); if (ret) goto out_delete_from_cache; --- a/mm/userfaultfd.c~mm-shmem-take-care-of-uffdio_copy_mode_wp +++ a/mm/userfaultfd.c @@ -78,10 +78,19 @@ int mfill_atomic_install_pte(struct mm_s * Always mark a PTE as write-protected when needed, regardless of * VM_WRITE, which the user might change. */ - if (wp_copy) + if (wp_copy) { _dst_pte = pte_mkuffd_wp(_dst_pte); - else if (writable) + writable = false; + } + + if (writable) _dst_pte = pte_mkwrite(_dst_pte); + else + /* + * We need this to make sure write bit removed; as mk_pte() + * could return a pte with write bit set. + */ + _dst_pte = pte_wrprotect(_dst_pte); dst_pte = pte_offset_map_lock(dst_mm, dst_pmd, dst_addr, &ptl); @@ -96,7 +105,12 @@ int mfill_atomic_install_pte(struct mm_s } ret = -EEXIST; - if (!pte_none(*dst_pte)) + /* + * We allow to overwrite a pte marker: consider when both MISSING|WP + * registered, we firstly wr-protect a none pte which has no page cache + * page backing it, then access the page. + */ + if (!pte_none_mostly(*dst_pte)) goto out_unlock; if (page_in_cache) { @@ -480,11 +494,10 @@ static __always_inline ssize_t mfill_ato err = mfill_zeropage_pte(dst_mm, dst_pmd, dst_vma, dst_addr); } else { - VM_WARN_ON_ONCE(wp_copy); err = shmem_mfill_atomic_pte(dst_mm, dst_pmd, dst_vma, dst_addr, src_addr, mode != MCOPY_ATOMIC_NORMAL, - page); + wp_copy, page); } return err; _ Patches currently in -mm which might be from peterx@xxxxxxxxxx are mm-introduce-pte_marker-swap-entry.patch mm-teach-core-mm-about-pte-markers.patch mm-check-against-orig_pte-for-finish_fault.patch mm-uffd-pte_marker_uffd_wp.patch mm-shmem-take-care-of-uffdio_copy_mode_wp.patch mm-shmem-handle-uffd-wp-special-pte-in-page-fault-handler.patch mm-shmem-persist-uffd-wp-bit-across-zapping-for-file-backed.patch mm-shmem-allow-uffd-wr-protect-none-pte-for-file-backed-mem.patch mm-shmem-allows-file-back-mem-to-be-uffd-wr-protected-on-thps.patch mm-shmem-handle-uffd-wp-during-fork.patch mm-hugetlb-introduce-huge-pte-version-of-uffd-wp-helpers.patch mm-hugetlb-hook-page-faults-for-uffd-write-protection.patch mm-hugetlb-take-care-of-uffdio_copy_mode_wp.patch mm-hugetlb-handle-uffdio_writeprotect.patch mm-hugetlb-handle-pte-markers-in-page-faults.patch mm-hugetlb-allow-uffd-wr-protect-none-ptes.patch mm-hugetlb-only-drop-uffd-wp-special-pte-if-required.patch mm-hugetlb-handle-uffd-wp-during-fork.patch mm-khugepaged-dont-recycle-vma-pgtable-if-uffd-wp-registered.patch mm-pagemap-recognize-uffd-wp-bit-for-shmem-hugetlbfs.patch mm-uffd-enable-write-protection-for-shmem-hugetlbfs.patch mm-enable-pte-markers-by-default.patch selftests-uffd-enable-uffd-wp-for-shmem-hugetlbfs.patch