From nobody Sat Apr 4 03:26:50 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 6684E35FF5B; Thu, 2 Apr 2026 04:12:27 +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=1775103147; cv=none; b=sDt2tGHryhw4M1mfvG2vQ6mQBmpkk0cHaZgBibsnpNPEGFEbR1BVgSMBJyeW7DXXAL91JZvHDqvooa+II49dqI0mF+76EGEAed/dorOigeV7ON0vuTw1pT4255Qe/AO1e+EfgVWTMIX4lFnUF0HCl4kGxL3BpWxb76wWbyTqv84= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775103147; c=relaxed/simple; bh=r29RRcoEme4UqN+o6MMTGc0o3ga+E0dZNYRM9ni1tig=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Z7kU/4Ah1FSO7FhDCNQZCgbmV+wlsiXlbWrW4wM35iJBkp89zl/ngUeU3fgV6lGBwuEu9ogb0lfMK9jdB0m6JeXW3Z1K73xK/Ylzo69WpT8qBVp3VA4T7xIG7w2oxs727yxGjwvLSl+yKXXiUSteyoBqIh51ITEcHqdbv43zmmQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=W0wnJHed; 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="W0wnJHed" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9AFF1C19424; Thu, 2 Apr 2026 04:12:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1775103147; bh=r29RRcoEme4UqN+o6MMTGc0o3ga+E0dZNYRM9ni1tig=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=W0wnJHed8Py1/QjFAsaFbm+ktVcRQhSvRRsO7j8/qGRWjH3U5vvwyCxf0bJ4KQPQO 1arzTZm+aJtyigQO50fSmS7u19Y3yQ7VgvFbfsSKyUPAzBRScBsxpV8JXnBFzQz4uQ +u96RdoVp3uEPPycvXHZVuNBdAM6s7wH6UZWZK81+Rm0ymUd4vNR1HgHwsCJMRjUPD ALs4fw0e4BioIrIr/C9ko0uPbkL6pcA/DVZmdXmesGz6I1dPNfCIoThVdQDdRV/MUz Gqv16BEn6zNP5UFoikllMyeLKP7F4NViLB0Glc+YIZNbWco/xNS0ucpctdpW0P/PJe +f25Wy/Ruj5qQ== From: Mike Rapoport To: Andrew Morton Cc: Andrea Arcangeli , Andrei Vagin , Axel Rasmussen , Baolin Wang , David Hildenbrand , Harry Yoo , Hugh Dickins , James Houghton , "Liam R. Howlett" , "Lorenzo Stoakes (Oracle)" , "Matthew Wilcox (Oracle)" , Michal Hocko , Mike Rapoport , Muchun Song , Nikita Kalyazin , Oscar Salvador , Paolo Bonzini , Peter Xu , Sean Christopherson , Shuah Khan , Suren Baghdasaryan , Vlastimil Babka , kvm@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org, "Harry Yoo (Oracle)" Subject: [PATCH v4 03/15] userfaultfd: introduce mfill_establish_pmd() helper Date: Thu, 2 Apr 2026 07:11:44 +0300 Message-ID: <20260402041156.1377214-4-rppt@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260402041156.1377214-1-rppt@kernel.org> References: <20260402041156.1377214-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)" There is a lengthy code chunk in mfill_atomic() that establishes the PMD for UFFDIO operations. This code may be called twice: first time when the copy is performed with VMA/mm locks held and the other time after the copy is retried with locks dropped. Move the code that establishes a PMD into a helper function so it can be reused later during refactoring of mfill_atomic_pte_copy(). Signed-off-by: Mike Rapoport (Microsoft) Reviewed-by: Harry Yoo (Oracle) --- mm/userfaultfd.c | 102 ++++++++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 50 deletions(-) diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c index c4074b6f4aca..f653fb3f74df 100644 --- a/mm/userfaultfd.c +++ b/mm/userfaultfd.c @@ -157,6 +157,56 @@ static void uffd_mfill_unlock(struct vm_area_struct *v= ma) } #endif =20 +static pmd_t *mm_alloc_pmd(struct mm_struct *mm, unsigned long address) +{ + pgd_t *pgd; + p4d_t *p4d; + pud_t *pud; + + pgd =3D pgd_offset(mm, address); + p4d =3D p4d_alloc(mm, pgd, address); + if (!p4d) + return NULL; + pud =3D pud_alloc(mm, p4d, address); + if (!pud) + return NULL; + /* + * Note that we didn't run this because the pmd was + * missing, the *pmd may be already established and in + * turn it may also be a trans_huge_pmd. + */ + return pmd_alloc(mm, pud, address); +} + +static int mfill_establish_pmd(struct mfill_state *state) +{ + struct mm_struct *dst_mm =3D state->ctx->mm; + pmd_t *dst_pmd, dst_pmdval; + + dst_pmd =3D mm_alloc_pmd(dst_mm, state->dst_addr); + if (unlikely(!dst_pmd)) + return -ENOMEM; + + dst_pmdval =3D pmdp_get_lockless(dst_pmd); + if (unlikely(pmd_none(dst_pmdval)) && + unlikely(__pte_alloc(dst_mm, dst_pmd))) + return -ENOMEM; + + dst_pmdval =3D pmdp_get_lockless(dst_pmd); + /* + * If the dst_pmd is THP don't override it and just be strict. + * (This includes the case where the PMD used to be THP and + * changed back to none after __pte_alloc().) + */ + if (unlikely(!pmd_present(dst_pmdval) || pmd_leaf(dst_pmdval))) + return -EEXIST; + if (unlikely(pmd_bad(dst_pmdval))) + return -EFAULT; + + state->pmd =3D dst_pmd; + return 0; +} + /* Check if dst_addr is outside of file's size. Must be called with ptl he= ld. */ static bool mfill_file_over_size(struct vm_area_struct *dst_vma, unsigned long dst_addr) @@ -489,27 +539,6 @@ static int mfill_atomic_pte_poison(struct mfill_state = *state) return ret; } =20 -static pmd_t *mm_alloc_pmd(struct mm_struct *mm, unsigned long address) -{ - pgd_t *pgd; - p4d_t *p4d; - pud_t *pud; - - pgd =3D pgd_offset(mm, address); - p4d =3D p4d_alloc(mm, pgd, address); - if (!p4d) - return NULL; - pud =3D pud_alloc(mm, p4d, address); - if (!pud) - return NULL; - /* - * Note that we didn't run this because the pmd was - * missing, the *pmd may be already established and in - * turn it may also be a trans_huge_pmd. - */ - return pmd_alloc(mm, pud, address); -} - #ifdef CONFIG_HUGETLB_PAGE /* * mfill_atomic processing for HUGETLB vmas. Note that this routine is @@ -742,7 +771,6 @@ static __always_inline ssize_t mfill_atomic(struct user= faultfd_ctx *ctx, struct vm_area_struct *dst_vma; long copied =3D 0; ssize_t err; - pmd_t *dst_pmd; =20 /* * Sanitize the command parameters: @@ -808,41 +836,15 @@ static __always_inline ssize_t mfill_atomic(struct us= erfaultfd_ctx *ctx, while (state.src_addr < src_start + len) { VM_WARN_ON_ONCE(state.dst_addr >=3D dst_start + len); =20 - pmd_t dst_pmdval; - - dst_pmd =3D mm_alloc_pmd(dst_mm, state.dst_addr); - if (unlikely(!dst_pmd)) { - err =3D -ENOMEM; + err =3D mfill_establish_pmd(&state); + if (err) break; - } =20 - dst_pmdval =3D pmdp_get_lockless(dst_pmd); - if (unlikely(pmd_none(dst_pmdval)) && - unlikely(__pte_alloc(dst_mm, dst_pmd))) { - err =3D -ENOMEM; - break; - } - dst_pmdval =3D pmdp_get_lockless(dst_pmd); - /* - * If the dst_pmd is THP don't override it and just be strict. - * (This includes the case where the PMD used to be THP and - * changed back to none after __pte_alloc().) - */ - if (unlikely(!pmd_present(dst_pmdval) || - pmd_trans_huge(dst_pmdval))) { - err =3D -EEXIST; - break; - } - if (unlikely(pmd_bad(dst_pmdval))) { - err =3D -EFAULT; - break; - } /* * For shmem mappings, khugepaged is allowed to remove page * tables under us; pte_offset_map_lock() will deal with that. */ =20 - state.pmd =3D dst_pmd; err =3D mfill_atomic_pte(&state); cond_resched(); =20 --=20 2.53.0