Skip to content

Commit 5b51072

Browse files
aagittorvalds
authored andcommitted
userfaultfd: shmem: allocate anonymous memory for MAP_PRIVATE shmem
Userfaultfd did not create private memory when UFFDIO_COPY was invoked on a MAP_PRIVATE shmem mapping. Instead it wrote to the shmem file, even when that had not been opened for writing. Though, fortunately, that could only happen where there was a hole in the file. Fix the shmem-backed implementation of UFFDIO_COPY to create private memory for MAP_PRIVATE mappings. The hugetlbfs-backed implementation was already correct. This change is visible to userland, if userfaultfd has been used in unintended ways: so it introduces a small risk of incompatibility, but is necessary in order to respect file permissions. An app that uses UFFDIO_COPY for anything like postcopy live migration won't notice the difference, and in fact it'll run faster because there will be no copy-on-write and memory waste in the tmpfs pagecache anymore. Userfaults on MAP_PRIVATE shmem keep triggering only on file holes like before. The real zeropage can also be built on a MAP_PRIVATE shmem mapping through UFFDIO_ZEROPAGE and that's safe because the zeropage pte is never dirty, in turn even an mprotect upgrading the vma permission from PROT_READ to PROT_READ|PROT_WRITE won't make the zeropage pte writable. Link: http://lkml.kernel.org/r/[email protected] Fixes: 4c27fe4 ("userfaultfd: shmem: add shmem_mcopy_atomic_pte for userfaultfd support") Signed-off-by: Andrea Arcangeli <[email protected]> Reported-by: Mike Rapoport <[email protected]> Reviewed-by: Hugh Dickins <[email protected]> Cc: <[email protected]> Cc: "Dr. David Alan Gilbert" <[email protected]> Cc: Jann Horn <[email protected]> Cc: Mike Kravetz <[email protected]> Cc: Peter Xu <[email protected]> Cc: [email protected] Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 9e36825 commit 5b51072

File tree

1 file changed

+13
-2
lines changed

1 file changed

+13
-2
lines changed

mm/userfaultfd.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,17 @@ static __always_inline ssize_t mfill_atomic_pte(struct mm_struct *dst_mm,
380380
{
381381
ssize_t err;
382382

383-
if (vma_is_anonymous(dst_vma)) {
383+
/*
384+
* The normal page fault path for a shmem will invoke the
385+
* fault, fill the hole in the file and COW it right away. The
386+
* result generates plain anonymous memory. So when we are
387+
* asked to fill an hole in a MAP_PRIVATE shmem mapping, we'll
388+
* generate anonymous memory directly without actually filling
389+
* the hole. For the MAP_PRIVATE case the robustness check
390+
* only happens in the pagetable (to verify it's still none)
391+
* and not in the radix tree.
392+
*/
393+
if (!(dst_vma->vm_flags & VM_SHARED)) {
384394
if (!zeropage)
385395
err = mcopy_atomic_pte(dst_mm, dst_pmd, dst_vma,
386396
dst_addr, src_addr, page);
@@ -489,7 +499,8 @@ static __always_inline ssize_t __mcopy_atomic(struct mm_struct *dst_mm,
489499
* dst_vma.
490500
*/
491501
err = -ENOMEM;
492-
if (vma_is_anonymous(dst_vma) && unlikely(anon_vma_prepare(dst_vma)))
502+
if (!(dst_vma->vm_flags & VM_SHARED) &&
503+
unlikely(anon_vma_prepare(dst_vma)))
493504
goto out_unlock;
494505

495506
while (src_addr < src_start + len) {

0 commit comments

Comments
 (0)