All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dev Jain <dev.jain@arm.com>
To: akpm@linux-foundation.org, david@kernel.org, ljs@kernel.org
Cc: Dev Jain <dev.jain@arm.com>,
	liam@infradead.org, vbabka@kernel.org, rppt@kernel.org,
	surenb@google.com, mhocko@suse.com, kasong@tencent.com,
	qi.zheng@linux.dev, shakeel.butt@linux.dev, baohua@kernel.org,
	axelrasmussen@google.com, yuanchu@google.com, weixugc@google.com,
	linux-mm@kvack.org, linux-kernel@vger.kernel.org,
	riel@surriel.com, harry@kernel.org, jannh@google.com,
	lance.yang@linux.dev, ryan.roberts@arm.com,
	anshuman.khandual@arm.com
Subject: [PATCH 2/3] mm/memory: batch set uffd-wp markers during zapping
Date: Wed, 15 Jul 2026 11:18:35 +0000	[thread overview]
Message-ID: <20260715111839.1667914-3-dev.jain@arm.com> (raw)
In-Reply-To: <20260715111839.1667914-1-dev.jain@arm.com>

Enable batch setting of uffd-wp ptes.

The code paths passing nr > 1 to zap_install_uffd_wp_if_needed() produce
that nr through either folio_pte_batch or swap_pte_batch, therefore
batching is correct:

1) all ptes belong to the same type of VMA (anonymous or non-anonymous,
   wp-armed or non-wp-armed)

2) all ptes being marked with uffd-wp or all being not marked (same is the
   case with the pte_swp_uffd_wp_any check)

3) uffd_supports_wp_marker() is independent of the function parameters

Note that we will have to use set_pte_at() in a loop instead of set_ptes()
since the latter cannot handle present->non-present conversion for
nr_pages > 1.

Rename the function to cond_install_uffd_wp_ptes.

Signed-off-by: Dev Jain <dev.jain@arm.com>
---
To handle nonpresent->nonpresent transition in the ptes, we can have a
set_nonpresent_ptes() (in my unmap series) : if !softleaf_has_pfn(), use
set the same pte value to all ptep's in the patch. if softleaf_has_pfn(),
then add a softleaf_next_pfn() to construct the next softleaf, and
pte_next_softleaf() to call softleaf_next_pfn() and preserve the
wp bit, s-d bit, etc from the previous pte.

 include/linux/mm.h |  6 +++--
 mm/memory.c        | 64 +++++++++++++++++-----------------------------
 mm/rmap.c          |  2 +-
 3 files changed, 29 insertions(+), 43 deletions(-)

diff --git a/include/linux/mm.h b/include/linux/mm.h
index a71341c44655e..94e0a92bc70b1 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -5406,6 +5406,8 @@ void map_anon_folio_pte_nopf(struct folio *folio, pte_t *pte,
 		struct vm_area_struct *vma, unsigned long addr,
 		bool uffd_wp);
 
-bool pte_install_uffd_wp_if_needed(struct vm_area_struct *vma,
-		unsigned long addr, pte_t *ptep, pte_t pte);
+bool cond_install_uffd_wp_ptes(struct vm_area_struct *vma, unsigned long addr,
+			       pte_t *ptep, pte_t pte,
+			       unsigned long nr_ptes);
+
 #endif /* _LINUX_MM_H */
diff --git a/mm/memory.c b/mm/memory.c
index 98b3ace15cef2..5d2b567b383d4 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1676,27 +1676,29 @@ static inline bool zap_drop_markers(struct zap_details *details)
 }
 
 /**
- * pte_install_uffd_wp_if_needed - install uffd-wp marker after clearing a PTE
- * @vma: The VMA the page is mapped into.
- * @addr: Address the page is mapped at.
- * @ptep: Page table pointer for this entry.
+ * cond_install_uffd_wp_ptes - install uffd-wp markers after clearing PTEs
+ * @vma: The VMA the pages are mapped into.
+ * @addr: Address the first page of this batch is mapped at.
+ * @ptep: Page table pointer for the first entry of this batch.
  * @pte: Old value of the entry pointed to by @ptep.
+ * @nr_ptes: Number of entries to install.
  *
- * If the PTE was write-protected by uffd-wp in any form, arm a special PTE
- * to replace a none PTE. NOTE! This should only be called when the PTE is
- * already cleared so we will never accidentally replace something valuable.
- * Meanwhile none PTEs also mean we are not demoting the PTE so a TLB flush is
- * not needed. E.g., when the PTE was cleared, the caller should have taken care
- * of the TLB flush.
+ * If the PTEs were write-protected by uffd-wp in any form, arm special
+ * PTEs to replace none PTEs. NOTE! This should only be called when the PTEs
+ * are already cleared so we will never accidentally replace something
+ * valuable. Meanwhile none PTEs also mean we are not demoting the PTEs so a
+ * TLB flush is not needed. E.g., when PTEs were cleared, the caller should
+ * have taken care of the TLB flush.
  *
- * Must be called with the page table lock held so that no thread will see the
- * none PTE, and if they see it, they'll fault and serialize at the page table
- * lock.
+ * Must be called with the page table lock held so that no thread will see
+ * the none PTEs, and if they see them, they'll fault and serialize at the
+ * page table lock.
  *
- * Returns true if an uffd-wp PTE was installed, false otherwise.
+ * Returns true if uffd-wp PTEs were installed, false otherwise.
  */
