return &default_uffd_ops;
}
+/*
+ * Global checks live here, specific checks are in the callback.
+ */
static inline ssize_t
uffd_ctx_lock_and_validate_dst(struct userfaultfd_ctx *ctx,
struct vm_area_struct *dst_vma, unsigned long dst_start,
- unsigned long len)
+ unsigned long len, uffd_flags_t flags)
{
const struct vm_uffd_ops *uffd_ops;
if (atomic_read(&ctx->mmap_changing))
return -EAGAIN;
+ /*
+ * shmem_zero_setup is invoked in mmap for MAP_ANONYMOUS|MAP_SHARED but
+ * it will overwrite vm_ops, so vma_is_anonymous must return false.
+ */
+ if (WARN_ON_ONCE(vma_is_anonymous(dst_vma) &&
+ dst_vma->vm_flags & VM_SHARED))
+ return -EINVAL;
+ /*
+ * validate 'mode' now that we know the dst_vma: don't allow
+ * a wrprotect copy if the userfaultfd didn't register as WP.
+ */
+ if ((flags & MFILL_ATOMIC_WP) && !(dst_vma->vm_flags & VM_UFFD_WP))
+ return -EINVAL;
+
uffd_ops = vma_get_uffd_ops(dst_vma);
WARN_ON_ONCE(!uffd_ops || !uffd_ops->is_dst_valid);
return uffd_ops->is_dst_valid(dst_vma, dst_start, len);
goto out;
}
- err = uffd_ctx_lock_and_validate_dst(ctx, dst_vma, dst_start, len);
+ err = uffd_ctx_lock_and_validate_dst(ctx, dst_vma, dst_start,
+ len, flags);
if (err)
goto out_unlock;
}
increment = uffd_ops->increment(dst_vma);
}
- err = uffd_ctx_lock_and_validate_dst(ctx, dst_vma, dst_start, len);
+ err = uffd_ctx_lock_and_validate_dst(ctx, dst_vma, dst_start, len,
+ flags);
if (err)
goto out_unlock;
- err = -EINVAL;
- /*
- * shmem_zero_setup is invoked in mmap for MAP_ANONYMOUS|MAP_SHARED but
- * it will overwrite vm_ops, so vma_is_anonymous must return false.
- */
- if (WARN_ON_ONCE(vma_is_anonymous(dst_vma) &&
- dst_vma->vm_flags & VM_SHARED))
- goto out_unlock;
-
- /*
- * validate 'mode' now that we know the dst_vma: don't allow
- * a wrprotect copy if the userfaultfd didn't register as WP.
- */
- if ((flags & MFILL_ATOMIC_WP) && !(dst_vma->vm_flags & VM_UFFD_WP))
- goto out_unlock;
-
/*
* If this is a HUGETLB vma, pass off to appropriate routine
*/
return mfill_atomic_hugetlb(ctx, dst_vma, dst_start,
src_start, len, flags);
+ err = -EINVAL;
if (!vma_is_anonymous(dst_vma) && !vma_is_shmem(dst_vma))
goto out_unlock;
if (!vma_is_shmem(dst_vma) &&