}
/* VMA userfaultfd operations */
+int uffd_writeprotect(struct uffd_info *info);
ssize_t uffd_failed_do_unlock(struct userfaultfd_ctx *ctx,
struct vm_area_struct *dst, struct folio *folio,
unsigned long src_addr);
int (*zeropage)(struct uffd_info *info);
int (*cont)(struct uffd_info *info);
int (*poison)(struct uffd_info *info);
+ int (*writeprotect)(struct uffd_info *info);
/* Required features below */
ssize_t (*is_dst_valid)(struct vm_area_struct *dst_vma,
unsigned long dst_start, unsigned long len);
.zeropage = NULL,
.cont = hugetlb_mfill_pte_continue,
.poison = hugetlb_mfill_pte_poison,
+ .writeprotect = uffd_writeprotect,
.is_dst_valid = hugetlb_is_dst_valid,
.increment = hugetlb_mfill_size,
.failed_do_unlock = hugetlb_failed_do_unlock,
.zeropage = shmem_mfill_atomic_pte_zeropage,
.cont = shmem_mfill_atomic_pte_continue,
.poison = mfill_atomic_pte_poison,
+ .writeprotect = uffd_writeprotect,
.is_dst_valid = shmem_is_dst_valid,
.increment = mfill_size,
.failed_do_unlock = uffd_failed_do_unlock,
.zeropage = mfill_atomic_pte_zeropage,
.cont = NULL,
.poison = mfill_atomic_pte_poison,
+ .writeprotect = uffd_writeprotect,
.is_dst_valid = uffd_def_is_dst_valid,
.increment = mfill_size,
.failed_do_unlock = uffd_failed_do_unlock,
return ret;
}
-static int uffd_writeprotect(struct uffd_info *info)
+int uffd_writeprotect(struct uffd_info *info)
{
long err;
struct vm_area_struct *dst_vma;
err = -ENOENT;
for_each_vma_range(vmi, info.dst_vma, start + len) {
- err = uffd_writeprotect(&info);
+ info.uffd_ops = vma_get_uffd_ops(info.dst_vma);
+ err = -EINVAL;
+ if (!info.uffd_ops || !info.uffd_ops->writeprotect)
+ break;
+ err = info.uffd_ops->writeprotect(&info);
if (err)
break;
}