[PATCH RFC 1/3] mm/pagewalk: allow folio_walk_start() under a vma read lock
From: Longlong Xia
Date: Sat Sep 12 2026 - 04:30:58 EST
From: Longlong Xia <xialonglong@xxxxxxxxxx>
Allow folio_walk_start() to use a vma read lock by replacing
mmap_assert_locked() with vma_assert_locked(). This lets KSM look
up pages without taking the mmap read lock.
The vma lock stabilizes the mapping, while page table locks serialize
entry updates. Callers walking another mm under the vma lock must
also hold an mm_users reference to prevent exit_mmap() from freeing
the page tables.
Assisted-by: Zcode:GLM-5.3
Signed-off-by: Longlong Xia <xialonglong@xxxxxxxxxx>
---
include/linux/pagewalk.h | 3 +++
mm/pagewalk.c | 11 +++++++++--
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/include/linux/pagewalk.h b/include/linux/pagewalk.h
index b41d7265c01b..cafd7b15f480 100644
--- a/include/linux/pagewalk.h
+++ b/include/linux/pagewalk.h
@@ -151,6 +151,9 @@ typedef int __bitwise folio_walk_flags_t;
/* Walk shared zeropages (small + huge) as well. */
#define FW_ZEROPAGE ((__force folio_walk_flags_t)BIT(0))
+/* The caller holds the VMA read lock instead of the mmap lock. */
+#define FW_VMA_LOCKED ((__force folio_walk_flags_t)BIT(1))
+
enum folio_walk_level {
FW_LEVEL_PTE,
FW_LEVEL_PMD,
diff --git a/mm/pagewalk.c b/mm/pagewalk.c
index cc07fcf50e87..57ffaf2a85b8 100644
--- a/mm/pagewalk.c
+++ b/mm/pagewalk.c
@@ -894,7 +894,11 @@ int walk_page_mapping(struct address_space *mapping, pgoff_t first_index,
* huge_ptep_set_*, ...). Note that the page table entry stored in @fw might
* not correspond to the first physical entry of a logical hugetlb entry.
*
- * The mmap lock must be held in read mode.
+ * The mmap lock must be held in read mode. Alternatively, with
+ * CONFIG_PER_VMA_LOCK and @FW_VMA_LOCKED, the vma lock may be held in read mode: the
+ * page tables of a read-locked vma cannot be torn down while the mm has
+ * users, so a caller that walks an mm other than its own must also hold a
+ * mm_users reference for the duration of the walk.
*
* Return: folio pointer on success, otherwise NULL.
*/
@@ -912,7 +916,10 @@ struct folio *folio_walk_start(struct folio_walk *fw,
pgd_t *pgdp;
p4d_t *p4dp;
- mmap_assert_locked(vma->vm_mm);
+ if (flags & FW_VMA_LOCKED)
+ vma_assert_locked(vma);
+ else
+ mmap_assert_locked(vma->vm_mm);
vma_pgtable_walk_begin(vma);
if (WARN_ON_ONCE(addr < vma->vm_start || addr >= vma->vm_end))
--
2.43.0