|
@@ -16,6 +16,7 @@
|
|
|
#include <linux/mmu_notifier.h>
|
|
|
#include <linux/hugetlb.h>
|
|
|
#include <linux/pagemap.h>
|
|
|
+#include <linux/shmem_fs.h>
|
|
|
#include <asm/tlbflush.h>
|
|
|
#include "internal.h"
|
|
|
|
|
@@ -369,7 +370,9 @@ retry:
|
|
|
*/
|
|
|
err = -EINVAL;
|
|
|
dst_vma = find_vma(dst_mm, dst_start);
|
|
|
- if (!dst_vma || (dst_vma->vm_flags & VM_SHARED))
|
|
|
+ if (!dst_vma)
|
|
|
+ goto out_unlock;
|
|
|
+ if (!vma_is_shmem(dst_vma) && dst_vma->vm_flags & VM_SHARED)
|
|
|
goto out_unlock;
|
|
|
if (dst_start < dst_vma->vm_start ||
|
|
|
dst_start + len > dst_vma->vm_end)
|
|
@@ -394,11 +397,7 @@ retry:
|
|
|
if (!dst_vma->vm_userfaultfd_ctx.ctx)
|
|
|
goto out_unlock;
|
|
|
|
|
|
- /*
|
|
|
- * FIXME: only allow copying on anonymous vmas, tmpfs should
|
|
|
- * be added.
|
|
|
- */
|
|
|
- if (!vma_is_anonymous(dst_vma))
|
|
|
+ if (!vma_is_anonymous(dst_vma) && !vma_is_shmem(dst_vma))
|
|
|
goto out_unlock;
|
|
|
|
|
|
/*
|
|
@@ -407,7 +406,7 @@ retry:
|
|
|
* dst_vma.
|
|
|
*/
|
|
|
err = -ENOMEM;
|
|
|
- if (unlikely(anon_vma_prepare(dst_vma)))
|
|
|
+ if (vma_is_anonymous(dst_vma) && unlikely(anon_vma_prepare(dst_vma)))
|
|
|
goto out_unlock;
|
|
|
|
|
|
while (src_addr < src_start + len) {
|
|
@@ -444,12 +443,21 @@ retry:
|
|
|
BUG_ON(pmd_none(*dst_pmd));
|
|
|
BUG_ON(pmd_trans_huge(*dst_pmd));
|
|
|
|
|
|
- if (!zeropage)
|
|
|
- err = mcopy_atomic_pte(dst_mm, dst_pmd, dst_vma,
|
|
|
- dst_addr, src_addr, &page);
|
|
|
- else
|
|
|
- err = mfill_zeropage_pte(dst_mm, dst_pmd, dst_vma,
|
|
|
- dst_addr);
|
|
|
+ if (vma_is_anonymous(dst_vma)) {
|
|
|
+ if (!zeropage)
|
|
|
+ err = mcopy_atomic_pte(dst_mm, dst_pmd, dst_vma,
|
|
|
+ dst_addr, src_addr,
|
|
|
+ &page);
|
|
|
+ else
|
|
|
+ err = mfill_zeropage_pte(dst_mm, dst_pmd,
|
|
|
+ dst_vma, dst_addr);
|
|
|
+ } else {
|
|
|
+ err = -EINVAL; /* if zeropage is true return -EINVAL */
|
|
|
+ if (likely(!zeropage))
|
|
|
+ err = shmem_mcopy_atomic_pte(dst_mm, dst_pmd,
|
|
|
+ dst_vma, dst_addr,
|
|
|
+ src_addr, &page);
|
|
|
+ }
|
|
|
|
|
|
cond_resched();
|
|
|
|