From nobody Sun Feb 8 16:31:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4AA3D326949; Tue, 27 Jan 2026 19:29:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769542200; cv=none; b=ludgT81kIhG8HnrgpLG1FGQiqHgSB9bSglIYLWsow0PoT/rY+LZ/THv0P46GrPMXvz5wC1bvZh8iNbs9qI1V4Qo6IpBIC8FlZF+BjrZUWkmBSmbc+Bs6jXElxkzeA2LYtdXRYOaiKmifWdzxftfyTH/nS3Q7yUZ+05GWbsbo7l8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769542200; c=relaxed/simple; bh=QA0/2G/K3ZBW3GhC7A4tfiRTq7LYOOc+8j2kW+8FnYs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=f4F2y7+OoPduVlQaEb+Ya1lPU+MA5M2EpGXB/nQ1vVcqsQn+6C/ayBEIiGpLajtWPgWxio33ufW9yrzgg4hE+FkCVLVgrYeFz/V5zbwPhYIO2APN5R7i5tgSPTH2p4INaIttRmwNIw1IPC9ropuTvDvD7Ft60RkZ3IXnV51qIH4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ooGptc46; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ooGptc46" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2044FC116C6; Tue, 27 Jan 2026 19:29:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1769542199; bh=QA0/2G/K3ZBW3GhC7A4tfiRTq7LYOOc+8j2kW+8FnYs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ooGptc46J+V4zaOBgMR5V5oW964P8jwsjhTyh26ptaR2Uzz5YCZvZDI+tiwrm+9vb I4FTzO1f/yKV7oi88yV2Ka4LLX0tpS86XWLDFcUeDQ4+5bydO1zCjl9kDLIUStScmu o/65K1e7p8pWAANkdpveXk8qxmqQwxNwpWKlFQ5c4jOqeCyRgcAJ9SwYHS7xaXUEmB X4mgaXSSxKTSU5rgo1wlPGZXwHzQ4FpE3meM3saJUpUNzdzewdmyKKhRpqUSa+vkVz pyHQ8USM1zM3U+R10dlg22Xfm60B5O7bJPS3snC9o9cjUxKiudhrjwgHT/FfrkR8n6 +8ZDzXtdfihtg== From: Mike Rapoport To: linux-mm@kvack.org Cc: Andrea Arcangeli , Andrew Morton , Axel Rasmussen , Baolin Wang , David Hildenbrand , Hugh Dickins , James Houghton , "Liam R. Howlett" , Lorenzo Stoakes , Michal Hocko , Mike Rapoport , Muchun Song , Nikita Kalyazin , Oscar Salvador , Paolo Bonzini , Peter Xu , Sean Christopherson , Shuah Khan , Suren Baghdasaryan , Vlastimil Babka , linux-kernel@vger.kernel.org, kvm@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH RFC 02/17] userfaultfd: introduce struct mfill_state Date: Tue, 27 Jan 2026 21:29:21 +0200 Message-ID: <20260127192936.1250096-3-rppt@kernel.org> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260127192936.1250096-1-rppt@kernel.org> References: <20260127192936.1250096-1-rppt@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Mike Rapoport (Microsoft)" mfill_atomic() passes a lot of parameters down to its callees. Aggregate them all into mfill_state structure and pass this structure to functions that implement various UFFDIO_ commands. Tracking the state in a structure will allow moving the code that retries copying of data for UFFDIO_COPY into mfill_atomic_pte_copy() and make the loop in mfill_atomic() identical for all UFFDIO operations on PTE-mapped memory. The mfill_state definition is deliberately local to mm/userfaultfd.c, hence shmem_mfill_atomic_pte() is not updated. Signed-off-by: Mike Rapoport (Microsoft) --- mm/userfaultfd.c | 148 ++++++++++++++++++++++++++--------------------- 1 file changed, 82 insertions(+), 66 deletions(-) diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c index a0885d543f22..6a0697c93ff4 100644 --- a/mm/userfaultfd.c +++ b/mm/userfaultfd.c @@ -20,6 +20,20 @@ #include "internal.h" #include "swap.h" =20 +struct mfill_state { + struct userfaultfd_ctx *ctx; + unsigned long src_start; + unsigned long dst_start; + unsigned long len; + uffd_flags_t flags; + + struct vm_area_struct *vma; + unsigned long src_addr; + unsigned long dst_addr; + struct folio *folio; + pmd_t *pmd; +}; + static __always_inline bool validate_dst_vma(struct vm_area_struct *dst_vma, unsigned long dst_en= d) { @@ -272,17 +286,17 @@ static int mfill_copy_folio_locked(struct folio *foli= o, unsigned long src_addr) return ret; } =20 -static int mfill_atomic_pte_copy(pmd_t *dst_pmd, - struct vm_area_struct *dst_vma, - unsigned long dst_addr, - unsigned long src_addr, - uffd_flags_t flags, - struct folio **foliop) +static int mfill_atomic_pte_copy(struct mfill_state *state) { - int ret; + struct vm_area_struct *dst_vma =3D state->vma; + unsigned long dst_addr =3D state->dst_addr; + unsigned long src_addr =3D state->src_addr; + uffd_flags_t flags =3D state->flags; + pmd_t *dst_pmd =3D state->pmd; struct folio *folio; + int ret; =20 - if (!*foliop) { + if (!state->folio) { ret =3D -ENOMEM; folio =3D vma_alloc_folio(GFP_HIGHUSER_MOVABLE, 0, dst_vma, dst_addr); @@ -294,13 +308,13 @@ static int mfill_atomic_pte_copy(pmd_t *dst_pmd, /* fallback to copy_from_user outside mmap_lock */ if (unlikely(ret)) { ret =3D -ENOENT; - *foliop =3D folio; + state->folio =3D folio; /* don't free the page */ goto out; } } else { - folio =3D *foliop; - *foliop =3D NULL; + folio =3D state->folio; + state->folio =3D NULL; } =20 /* @@ -357,10 +371,11 @@ static int mfill_atomic_pte_zeroed_folio(pmd_t *dst_p= md, return ret; } =20 -static int mfill_atomic_pte_zeropage(pmd_t *dst_pmd, - struct vm_area_struct *dst_vma, - unsigned long dst_addr) +static int mfill_atomic_pte_zeropage(struct mfill_state *state) { + struct vm_area_struct *dst_vma =3D state->vma; + unsigned long dst_addr =3D state->dst_addr; + pmd_t *dst_pmd =3D state->pmd; pte_t _dst_pte, *dst_pte; spinlock_t *ptl; int ret; @@ -392,13 +407,14 @@ static int mfill_atomic_pte_zeropage(pmd_t *dst_pmd, } =20 /* Handles UFFDIO_CONTINUE for all shmem VMAs (shared or private). */ -static int mfill_atomic_pte_continue(pmd_t *dst_pmd, - struct vm_area_struct *dst_vma, - unsigned long dst_addr, - uffd_flags_t flags) +static int mfill_atomic_pte_continue(struct mfill_state *state) { - struct inode *inode =3D file_inode(dst_vma->vm_file); + struct vm_area_struct *dst_vma =3D state->vma; + unsigned long dst_addr =3D state->dst_addr; pgoff_t pgoff =3D linear_page_index(dst_vma, dst_addr); + struct inode *inode =3D file_inode(dst_vma->vm_file); + uffd_flags_t flags =3D state->flags; + pmd_t *dst_pmd =3D state->pmd; struct folio *folio; struct page *page; int ret; @@ -436,15 +452,15 @@ static int mfill_atomic_pte_continue(pmd_t *dst_pmd, } =20 /* Handles UFFDIO_POISON for all non-hugetlb VMAs. */ -static int mfill_atomic_pte_poison(pmd_t *dst_pmd, - struct vm_area_struct *dst_vma, - unsigned long dst_addr, - uffd_flags_t flags) +static int mfill_atomic_pte_poison(struct mfill_state *state) { - int ret; + struct vm_area_struct *dst_vma =3D state->vma; struct mm_struct *dst_mm =3D dst_vma->vm_mm; + unsigned long dst_addr =3D state->dst_addr; + pmd_t *dst_pmd =3D state->pmd; pte_t _dst_pte, *dst_pte; spinlock_t *ptl; + int ret; =20 _dst_pte =3D make_pte_marker(PTE_MARKER_POISONED); ret =3D -EAGAIN; @@ -668,22 +684,20 @@ extern ssize_t mfill_atomic_hugetlb(struct userfaultf= d_ctx *ctx, uffd_flags_t flags); #endif /* CONFIG_HUGETLB_PAGE */ =20 -static __always_inline ssize_t mfill_atomic_pte(pmd_t *dst_pmd, - struct vm_area_struct *dst_vma, - unsigned long dst_addr, - unsigned long src_addr, - uffd_flags_t flags, - struct folio **foliop) +static __always_inline ssize_t mfill_atomic_pte(struct mfill_state *state) { + struct vm_area_struct *dst_vma =3D state->vma; + unsigned long src_addr =3D state->src_addr; + unsigned long dst_addr =3D state->dst_addr; + struct folio **foliop =3D &state->folio; + uffd_flags_t flags =3D state->flags; + pmd_t *dst_pmd =3D state->pmd; ssize_t err; =20 - if (uffd_flags_mode_is(flags, MFILL_ATOMIC_CONTINUE)) { - return mfill_atomic_pte_continue(dst_pmd, dst_vma, - dst_addr, flags); - } else if (uffd_flags_mode_is(flags, MFILL_ATOMIC_POISON)) { - return mfill_atomic_pte_poison(dst_pmd, dst_vma, - dst_addr, flags); - } + if (uffd_flags_mode_is(flags, MFILL_ATOMIC_CONTINUE)) + return mfill_atomic_pte_continue(state); + if (uffd_flags_mode_is(flags, MFILL_ATOMIC_POISON)) + return mfill_atomic_pte_poison(state); =20 /* * The normal page fault path for a shmem will invoke the @@ -697,12 +711,9 @@ static __always_inline ssize_t mfill_atomic_pte(pmd_t = *dst_pmd, */ if (!(dst_vma->vm_flags & VM_SHARED)) { if (uffd_flags_mode_is(flags, MFILL_ATOMIC_COPY)) - err =3D mfill_atomic_pte_copy(dst_pmd, dst_vma, - dst_addr, src_addr, - flags, foliop); + err =3D mfill_atomic_pte_copy(state); else - err =3D mfill_atomic_pte_zeropage(dst_pmd, - dst_vma, dst_addr); + err =3D mfill_atomic_pte_zeropage(state); } else { err =3D shmem_mfill_atomic_pte(dst_pmd, dst_vma, dst_addr, src_addr, @@ -718,13 +729,20 @@ static __always_inline ssize_t mfill_atomic(struct us= erfaultfd_ctx *ctx, unsigned long len, uffd_flags_t flags) { + struct mfill_state state =3D (struct mfill_state){ + .ctx =3D ctx, + .dst_start =3D dst_start, + .src_start =3D src_start, + .flags =3D flags, + + .src_addr =3D src_start, + .dst_addr =3D dst_start, + }; struct mm_struct *dst_mm =3D ctx->mm; struct vm_area_struct *dst_vma; + long copied =3D 0; ssize_t err; pmd_t *dst_pmd; - unsigned long src_addr, dst_addr; - long copied; - struct folio *folio; =20 /* * Sanitize the command parameters: @@ -736,10 +754,6 @@ static __always_inline ssize_t mfill_atomic(struct use= rfaultfd_ctx *ctx, VM_WARN_ON_ONCE(src_start + len <=3D src_start); VM_WARN_ON_ONCE(dst_start + len <=3D dst_start); =20 - src_addr =3D src_start; - dst_addr =3D dst_start; - copied =3D 0; - folio =3D NULL; retry: /* * Make sure the vma is not shared, that the dst range is @@ -790,12 +804,14 @@ static __always_inline ssize_t mfill_atomic(struct us= erfaultfd_ctx *ctx, uffd_flags_mode_is(flags, MFILL_ATOMIC_CONTINUE)) goto out_unlock; =20 - while (src_addr < src_start + len) { - pmd_t dst_pmdval; + state.vma =3D dst_vma; =20 - VM_WARN_ON_ONCE(dst_addr >=3D dst_start + len); + while (state.src_addr < src_start + len) { + VM_WARN_ON_ONCE(state.dst_addr >=3D dst_start + len); + + pmd_t dst_pmdval; =20 - dst_pmd =3D mm_alloc_pmd(dst_mm, dst_addr); + dst_pmd =3D mm_alloc_pmd(dst_mm, state.dst_addr); if (unlikely(!dst_pmd)) { err =3D -ENOMEM; break; @@ -827,34 +843,34 @@ static __always_inline ssize_t mfill_atomic(struct us= erfaultfd_ctx *ctx, * tables under us; pte_offset_map_lock() will deal with that. */ =20 - err =3D mfill_atomic_pte(dst_pmd, dst_vma, dst_addr, - src_addr, flags, &folio); + state.pmd =3D dst_pmd; + err =3D mfill_atomic_pte(&state); cond_resched(); =20 if (unlikely(err =3D=3D -ENOENT)) { void *kaddr; =20 up_read(&ctx->map_changing_lock); - uffd_mfill_unlock(dst_vma); - VM_WARN_ON_ONCE(!folio); + uffd_mfill_unlock(state.vma); + VM_WARN_ON_ONCE(!state.folio); =20 - kaddr =3D kmap_local_folio(folio, 0); + kaddr =3D kmap_local_folio(state.folio, 0); err =3D copy_from_user(kaddr, - (const void __user *) src_addr, + (const void __user *)state.src_addr, PAGE_SIZE); kunmap_local(kaddr); if (unlikely(err)) { err =3D -EFAULT; goto out; } - flush_dcache_folio(folio); + flush_dcache_folio(state.folio); goto retry; } else - VM_WARN_ON_ONCE(folio); + VM_WARN_ON_ONCE(state.folio); =20 if (!err) { - dst_addr +=3D PAGE_SIZE; - src_addr +=3D PAGE_SIZE; + state.dst_addr +=3D PAGE_SIZE; + state.src_addr +=3D PAGE_SIZE; copied +=3D PAGE_SIZE; =20 if (fatal_signal_pending(current)) @@ -866,10 +882,10 @@ static __always_inline ssize_t mfill_atomic(struct us= erfaultfd_ctx *ctx, =20 out_unlock: up_read(&ctx->map_changing_lock); - uffd_mfill_unlock(dst_vma); + uffd_mfill_unlock(state.vma); out: - if (folio) - folio_put(folio); + if (state.folio) + folio_put(state.folio); VM_WARN_ON_ONCE(copied < 0); VM_WARN_ON_ONCE(err > 0); VM_WARN_ON_ONCE(!copied && !err); --=20 2.51.0