-bool pte_install_uffd_wp_if_needed(struct vm_area_struct *vma,
-				   unsigned long addr, pte_t *ptep, pte_t pte)
+bool cond_install_uffd_wp_ptes(struct vm_area_struct *vma,
+		unsigned long addr, pte_t *ptep, pte_t pte,
+		unsigned long nr_ptes)
 {
 	bool arm_uffd_pte = false;
 
@@ -1726,13 +1728,14 @@ bool pte_install_uffd_wp_if_needed(struct vm_area_struct *vma,
 	if (unlikely(pte_swp_uffd_any(pte)))
 		arm_uffd_pte = true;
 
-	if (unlikely(arm_uffd_pte)) {
+	if (likely(!arm_uffd_pte))
+		return false;
+
+	for (unsigned long i = 0; i < nr_ptes; ++i, ++ptep, addr += PAGE_SIZE)
 		set_pte_at(vma->vm_mm, addr, ptep,
 			   make_pte_marker(PTE_MARKER_UFFD_WP));
-		return true;
-	}
 
-	return false;
+	return true;
 }
 
 /*
@@ -1746,29 +1749,10 @@ zap_install_uffd_wp_if_needed(struct vm_area_struct *vma,
 			      unsigned long addr, pte_t *pte, int nr,
 			      struct zap_details *details, pte_t pteval)
 {
-	bool was_installed = false;
-
-	if (!uffd_supports_wp_marker())
-		return false;
-
-	/* Zap on anonymous always means dropping everything */
-	if (vma_is_anonymous(vma))
-		return false;
-
 	if (zap_drop_markers(details))
 		return false;
 
-	for (;;) {
-		/* the PFN in the PTE is irrelevant. */
-		if (pte_install_uffd_wp_if_needed(vma, addr, pte, pteval))
-			was_installed = true;
-		if (--nr == 0)
-			break;
-		pte++;
-		addr += PAGE_SIZE;
-	}
-
-	return was_installed;
+	return cond_install_uffd_wp_ptes(vma, addr, pte, pteval, nr);
 }
 
 static __always_inline void zap_present_folio_ptes(struct mmu_gather *tlb,
diff --git a/mm/rmap.c b/mm/rmap.c
index ad820fe86f7d8..2f938d0ac6953 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -2345,7 +2345,7 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
 		 * we may want to replace a none pte with a marker pte if
 		 * it's file-backed, so we don't lose the tracking info.
 		 */
-		pte_install_uffd_wp_if_needed(vma, address, pvmw.pte, pteval);
+		cond_install_uffd_wp_ptes(vma, address, pvmw.pte, pteval, 1);
 
 		/* Update high watermark before we lower rss */
 		update_hiwater_rss(mm);
-- 
2.43.0


  parent reply	other threads:[~2026-07-15 11:19 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-15 11:18 [PATCH 0/3] Batch unmap of uffd-wp file folios Dev Jain
2026-07-15 11:18 ` [PATCH 1/3] mm/memory: move pte_install_uffd_wp_if_needed() into memory.c Dev Jain
2026-07-16  9:35   ` David Hildenbrand (Arm)
2026-07-16 10:06     ` Dev Jain
2026-07-15 11:18 ` Dev Jain [this message]
2026-07-16  9:41   ` [PATCH 2/3] mm/memory: batch set uffd-wp markers during zapping David Hildenbrand (Arm)
2026-07-16 10:08     ` Dev Jain
2026-07-15 11:18 ` [PATCH 3/3] mm/rmap: batch unmap file folios belonging to uffd-wp VMAs Dev Jain
2026-07-16  9:44   ` David Hildenbrand (Arm)
2026-07-15 18:58 ` [PATCH 0/3] Batch unmap of uffd-wp file folios Andrew Morton
2026-07-16  4:57   ` Dev Jain

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260715111839.1667914-3-dev.jain@arm.com \
    --to=dev.jain@arm.com \
    --cc=akpm@linux-foundation.org \
    --cc=anshuman.khandual@arm.com \
    --cc=axelrasmussen@google.com \
    --cc=baohua@kernel.org \
    --cc=david@kernel.org \
    --cc=harry@kernel.org \
    --cc=jannh@google.com \
    --cc=kasong@tencent.com \
    --cc=lance.yang@linux.dev \
    --cc=liam@infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=ljs@kernel.org \
    --cc=mhocko@suse.com \
    --cc=qi.zheng@linux.dev \
    --cc=riel@surriel.com \
    --cc=rppt@kernel.org \
    --cc=ryan.roberts@arm.com \
    --cc=shakeel.butt@linux.dev \
    --cc=surenb@google.com \
    --cc=vbabka@kernel.org \
    --cc=weixugc@google.com \
    --cc=yuanchu@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.