From 9884fc6cbd389cf3a0df445ea95c59b9786bb45e Mon Sep 17 00:00:00 2001 From: "Liam R. Howlett" Date: Wed, 29 Oct 2025 04:40:31 -0400 Subject: [PATCH] mm/userfaultfd: Moduarlize uffd_writeprotect() for memory types Each memory type that treats the writeprotect differently has its own implementation so that each one can do what it needs without injecting checks on other types unnecessarily. Signed-off-by: Liam R. Howlett --- include/linux/userfaultfd_k.h | 2 ++ mm/hugetlb.c | 1 + mm/shmem.c | 1 + mm/userfaultfd.c | 9 +++++++-- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h index 114f9257d240..6f919008bdde 100644 --- a/include/linux/userfaultfd_k.h +++ b/include/linux/userfaultfd_k.h @@ -116,6 +116,7 @@ struct uffd_info { } /* 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); @@ -125,6 +126,7 @@ struct vm_uffd_ops { 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); diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 97b402762921..72daaf8d06e1 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -5538,6 +5538,7 @@ static const struct vm_uffd_ops hugetlb_uffd_ops = { .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, diff --git a/mm/shmem.c b/mm/shmem.c index 165b428a661e..3ddf7f42e1fa 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -5273,6 +5273,7 @@ static const struct vm_uffd_ops shmem_uffd_ops = { .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, diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c index 1bdccadcaeb3..f7c5b40f3e05 100644 --- a/mm/userfaultfd.c +++ b/mm/userfaultfd.c @@ -475,6 +475,7 @@ static const struct vm_uffd_ops default_uffd_ops = { .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, @@ -784,7 +785,7 @@ long uffd_wp_range(struct vm_area_struct *dst_vma, 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; @@ -843,7 +844,11 @@ int mwriteprotect_range(struct userfaultfd_ctx *ctx, unsigned long start, 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; } -- 2.51.0