From a77f36948eb7a9ceebdf6cf8d6d5ea936433edb9 Mon Sep 17 00:00:00 2001 From: "Liam R. Howlett" Date: Wed, 22 Oct 2025 22:07:51 -0400 Subject: [PATCH] mm/userfaultfd: Extract error recover from mfill_atomic() loop into uffd_failed_do_unlock() When a failure occurs during the mfill_atomic() operation, some special error recovery may be required - based on memory type. Move the error recovery to its own function so it is easily modularized later. Signed-off-by: Liam R. Howlett --- mm/userfaultfd.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c index 8bc1c55005bf..1b7828a0acfa 100644 --- a/mm/userfaultfd.c +++ b/mm/userfaultfd.c @@ -719,6 +719,27 @@ uffd_ctx_lock_and_validate_dst(struct userfaultfd_ctx *ctx, return 0; } +static inline ssize_t +uffd_failed_do_unlock(struct userfaultfd_ctx *ctx, struct vm_area_struct *dst, + struct folio *folio, unsigned long src_addr) +{ + ssize_t err; + void *kaddr; + + up_read(&ctx->map_changing_lock); + uffd_mfill_unlock(dst); + VM_WARN_ON_ONCE(!folio); + + kaddr = kmap_local_folio(folio, 0); + err = copy_from_user(kaddr, (const void __user *) src_addr, PAGE_SIZE); + kunmap_local(kaddr); + if (unlikely(err)) + return -EFAULT; + + flush_dcache_folio(folio); + return 0; +} + static inline ssize_t uffd_get_dst_pmd(struct mm_struct *dst_mm, struct vm_area_struct *dst_vma, unsigned long dst_addr, pmd_t **dst_pmd) @@ -839,25 +860,15 @@ retry: cond_resched(); if (unlikely(err == -ENOENT)) { - void *kaddr; - - up_read(&ctx->map_changing_lock); - uffd_mfill_unlock(dst_vma); - VM_WARN_ON_ONCE(!folio); - - kaddr = kmap_local_folio(folio, 0); - err = copy_from_user(kaddr, - (const void __user *) src_addr, - PAGE_SIZE); - kunmap_local(kaddr); - if (unlikely(err)) { - err = -EFAULT; + err = uffd_failed_do_unlock(ctx, dst_vma, folio, + src_addr); + if (unlikely(err)) goto out; - } - flush_dcache_folio(folio); + goto retry; - } else + } else { VM_WARN_ON_ONCE(folio); + } if (!err) { dst_addr += PAGE_SIZE; -- 2.51.0