On Thu, Feb 21, 2019 at 01:23:59PM -0500, Jerome Glisse wrote: > On Tue, Feb 12, 2019 at 10:56:26AM +0800, Peter Xu wrote: > > From: Shaohua Li <shli@xxxxxx> > > > > Add API to enable/disable writeprotect a vma range. Unlike mprotect, > > this doesn't split/merge vmas. > > > > Cc: Andrea Arcangeli <aarcange@xxxxxxxxxx> > > Cc: Rik van Riel <riel@xxxxxxxxxx> > > Cc: Kirill A. Shutemov <kirill@xxxxxxxxxxxxx> > > Cc: Mel Gorman <mgorman@xxxxxxx> > > Cc: Hugh Dickins <hughd@xxxxxxxxxx> > > Cc: Johannes Weiner <hannes@xxxxxxxxxxx> > > Signed-off-by: Shaohua Li <shli@xxxxxx> > > Signed-off-by: Andrea Arcangeli <aarcange@xxxxxxxxxx> > > [peterx: > > - use the helper to find VMA; > > - return -ENOENT if not found to match mcopy case; > > - use the new MM_CP_UFFD_WP* flags for change_protection > > - check against mmap_changing for failures] > > Signed-off-by: Peter Xu <peterx@xxxxxxxxxx> > > I have a question see below but anyway: > > Reviewed-by: Jérôme Glisse <jglisse@xxxxxxxxxx> Thanks! > > > --- > > include/linux/userfaultfd_k.h | 3 ++ > > mm/userfaultfd.c | 54 +++++++++++++++++++++++++++++++++++ > > 2 files changed, 57 insertions(+) > > > > diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h > > index 765ce884cec0..8f6e6ed544fb 100644 > > --- a/include/linux/userfaultfd_k.h > > +++ b/include/linux/userfaultfd_k.h > > @@ -39,6 +39,9 @@ extern ssize_t mfill_zeropage(struct mm_struct *dst_mm, > > unsigned long dst_start, > > unsigned long len, > > bool *mmap_changing); > > +extern int mwriteprotect_range(struct mm_struct *dst_mm, > > + unsigned long start, unsigned long len, > > + bool enable_wp, bool *mmap_changing); > > > > /* mm helpers */ > > static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma, > > diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c > > index fefa81c301b7..529d180bb4d7 100644 > > --- a/mm/userfaultfd.c > > +++ b/mm/userfaultfd.c > > @@ -639,3 +639,57 @@ ssize_t mfill_zeropage(struct mm_struct *dst_mm, unsigned long start, > > { > > return __mcopy_atomic(dst_mm, start, 0, len, true, mmap_changing, 0); > > } > > + > > +int mwriteprotect_range(struct mm_struct *dst_mm, unsigned long start, > > + unsigned long len, bool enable_wp, bool *mmap_changing) > > +{ > > + struct vm_area_struct *dst_vma; > > + pgprot_t newprot; > > + int err; > > + > > + /* > > + * Sanitize the command parameters: > > + */ > > + BUG_ON(start & ~PAGE_MASK); > > + BUG_ON(len & ~PAGE_MASK); > > + > > + /* Does the address range wrap, or is the span zero-sized? */ > > + BUG_ON(start + len <= start); > > + > > + down_read(&dst_mm->mmap_sem); > > + > > + /* > > + * If memory mappings are changing because of non-cooperative > > + * operation (e.g. mremap) running in parallel, bail out and > > + * request the user to retry later > > + */ > > + err = -EAGAIN; > > + if (mmap_changing && READ_ONCE(*mmap_changing)) > > + goto out_unlock; > > + > > + err = -ENOENT; > > + dst_vma = vma_find_uffd(dst_mm, start, len); > > + /* > > + * Make sure the vma is not shared, that the dst range is > > + * both valid and fully within a single existing vma. > > + */ > > + if (!dst_vma || (dst_vma->vm_flags & VM_SHARED)) > > + goto out_unlock; > > + if (!userfaultfd_wp(dst_vma)) > > + goto out_unlock; > > + if (!vma_is_anonymous(dst_vma)) > > + goto out_unlock; > > Don't you want to distinguish between no VMA ie ENOENT and vma that > can not be write protected (VM_SHARED, not userfaultfd, not anonymous) ? Here we'll return ENOENT for all these errors which is actually trying to follow existing MISSING codes. Mike noticed some errno issues during reviewing the first version and suggested that we'd better follow the old rules which makes perfect sense to me. E.g., in __mcopy_atomic() we'll return ENOENT for either (1) VMA not found, (2) not UFFD VMA, (3) range check failures. Checking against anonymous and VM_SHARED are special for uffd-wp but I'm simply using this same errno since after all all these errors will stop us from finding a valid VMA before going anywhere further. Thanks, -- Peter Xu