* [PATCH 0/6] userfaultfd: decouple uffd mode from VMA flags
@ 2026-08-23 12:17 Mike Rapoport (Microsoft)
2026-08-23 12:17 ` [PATCH 1/6] mm/gup: move gup_can_follow_protnone() to gup.c Mike Rapoport (Microsoft)
` (5 more replies)
0 siblings, 6 replies; 32+ messages in thread
From: Mike Rapoport (Microsoft) @ 2026-08-23 12:17 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand
Cc: Baolin Wang, Barry Song, Dev Jain, Hugh Dickins, Jann Horn,
Jason Gunthorpe, John Hubbard, Jonathan Corbet, Lance Yang,
Liam R. Howlett, Lorenzo Stoakes, Masami Hiramatsu,
Mathieu Desnoyers, Mike Rapoport, Michal Hocko, Muchun Song,
Nico Pache, Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, Zi Yan, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
Currently userfault related VMA flags have multiple meanings:
* identify VMAs that are registered with userfaultfd
* and also how exactly VMA is registered with uffd
* and also communicate kind of user fault between the page fault handler
and handle_userfault()
Introduce an enum for user fault reasons and move the registration mode
into per VMA vm_uffd_state structure today known as vm_userfaultfd_ctx.
---
Mike Rapoport (Microsoft) (6):
mm/gup: move gup_can_follow_protnone() to gup.c
userfaultfd: constify VMA parameter of userfaultfd_*() helpers
userfaultfd: use userfaultfd_*() helpers instead of open coded flag tests
userfaultfd: rename vm_userfaultfd_ctx to vm_uffd_state
userfaultfd: decouple fault reason from VMA flags
userfaultfd: collapse VM_UFFD_{MISSING,WP,MINOR,RWP} into single VM_UFFD
Documentation/mm/process_addrs.rst | 4 +-
fs/proc/task_mmu.c | 18 +--
include/linux/mm.h | 105 +++--------------
include/linux/mm_types.h | 11 +-
include/linux/pgtable.h | 4 +-
include/linux/userfaultfd_k.h | 155 ++++++++++++++-----------
include/trace/events/mmflags.h | 17 +--
include/uapi/linux/userfaultfd.h | 6 +-
mm/gup.c | 39 +++++++
mm/huge_memory.c | 6 +-
mm/hugetlb.c | 12 +-
mm/khugepaged.c | 2 +-
mm/memory.c | 16 +--
mm/mprotect.c | 2 +-
mm/mremap.c | 4 +-
mm/shmem.c | 6 +-
mm/userfaultfd.c | 225 +++++++++++++++++++------------------
mm/vma.c | 4 +-
mm/vma.h | 6 +-
mm/vma_init.c | 4 +-
tools/testing/vma/include/dup.h | 20 ++--
tools/testing/vma/include/stubs.h | 6 +-
22 files changed, 323 insertions(+), 349 deletions(-)
---
base-commit: 4b2ae13f3393ef4b4bce0021e8762790354f369f
change-id: 20260823-uffd-vm-flags-v1-ee3e131b381d
--
Sincerely yours,
Mike.
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH 1/6] mm/gup: move gup_can_follow_protnone() to gup.c
2026-08-23 12:17 [PATCH 0/6] userfaultfd: decouple uffd mode from VMA flags Mike Rapoport (Microsoft)
@ 2026-08-23 12:17 ` Mike Rapoport (Microsoft)
2026-08-23 21:03 ` Barry Song
` (3 more replies)
2026-08-23 12:17 ` [PATCH 2/6] userfaultfd: constify VMA parameter of userfaultfd_*() helpers Mike Rapoport (Microsoft)
` (4 subsequent siblings)
5 siblings, 4 replies; 32+ messages in thread
From: Mike Rapoport (Microsoft) @ 2026-08-23 12:17 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand
Cc: Baolin Wang, Barry Song, Dev Jain, Hugh Dickins, Jann Horn,
Jason Gunthorpe, John Hubbard, Jonathan Corbet, Lance Yang,
Liam R. Howlett, Lorenzo Stoakes, Masami Hiramatsu,
Mathieu Desnoyers, Mike Rapoport, Michal Hocko, Muchun Song,
Nico Pache, Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, Zi Yan, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
gup_can_follow_protnone() is defined in include/linux/mm.h but only used
by mm/gup.c.
First, there is no reason to have it in already gigantic header.
Next, the upcoming refactoring of userfaultfd flags will make
gup_can_follow_protnone() depend on userfaultfd_k.h which would cause a
cyclic header dependency.
Move gup_can_follow_protnone() to mm/gup.c.
No functional change.
Assisted-by: copilot:claude-opus-5
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
---
include/linux/mm.h | 38 --------------------------------------
mm/gup.c | 38 ++++++++++++++++++++++++++++++++++++++
2 files changed, 38 insertions(+), 38 deletions(-)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 0829e0d3b2d1..4daf9cd6ae8e 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -4860,44 +4860,6 @@ static inline int vm_fault_to_errno(vm_fault_t vm_fault, int foll_flags)
return 0;
}
-/*
- * Indicates whether GUP can follow a PROT_NONE mapped page, or whether
- * a (NUMA hinting or userfaultfd RWP) fault is required.
- */
-static inline bool gup_can_follow_protnone(const struct vm_area_struct *vma,
- unsigned int flags)
-{
- /*
- * VM_UFFD_RWP uses protnone as an access-tracking marker, not for
- * NUMA hinting. GUP must always take a fault so the access is
- * delivered to userfaultfd, regardless of FOLL_HONOR_NUMA_FAULT.
- *
- * Only do so while the VMA is accessible. If it has been made
- * inaccessible (e.g. mprotect(PROT_NONE)), fall through to the guard
- * below: forcing a fault there would loop, as handle_mm_fault() makes
- * no progress on protnone in an inaccessible VMA, and the access is
- * denied regardless of RWP anyway.
- */
- if (vma_test_single_mask(vma, VMA_UFFD_RWP) && vma_is_accessible(vma))
- return false;
-
- /*
- * If callers don't want to honor NUMA hinting faults, no need to
- * determine if we would actually have to trigger a NUMA hinting fault.
- */
- if (!(flags & FOLL_HONOR_NUMA_FAULT))
- return true;
-
- /*
- * NUMA hinting faults don't apply in inaccessible (PROT_NONE) VMAs.
- *
- * Requiring a fault here even for inaccessible VMAs would mean that
- * FOLL_FORCE cannot make any progress, because handle_mm_fault()
- * refuses to process NUMA hinting faults in inaccessible VMAs.
- */
- return !vma_is_accessible(vma);
-}
-
typedef int (*pte_fn_t)(pte_t *pte, unsigned long addr, void *data);
extern int apply_to_page_range(struct mm_struct *mm, unsigned long address,
unsigned long size, pte_fn_t fn, void *data);
diff --git a/mm/gup.c b/mm/gup.c
index eb898ea1ee22..500e2aa99e48 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -633,6 +633,44 @@ static struct page *no_page_table(struct vm_area_struct *vma,
return NULL;
}
+/*
+ * Indicates whether GUP can follow a PROT_NONE mapped page, or whether
+ * a (NUMA hinting or userfaultfd RWP) fault is required.
+ */
+static inline bool gup_can_follow_protnone(const struct vm_area_struct *vma,
+ unsigned int flags)
+{
+ /*
+ * VM_UFFD_RWP uses protnone as an access-tracking marker, not for
+ * NUMA hinting. GUP must always take a fault so the access is
+ * delivered to userfaultfd, regardless of FOLL_HONOR_NUMA_FAULT.
+ *
+ * Only do so while the VMA is accessible. If it has been made
+ * inaccessible (e.g. mprotect(PROT_NONE)), fall through to the guard
+ * below: forcing a fault there would loop, as handle_mm_fault() makes
+ * no progress on protnone in an inaccessible VMA, and the access is
+ * denied regardless of RWP anyway.
+ */
+ if (vma_test_single_mask(vma, VMA_UFFD_RWP) && vma_is_accessible(vma))
+ return false;
+
+ /*
+ * If callers don't want to honor NUMA hinting faults, no need to
+ * determine if we would actually have to trigger a NUMA hinting fault.
+ */
+ if (!(flags & FOLL_HONOR_NUMA_FAULT))
+ return true;
+
+ /*
+ * NUMA hinting faults don't apply in inaccessible (PROT_NONE) VMAs.
+ *
+ * Requiring a fault here even for inaccessible VMAs would mean that
+ * FOLL_FORCE cannot make any progress, because handle_mm_fault()
+ * refuses to process NUMA hinting faults in inaccessible VMAs.
+ */
+ return !vma_is_accessible(vma);
+}
+
#ifdef CONFIG_PGTABLE_HAS_HUGE_LEAVES
/* FOLL_FORCE can write to even unwritable PUDs in COW mappings. */
static inline bool can_follow_write_pud(pud_t pud, struct page *page,
--
2.53.0
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH 2/6] userfaultfd: constify VMA parameter of userfaultfd_*() helpers
2026-08-23 12:17 [PATCH 0/6] userfaultfd: decouple uffd mode from VMA flags Mike Rapoport (Microsoft)
2026-08-23 12:17 ` [PATCH 1/6] mm/gup: move gup_can_follow_protnone() to gup.c Mike Rapoport (Microsoft)
@ 2026-08-23 12:17 ` Mike Rapoport (Microsoft)
2026-08-23 21:03 ` Barry Song
` (2 more replies)
2026-08-23 12:17 ` [PATCH 3/6] userfaultfd: use userfaultfd_*() helpers instead of open coded flag tests Mike Rapoport (Microsoft)
` (3 subsequent siblings)
5 siblings, 3 replies; 32+ messages in thread
From: Mike Rapoport (Microsoft) @ 2026-08-23 12:17 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand
Cc: Baolin Wang, Barry Song, Dev Jain, Hugh Dickins, Jann Horn,
Jason Gunthorpe, John Hubbard, Jonathan Corbet, Lance Yang,
Liam R. Howlett, Lorenzo Stoakes, Masami Hiramatsu,
Mathieu Desnoyers, Mike Rapoport, Michal Hocko, Muchun Song,
Nico Pache, Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, Zi Yan, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
userfaultfd_{missing,wp,minor,rwp}() and userfaultfd_protected() only
read the VMA.
Make their vma parameter const.
No functional change.
Assisted-by: copilot:claude-opus-5
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
---
include/linux/userfaultfd_k.h | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
index a4351cffc60c..3396d270b159 100644
--- a/include/linux/userfaultfd_k.h
+++ b/include/linux/userfaultfd_k.h
@@ -204,22 +204,22 @@ static inline bool uffd_disable_fault_around(struct vm_area_struct *vma)
VMA_UFFD_MINOR));
}
-static inline bool userfaultfd_missing(struct vm_area_struct *vma)
+static inline bool userfaultfd_missing(const struct vm_area_struct *vma)
{
return vma_test_any_mask(vma, VMA_UFFD_MISSING);
}
-static inline bool userfaultfd_wp(struct vm_area_struct *vma)
+static inline bool userfaultfd_wp(const struct vm_area_struct *vma)
{
return vma_test_any_mask(vma, VMA_UFFD_WP);
}
-static inline bool userfaultfd_minor(struct vm_area_struct *vma)
+static inline bool userfaultfd_minor(const struct vm_area_struct *vma)
{
return vma_test_any_mask(vma, VMA_UFFD_MINOR);
}
-static inline bool userfaultfd_rwp(struct vm_area_struct *vma)
+static inline bool userfaultfd_rwp(const struct vm_area_struct *vma)
{
/*
* Callers gate PAGE_NONE usage on this; PAGE_NONE is a BUILD_BUG()
@@ -230,7 +230,7 @@ static inline bool userfaultfd_rwp(struct vm_area_struct *vma)
return vma_test_single_mask(vma, VMA_UFFD_RWP);
}
-static inline bool userfaultfd_protected(struct vm_area_struct *vma)
+static inline bool userfaultfd_protected(const struct vm_area_struct *vma)
{
return userfaultfd_wp(vma) || userfaultfd_rwp(vma);
}
@@ -353,27 +353,27 @@ static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
return true;
}
-static inline bool userfaultfd_missing(struct vm_area_struct *vma)
+static inline bool userfaultfd_missing(const struct vm_area_struct *vma)
{
return false;
}
-static inline bool userfaultfd_wp(struct vm_area_struct *vma)
+static inline bool userfaultfd_wp(const struct vm_area_struct *vma)
{
return false;
}
-static inline bool userfaultfd_minor(struct vm_area_struct *vma)
+static inline bool userfaultfd_minor(const struct vm_area_struct *vma)
{
return false;
}
-static inline bool userfaultfd_rwp(struct vm_area_struct *vma)
+static inline bool userfaultfd_rwp(const struct vm_area_struct *vma)
{
return false;
}
-static inline bool userfaultfd_protected(struct vm_area_struct *vma)
+static inline bool userfaultfd_protected(const struct vm_area_struct *vma)
{
return false;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH 3/6] userfaultfd: use userfaultfd_*() helpers instead of open coded flag tests
2026-08-23 12:17 [PATCH 0/6] userfaultfd: decouple uffd mode from VMA flags Mike Rapoport (Microsoft)
2026-08-23 12:17 ` [PATCH 1/6] mm/gup: move gup_can_follow_protnone() to gup.c Mike Rapoport (Microsoft)
2026-08-23 12:17 ` [PATCH 2/6] userfaultfd: constify VMA parameter of userfaultfd_*() helpers Mike Rapoport (Microsoft)
@ 2026-08-23 12:17 ` Mike Rapoport (Microsoft)
2026-08-23 21:14 ` Barry Song
2026-08-24 15:10 ` Lorenzo Stoakes (ARM)
2026-08-23 12:17 ` [PATCH 4/6] userfaultfd: rename vm_userfaultfd_ctx to vm_uffd_state Mike Rapoport (Microsoft)
` (2 subsequent siblings)
5 siblings, 2 replies; 32+ messages in thread
From: Mike Rapoport (Microsoft) @ 2026-08-23 12:17 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand
Cc: Baolin Wang, Barry Song, Dev Jain, Hugh Dickins, Jann Horn,
Jason Gunthorpe, John Hubbard, Jonathan Corbet, Lance Yang,
Liam R. Howlett, Lorenzo Stoakes, Masami Hiramatsu,
Mathieu Desnoyers, Mike Rapoport, Michal Hocko, Muchun Song,
Nico Pache, Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, Zi Yan, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
Move userfaultfd_{missing,wp,minor,rwp}() and userfaultfd_protected()
ahead of uffd_disable_huge_pmd_share() and uffd_disable_fault_around()
and make the latter two use the helpers rather than open coded VMA flag
masks.
Convert open coded VMA flag test in mfill_get_vma() to userfaultfd_wp()
as well.
With every user of the per-VMA uffd modes going through the helpers,
their underlying representation can be changed in the next step.
No functional change.
Assisted-by: copilot:claude-opus-5
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
---
include/linux/userfaultfd_k.h | 70 +++++++++++++++++++++----------------------
mm/userfaultfd.c | 2 +-
2 files changed, 35 insertions(+), 37 deletions(-)
diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
index 3396d270b159..d8262e3dc134 100644
--- a/include/linux/userfaultfd_k.h
+++ b/include/linux/userfaultfd_k.h
@@ -168,42 +168,6 @@ static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
return vma->vm_userfaultfd_ctx.ctx == vm_ctx.ctx;
}
-/*
- * Never enable huge pmd sharing on some uffd registered vmas:
- *
- * - VM_UFFD_WP and VM_UFFD_RWP VMAs, because the write protect / access
- * tracking information is per pgtable entry.
- *
- * - VM_UFFD_MINOR VMAs, because otherwise we would never get minor faults for
- * VMAs which share huge pmds. (If you have two mappings to the same
- * underlying pages, and fault in the non-UFFD-registered one with a write,
- * with huge pmd sharing this would *also* setup the second UFFD-registered
- * mapping, and we'd not get minor faults.)
- */
-static inline bool uffd_disable_huge_pmd_share(struct vm_area_struct *vma)
-{
- return vma_test_any_mask(vma,
- mk_vma_flags_from_masks(VMA_UFFD_WP, VMA_UFFD_RWP,
- VMA_UFFD_MINOR));
-}
-
-/*
- * Don't do fault around for WP, RWP or MINOR registered uffd range. For
- * MINOR registered range, fault around will be a total disaster and ptes can
- * be installed without notifications; for WP it should mostly be fine as long
- * as the fault around checks for pte_none() before the installation, however
- * to be super safe we just forbid it; for RWP, pre-faulted neighbours would
- * be indistinguishable from accessed pages in PAGEMAP_SCAN (PAGE_IS_ACCESSED)
- * and pollute the tracked working set, so each page must be populated by its
- * own fault.
- */
-static inline bool uffd_disable_fault_around(struct vm_area_struct *vma)
-{
- return vma_test_any_mask(vma,
- mk_vma_flags_from_masks(VMA_UFFD_WP, VMA_UFFD_RWP,
- VMA_UFFD_MINOR));
-}
-
static inline bool userfaultfd_missing(const struct vm_area_struct *vma)
{
return vma_test_any_mask(vma, VMA_UFFD_MISSING);
@@ -235,6 +199,40 @@ static inline bool userfaultfd_protected(const struct vm_area_struct *vma)
return userfaultfd_wp(vma) || userfaultfd_rwp(vma);
}
+/*
+ * Never enable huge pmd sharing on some uffd registered vmas:
+ *
+ * - uffd-WP and uffd-RWP VMAs, because the write protect / access tracking
+ * information is per pgtable entry.
+ *
+ * - uffd-MINOR VMAs, because otherwise we would never get minor faults for
+ * VMAs which share huge pmds. (If you have two mappings to the same
+ * underlying pages, and fault in the non-UFFD-registered one with a write,
+ * with huge pmd sharing this would *also* setup the second UFFD-registered
+ * mapping, and we'd not get minor faults.)
+ */
+static inline bool uffd_disable_huge_pmd_share(struct vm_area_struct *vma)
+{
+ return userfaultfd_minor(vma) || userfaultfd_wp(vma) ||
+ userfaultfd_rwp(vma);
+}
+
+/*
+ * Don't do fault around for WP, RWP or MINOR registered uffd range. For
+ * MINOR registered range, fault around will be a total disaster and ptes can
+ * be installed without notifications; for WP it should mostly be fine as long
+ * as the fault around checks for pte_none() before the installation, however
+ * to be super safe we just forbid it; for RWP, pre-faulted neighbours would
+ * be indistinguishable from accessed pages in PAGEMAP_SCAN (PAGE_IS_ACCESSED)
+ * and pollute the tracked working set, so each page must be populated by its
+ * own fault.
+ */
+static inline bool uffd_disable_fault_around(struct vm_area_struct *vma)
+{
+ return userfaultfd_minor(vma) || userfaultfd_wp(vma) ||
+ userfaultfd_rwp(vma);
+}
+
static inline bool userfaultfd_pte_wp(struct vm_area_struct *vma,
pte_t pte)
{
diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index 74f04c323c50..32003aa04943 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -261,7 +261,7 @@ static int mfill_get_vma(struct mfill_state *state)
* validate 'mode' now that we know the dst_vma: don't allow
* a wrprotect copy if the userfaultfd didn't register as WP.
*/
- if ((flags & MFILL_ATOMIC_WP) && !(dst_vma->vm_flags & VM_UFFD_WP))
+ if ((flags & MFILL_ATOMIC_WP) && !userfaultfd_wp(dst_vma))
goto out_unlock;
if (is_vm_hugetlb_page(dst_vma))
--
2.53.0
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH 4/6] userfaultfd: rename vm_userfaultfd_ctx to vm_uffd_state
2026-08-23 12:17 [PATCH 0/6] userfaultfd: decouple uffd mode from VMA flags Mike Rapoport (Microsoft)
` (2 preceding siblings ...)
2026-08-23 12:17 ` [PATCH 3/6] userfaultfd: use userfaultfd_*() helpers instead of open coded flag tests Mike Rapoport (Microsoft)
@ 2026-08-23 12:17 ` Mike Rapoport (Microsoft)
2026-08-24 14:43 ` David Hildenbrand (Arm)
2026-08-24 15:42 ` Lorenzo Stoakes (ARM)
2026-08-23 12:17 ` [PATCH 5/6] userfaultfd: decouple fault reason from VMA flags Mike Rapoport (Microsoft)
2026-08-23 12:17 ` [PATCH 6/6] userfaultfd: collapse VM_UFFD_{MISSING,WP,MINOR,RWP} into single VM_UFFD Mike Rapoport (Microsoft)
5 siblings, 2 replies; 32+ messages in thread
From: Mike Rapoport (Microsoft) @ 2026-08-23 12:17 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand
Cc: Baolin Wang, Barry Song, Dev Jain, Hugh Dickins, Jann Horn,
Jason Gunthorpe, John Hubbard, Jonathan Corbet, Lance Yang,
Liam R. Howlett, Lorenzo Stoakes, Masami Hiramatsu,
Mathieu Desnoyers, Mike Rapoport, Michal Hocko, Muchun Song,
Nico Pache, Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, Zi Yan, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
Rename struct vm_userfaultfd_ctx to vm_uffd_state to better reflect that
it will represent the userfaultfd state for a VMA rather than just a
context pointer.
This is a preparatory step for extending the struct with a mode field.
Mechanical rename, no functional change.
Assisted-by: copilot:claude-opus-4.6
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
---
Documentation/mm/process_addrs.rst | 4 +--
include/linux/mm_types.h | 10 +++---
include/linux/userfaultfd_k.h | 24 ++++++-------
mm/mremap.c | 4 +--
mm/userfaultfd.c | 74 +++++++++++++++++++-------------------
mm/vma.c | 4 +--
mm/vma.h | 6 ++--
mm/vma_init.c | 4 +--
tools/testing/vma/include/dup.h | 2 +-
tools/testing/vma/include/stubs.h | 6 ++--
10 files changed, 69 insertions(+), 69 deletions(-)
diff --git a/Documentation/mm/process_addrs.rst b/Documentation/mm/process_addrs.rst
index a7296f251799..481e9435e4e8 100644
--- a/Documentation/mm/process_addrs.rst
+++ b/Documentation/mm/process_addrs.rst
@@ -229,8 +229,8 @@ These are the core fields which describe the MM the VMA belongs to and its attri
NUMA balancing in relation to this VMA. lock.
Updated under mmap read lock by
:c:func:`!task_numa_work`.
- :c:member:`!vm_userfaultfd_ctx` CONFIG_USERFAULTFD Userfaultfd context wrapper object of mmap write,
- type :c:type:`!vm_userfaultfd_ctx`, VMA write.
+ :c:member:`!vm_uffd_state` CONFIG_USERFAULTFD Userfaultfd context wrapper object of mmap write,
+ type :c:type:`!vm_uffd_state`, VMA write.
either of zero size if userfaultfd is
disabled, or containing a pointer
to an underlying
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 6d815f6440c9..d6deb655d82e 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -720,13 +720,13 @@ struct vm_region {
};
#ifdef CONFIG_USERFAULTFD
-#define NULL_VM_UFFD_CTX ((struct vm_userfaultfd_ctx) { NULL, })
-struct vm_userfaultfd_ctx {
+#define NULL_VM_UFFD_STATE ((struct vm_uffd_state) { NULL, })
+struct vm_uffd_state {
struct userfaultfd_ctx *ctx;
};
#else /* CONFIG_USERFAULTFD */
-#define NULL_VM_UFFD_CTX ((struct vm_userfaultfd_ctx) {})
-struct vm_userfaultfd_ctx {};
+#define NULL_VM_UFFD_STATE ((struct vm_uffd_state) {})
+struct vm_uffd_state {};
#endif /* CONFIG_USERFAULTFD */
struct anon_vma_name {
@@ -1071,7 +1071,7 @@ struct vm_area_struct {
*/
struct anon_vma_name *anon_name;
#endif
- struct vm_userfaultfd_ctx vm_userfaultfd_ctx;
+ struct vm_uffd_state vm_uffd_state;
#ifdef __HAVE_PFNMAP_TRACKING
struct pfnmap_track_ctx *pfnmap_track_ctx;
#endif
diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
index d8262e3dc134..45355bdb4ec7 100644
--- a/include/linux/userfaultfd_k.h
+++ b/include/linux/userfaultfd_k.h
@@ -162,10 +162,10 @@ int move_pages_huge_pmd(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd, pm
unsigned long dst_addr, unsigned long src_addr);
/* mm helpers */
-static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
- struct vm_userfaultfd_ctx vm_ctx)
+static inline bool is_mergeable_vm_uffd_state(struct vm_area_struct *vma,
+ struct vm_uffd_state vm_ctx)
{
- return vma->vm_userfaultfd_ctx.ctx == vm_ctx.ctx;
+ return vma->vm_uffd_state.ctx == vm_ctx.ctx;
}
static inline bool userfaultfd_missing(const struct vm_area_struct *vma)
@@ -264,7 +264,7 @@ static inline bool userfaultfd_armed(struct vm_area_struct *vma)
static inline bool vma_has_uffd_without_event_remap(struct vm_area_struct *vma)
{
- struct userfaultfd_ctx *uffd_ctx = vma->vm_userfaultfd_ctx.ctx;
+ struct userfaultfd_ctx *uffd_ctx = vma->vm_uffd_state.ctx;
return uffd_ctx && (uffd_ctx->features & UFFD_FEATURE_EVENT_REMAP) == 0;
}
@@ -274,11 +274,11 @@ extern void dup_userfaultfd_complete(struct list_head *);
void dup_userfaultfd_fail(struct list_head *);
extern void mremap_userfaultfd_prep(struct vm_area_struct *,
- struct vm_userfaultfd_ctx *);
-extern void mremap_userfaultfd_complete(struct vm_userfaultfd_ctx *,
+ struct vm_uffd_state *);
+extern void mremap_userfaultfd_complete(struct vm_uffd_state *,
unsigned long from, unsigned long to,
unsigned long len);
-void mremap_userfaultfd_fail(struct vm_userfaultfd_ctx *);
+void mremap_userfaultfd_fail(struct vm_uffd_state *);
extern bool userfaultfd_remove(struct vm_area_struct *vma,
unsigned long start,
@@ -345,8 +345,8 @@ static inline long uffd_wp_range(struct vm_area_struct *vma,
return false;
}
-static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
- struct vm_userfaultfd_ctx vm_ctx)
+static inline bool is_mergeable_vm_uffd_state(struct vm_area_struct *vma,
+ struct vm_uffd_state vm_ctx)
{
return true;
}
@@ -420,18 +420,18 @@ static inline void dup_userfaultfd_fail(struct list_head *l)
}
static inline void mremap_userfaultfd_prep(struct vm_area_struct *vma,
- struct vm_userfaultfd_ctx *ctx)
+ struct vm_uffd_state *ctx)
{
}
-static inline void mremap_userfaultfd_complete(struct vm_userfaultfd_ctx *ctx,
+static inline void mremap_userfaultfd_complete(struct vm_uffd_state *ctx,
unsigned long from,
unsigned long to,
unsigned long len)
{
}
-static inline void mremap_userfaultfd_fail(struct vm_userfaultfd_ctx *ctx)
+static inline void mremap_userfaultfd_fail(struct vm_uffd_state *ctx)
{
}
diff --git a/mm/mremap.c b/mm/mremap.c
index e8df5cdb0ac9..a4a38f30b255 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -56,7 +56,7 @@ struct vma_remap_struct {
unsigned long new_addr; /* Optionally, desired new address. */
/* uffd state. */
- struct vm_userfaultfd_ctx *uf;
+ struct vm_uffd_state *uf;
struct list_head *uf_unmap_early;
struct list_head *uf_unmap;
@@ -2033,7 +2033,7 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len,
unsigned long, new_len, unsigned long, flags,
unsigned long, new_addr)
{
- struct vm_userfaultfd_ctx uf = NULL_VM_UFFD_CTX;
+ struct vm_uffd_state uf = NULL_VM_UFFD_STATE;
LIST_HEAD(uf_unmap_early);
LIST_HEAD(uf_unmap);
/*
diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index 32003aa04943..119304547230 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -99,7 +99,7 @@ bool validate_dst_vma(struct vm_area_struct *dst_vma, unsigned long dst_end)
* enforce the VM_MAYWRITE check done at uffd registration
* time.
*/
- if (!dst_vma->vm_userfaultfd_ctx.ctx)
+ if (!dst_vma->vm_uffd_state.ctx)
return false;
return true;
@@ -1812,8 +1812,8 @@ static int validate_move_areas(struct userfaultfd_ctx *ctx,
return -EINVAL;
/* Ensure dst_vma is registered in uffd we are operating on */
- if (!dst_vma->vm_userfaultfd_ctx.ctx ||
- dst_vma->vm_userfaultfd_ctx.ctx != ctx)
+ if (!dst_vma->vm_uffd_state.ctx ||
+ dst_vma->vm_uffd_state.ctx != ctx)
return -EINVAL;
/* Only allow moving across anonymous vmas */
@@ -2249,7 +2249,7 @@ static void userfaultfd_set_ctx(struct vm_area_struct *vma,
vm_flags_t vm_flags)
{
vma_start_write(vma);
- vma->vm_userfaultfd_ctx = (struct vm_userfaultfd_ctx){ctx};
+ vma->vm_uffd_state = (struct vm_uffd_state){ctx};
userfaultfd_set_vm_flags(vma,
(vma->vm_flags & ~__VM_UFFD_FLAGS) | vm_flags);
}
@@ -2296,7 +2296,7 @@ static struct vm_area_struct *userfaultfd_clear_vma(struct vma_iterator *vmi,
}
ret = vma_modify_flags_uffd(vmi, prev, vma, start, end,
- &new_vma_flags, NULL_VM_UFFD_CTX,
+ &new_vma_flags, NULL_VM_UFFD_STATE,
give_up_on_oom);
/*
@@ -2330,15 +2330,15 @@ static int userfaultfd_register_range(struct userfaultfd_ctx *ctx,
cond_resched();
VM_WARN_ON_ONCE(!vma_can_userfault(vma, vm_flags, wp_async));
- VM_WARN_ON_ONCE(vma->vm_userfaultfd_ctx.ctx &&
- vma->vm_userfaultfd_ctx.ctx != ctx);
+ VM_WARN_ON_ONCE(vma->vm_uffd_state.ctx &&
+ vma->vm_uffd_state.ctx != ctx);
VM_WARN_ON_ONCE(!vma_test(vma, VMA_MAYWRITE_BIT));
/*
* Nothing to do: this vma is already registered into this
* userfaultfd and with the right tracking mode too.
*/
- if (vma->vm_userfaultfd_ctx.ctx == ctx &&
+ if (vma->vm_uffd_state.ctx == ctx &&
vma_test_all_mask(vma, vma_flags))
goto skip;
@@ -2347,7 +2347,7 @@ static int userfaultfd_register_range(struct userfaultfd_ctx *ctx,
* switches that would drop VM_UFFD_WP or VM_UFFD_RWP, so a
* stray bit here is a bug.
*/
- VM_WARN_ON_ONCE(vma->vm_userfaultfd_ctx.ctx == ctx &&
+ VM_WARN_ON_ONCE(vma->vm_uffd_state.ctx == ctx &&
vma->vm_flags & (VM_UFFD_WP | VM_UFFD_RWP) & ~vm_flags);
if (vma->vm_start > start)
@@ -2360,7 +2360,7 @@ static int userfaultfd_register_range(struct userfaultfd_ctx *ctx,
vma = vma_modify_flags_uffd(&vmi, prev, vma, start, vma_end,
&new_vma_flags,
- (struct vm_userfaultfd_ctx){ctx},
+ (struct vm_uffd_state){ctx},
/* give_up_on_oom = */false);
if (IS_ERR(vma))
return PTR_ERR(vma);
@@ -2389,10 +2389,10 @@ static void userfaultfd_release_new(struct userfaultfd_ctx *ctx)
struct vm_area_struct *vma;
VMA_ITERATOR(vmi, mm, 0);
- /* the various vma->vm_userfaultfd_ctx still points to it */
+ /* the various vma->vm_uffd_state still points to it */
mmap_write_lock(mm);
for_each_vma(vmi, vma) {
- if (vma->vm_userfaultfd_ctx.ctx == ctx)
+ if (vma->vm_uffd_state.ctx == ctx)
userfaultfd_reset_ctx(vma);
}
mmap_write_unlock(mm);
@@ -2419,9 +2419,9 @@ static void userfaultfd_release_all(struct mm_struct *mm,
prev = NULL;
for_each_vma(vmi, vma) {
cond_resched();
- VM_WARN_ON_ONCE(!!vma->vm_userfaultfd_ctx.ctx ^
+ VM_WARN_ON_ONCE(!!vma->vm_uffd_state.ctx ^
!!(vma->vm_flags & __VM_UFFD_FLAGS));
- if (vma->vm_userfaultfd_ctx.ctx != ctx) {
+ if (vma->vm_uffd_state.ctx != ctx) {
prev = vma;
continue;
}
@@ -2512,7 +2512,7 @@ static bool userfaultfd_rwp_async_ctx(struct userfaultfd_ctx *ctx)
*/
bool userfaultfd_wp_unpopulated(struct vm_area_struct *vma)
{
- struct userfaultfd_ctx *ctx = vma->vm_userfaultfd_ctx.ctx;
+ struct userfaultfd_ctx *ctx = vma->vm_uffd_state.ctx;
if (!ctx)
return false;
@@ -2854,7 +2854,7 @@ vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason)
assert_fault_locked(vmf);
- ctx = vma->vm_userfaultfd_ctx.ctx;
+ ctx = vma->vm_uffd_state.ctx;
if (!ctx)
goto out;
@@ -3094,7 +3094,7 @@ int dup_userfaultfd(struct vm_area_struct *vma, struct list_head *fcs)
struct userfaultfd_ctx *ctx = NULL, *octx;
struct userfaultfd_fork_ctx *fctx;
- octx = vma->vm_userfaultfd_ctx.ctx;
+ octx = vma->vm_uffd_state.ctx;
if (!octx)
return 0;
@@ -3138,7 +3138,7 @@ int dup_userfaultfd(struct vm_area_struct *vma, struct list_head *fcs)
list_add_tail(&fctx->list, fcs);
}
- vma->vm_userfaultfd_ctx.ctx = ctx;
+ vma->vm_uffd_state.ctx = ctx;
return 0;
}
@@ -3195,11 +3195,11 @@ void dup_userfaultfd_fail(struct list_head *fcs)
}
void mremap_userfaultfd_prep(struct vm_area_struct *vma,
- struct vm_userfaultfd_ctx *vm_ctx)
+ struct vm_uffd_state *vm_ctx)
{
struct userfaultfd_ctx *ctx;
- ctx = vma->vm_userfaultfd_ctx.ctx;
+ ctx = vma->vm_uffd_state.ctx;
if (!ctx)
return;
@@ -3216,7 +3216,7 @@ void mremap_userfaultfd_prep(struct vm_area_struct *vma,
}
}
-void mremap_userfaultfd_complete(struct vm_userfaultfd_ctx *vm_ctx,
+void mremap_userfaultfd_complete(struct vm_uffd_state *vm_ctx,
unsigned long from, unsigned long to,
unsigned long len)
{
@@ -3236,7 +3236,7 @@ void mremap_userfaultfd_complete(struct vm_userfaultfd_ctx *vm_ctx,
userfaultfd_event_wait_completion(ctx, &ewq);
}
-void mremap_userfaultfd_fail(struct vm_userfaultfd_ctx *vm_ctx)
+void mremap_userfaultfd_fail(struct vm_uffd_state *vm_ctx)
{
struct userfaultfd_ctx *ctx = vm_ctx->ctx;
@@ -3255,7 +3255,7 @@ bool userfaultfd_remove(struct vm_area_struct *vma,
struct userfaultfd_ctx *ctx;
struct userfaultfd_wait_queue ewq;
- ctx = vma->vm_userfaultfd_ctx.ctx;
+ ctx = vma->vm_uffd_state.ctx;
if (!ctx || !(ctx->features & UFFD_FEATURE_EVENT_REMOVE))
return true;
@@ -3293,7 +3293,7 @@ int userfaultfd_unmap_prep(struct vm_area_struct *vma, unsigned long start,
unsigned long end, struct list_head *unmaps)
{
struct userfaultfd_unmap_ctx *unmap_ctx;
- struct userfaultfd_ctx *ctx = vma->vm_userfaultfd_ctx.ctx;
+ struct userfaultfd_ctx *ctx = vma->vm_uffd_state.ctx;
if (!ctx || !(ctx->features & UFFD_FEATURE_EVENT_UNMAP) ||
has_unmap_ctx(ctx, unmaps, start, end))
@@ -3813,7 +3813,7 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
do {
cond_resched();
- VM_WARN_ON_ONCE(!!cur->vm_userfaultfd_ctx.ctx ^
+ VM_WARN_ON_ONCE(!!cur->vm_uffd_state.ctx ^
!!(cur->vm_flags & __VM_UFFD_FLAGS));
/* check not compatible vmas */
@@ -3867,8 +3867,8 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
* wouldn't know which one to deliver the userfaults to.
*/
ret = -EBUSY;
- if (cur->vm_userfaultfd_ctx.ctx &&
- cur->vm_userfaultfd_ctx.ctx != ctx)
+ if (cur->vm_uffd_state.ctx &&
+ cur->vm_uffd_state.ctx != ctx)
goto out_unlock;
/*
@@ -3877,7 +3877,7 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
* subsequent mprotect() would then promote stale markers
* into the other mode. Require an unregister first.
*/
- if (cur->vm_userfaultfd_ctx.ctx == ctx &&
+ if (cur->vm_uffd_state.ctx == ctx &&
cur->vm_flags & (VM_UFFD_WP | VM_UFFD_RWP) & ~vm_flags)
goto out_unlock;
@@ -3985,15 +3985,15 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
do {
cond_resched();
- VM_WARN_ON_ONCE(!!cur->vm_userfaultfd_ctx.ctx ^
+ VM_WARN_ON_ONCE(!!cur->vm_uffd_state.ctx ^
!!(cur->vm_flags & __VM_UFFD_FLAGS));
/*
* Prevent unregistering through a different userfaultfd than
* the one used for registration.
*/
- if (cur->vm_userfaultfd_ctx.ctx &&
- cur->vm_userfaultfd_ctx.ctx != ctx)
+ if (cur->vm_uffd_state.ctx &&
+ cur->vm_uffd_state.ctx != ctx)
goto out_unlock;
/*
@@ -4020,10 +4020,10 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
cond_resched();
/* VMA not registered with userfaultfd. */
- if (!vma->vm_userfaultfd_ctx.ctx)
+ if (!vma->vm_uffd_state.ctx)
goto skip;
- VM_WARN_ON_ONCE(vma->vm_userfaultfd_ctx.ctx != ctx);
+ VM_WARN_ON_ONCE(vma->vm_uffd_state.ctx != ctx);
VM_WARN_ON_ONCE(!vma_can_userfault(vma, vma->vm_flags, wp_async));
VM_WARN_ON_ONCE(!(vma->vm_flags & VM_MAYWRITE));
@@ -4041,7 +4041,7 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
struct userfaultfd_wake_range range;
range.start = start;
range.len = vma_end - start;
- wake_userfault(vma->vm_userfaultfd_ctx.ctx, &range);
+ wake_userfault(vma->vm_uffd_state.ctx, &range);
}
vma = userfaultfd_clear_vma(&vmi, prev, vma,
@@ -4382,7 +4382,7 @@ static int userfaultfd_set_mode(struct userfaultfd_ctx *ctx,
VMA_ITERATOR(vmi, mm, 0);
for_each_vma(vmi, vma) {
- if (vma->vm_userfaultfd_ctx.ctx == ctx)
+ if (vma->vm_uffd_state.ctx == ctx)
vma_start_write(vma);
}
}
@@ -4537,12 +4537,12 @@ static inline int userfaultfd_poison(struct userfaultfd_ctx *ctx, unsigned long
bool userfaultfd_wp_async(struct vm_area_struct *vma)
{
- return userfaultfd_wp_async_ctx(vma->vm_userfaultfd_ctx.ctx);
+ return userfaultfd_wp_async_ctx(vma->vm_uffd_state.ctx);
}
bool userfaultfd_rwp_async(struct vm_area_struct *vma)
{
- return userfaultfd_rwp_async_ctx(vma->vm_userfaultfd_ctx.ctx);
+ return userfaultfd_rwp_async_ctx(vma->vm_uffd_state.ctx);
}
static inline unsigned int uffd_ctx_features(__u64 user_features)
diff --git a/mm/vma.c b/mm/vma.c
index 35e7a64855fa..f2c65d148498 100644
--- a/mm/vma.c
+++ b/mm/vma.c
@@ -118,7 +118,7 @@ static inline bool is_mergeable_vma(struct vma_merge_struct *vmg, bool merge_nex
return false;
if (vma->vm_file != vmg->file)
return false;
- if (!is_mergeable_vm_userfaultfd_ctx(vma, vmg->uffd_ctx))
+ if (!is_mergeable_vm_uffd_state(vma, vmg->uffd_ctx))
return false;
if (!anon_vma_name_eq(anon_vma_name(vma), vmg->anon_name))
return false;
@@ -1837,7 +1837,7 @@ struct vm_area_struct *vma_modify_policy(struct vma_iterator *vmi,
struct vm_area_struct *vma_modify_flags_uffd(struct vma_iterator *vmi,
struct vm_area_struct *prev, struct vm_area_struct *vma,
unsigned long start, unsigned long end,
- const vma_flags_t *vma_flags, struct vm_userfaultfd_ctx new_ctx,
+ const vma_flags_t *vma_flags, struct vm_uffd_state new_ctx,
bool give_up_on_oom)
{
VMG_VMA_STATE(vmg, vmi, prev, vma, start, end);
diff --git a/mm/vma.h b/mm/vma.h
index 024fabe63560..ab23a65750de 100644
--- a/mm/vma.h
+++ b/mm/vma.h
@@ -114,7 +114,7 @@ struct vma_merge_struct {
struct file *file;
struct anon_vma *anon_vma;
struct mempolicy *policy;
- struct vm_userfaultfd_ctx uffd_ctx;
+ struct vm_uffd_state uffd_ctx;
struct anon_vma_name *anon_name;
enum vma_merge_state state;
@@ -349,7 +349,7 @@ static inline void vma_sub_pgoff(struct vm_area_struct *vma, pgoff_t delta)
.file = vma_->vm_file, \
.anon_vma = vma_->anon_vma, \
.policy = vma_policy(vma_), \
- .uffd_ctx = vma_->vm_userfaultfd_ctx, \
+ .uffd_ctx = vma_->vm_uffd_state, \
.anon_name = anon_vma_name(vma_), \
.state = VMA_MERGE_START, \
}
@@ -519,7 +519,7 @@ __must_check struct vm_area_struct *vma_modify_policy(struct vma_iterator *vmi,
__must_check struct vm_area_struct *vma_modify_flags_uffd(struct vma_iterator *vmi,
struct vm_area_struct *prev, struct vm_area_struct *vma,
unsigned long start, unsigned long end, const vma_flags_t *vma_flags,
- struct vm_userfaultfd_ctx new_ctx, bool give_up_on_oom);
+ struct vm_uffd_state new_ctx, bool give_up_on_oom);
__must_check struct vm_area_struct *vma_merge_new_range(struct vma_merge_struct *vmg);
diff --git a/mm/vma_init.c b/mm/vma_init.c
index baa7e82f47e3..61ddb31318bb 100644
--- a/mm/vma_init.c
+++ b/mm/vma_init.c
@@ -62,8 +62,8 @@ static void vm_area_init_from(const struct vm_area_struct *src,
* dup_mmap(), but the clone will reinitialize it.
*/
data_race(memcpy(&dest->shared, &src->shared, sizeof(dest->shared)));
- memcpy(&dest->vm_userfaultfd_ctx, &src->vm_userfaultfd_ctx,
- sizeof(dest->vm_userfaultfd_ctx));
+ memcpy(&dest->vm_uffd_state, &src->vm_uffd_state,
+ sizeof(dest->vm_uffd_state));
#ifdef CONFIG_ANON_VMA_NAME
dest->anon_name = src->anon_name;
#endif
diff --git a/tools/testing/vma/include/dup.h b/tools/testing/vma/include/dup.h
index 4c58487b764e..1a01c3529d22 100644
--- a/tools/testing/vma/include/dup.h
+++ b/tools/testing/vma/include/dup.h
@@ -634,7 +634,7 @@ struct vm_area_struct {
*/
struct anon_vma_name *anon_name;
#endif
- struct vm_userfaultfd_ctx vm_userfaultfd_ctx;
+ struct vm_uffd_state vm_uffd_state;
} __randomize_layout;
struct vm_operations_struct {
diff --git a/tools/testing/vma/include/stubs.h b/tools/testing/vma/include/stubs.h
index d6136e19a8af..dcd1b1719928 100644
--- a/tools/testing/vma/include/stubs.h
+++ b/tools/testing/vma/include/stubs.h
@@ -33,7 +33,7 @@ struct unmap_desc;
#define ASSERT_EXCLUSIVE_WRITER(x)
-struct vm_userfaultfd_ctx {};
+struct vm_uffd_state {};
struct mempolicy {};
struct mmu_gather {};
struct mutex {};
@@ -350,8 +350,8 @@ static inline struct anon_vma_name *anon_vma_name(struct vm_area_struct *vma)
return NULL;
}
-static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
- struct vm_userfaultfd_ctx vm_ctx)
+static inline bool is_mergeable_vm_uffd_state(struct vm_area_struct *vma,
+ struct vm_uffd_state vm_ctx)
{
return true;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH 5/6] userfaultfd: decouple fault reason from VMA flags
2026-08-23 12:17 [PATCH 0/6] userfaultfd: decouple uffd mode from VMA flags Mike Rapoport (Microsoft)
` (3 preceding siblings ...)
2026-08-23 12:17 ` [PATCH 4/6] userfaultfd: rename vm_userfaultfd_ctx to vm_uffd_state Mike Rapoport (Microsoft)
@ 2026-08-23 12:17 ` Mike Rapoport (Microsoft)
2026-08-24 8:12 ` Muchun Song
` (2 more replies)
2026-08-23 12:17 ` [PATCH 6/6] userfaultfd: collapse VM_UFFD_{MISSING,WP,MINOR,RWP} into single VM_UFFD Mike Rapoport (Microsoft)
5 siblings, 3 replies; 32+ messages in thread
From: Mike Rapoport (Microsoft) @ 2026-08-23 12:17 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand
Cc: Baolin Wang, Barry Song, Dev Jain, Hugh Dickins, Jann Horn,
Jason Gunthorpe, John Hubbard, Jonathan Corbet, Lance Yang,
Liam R. Howlett, Lorenzo Stoakes, Masami Hiramatsu,
Mathieu Desnoyers, Mike Rapoport, Michal Hocko, Muchun Song,
Nico Pache, Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, Zi Yan, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
Introduce enum uffd_reason to define reasons for user faults rather than
overload VM_UFFD_* VMA flags for that.
Using a dedicated enum makes the code clearer and decoupling the fault
reason from VMA flags clears the way for moving the uffd mode bits out
of VMA namespace.
No functional change.
Assisted-by: copilot:claude-opus-4.6
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
---
include/linux/userfaultfd_k.h | 16 ++++++++++++++--
include/uapi/linux/userfaultfd.h | 6 +++---
mm/huge_memory.c | 6 +++---
mm/hugetlb.c | 10 +++++-----
mm/memory.c | 10 +++++-----
mm/shmem.c | 4 ++--
mm/userfaultfd.c | 30 +++++++++++++++---------------
7 files changed, 47 insertions(+), 35 deletions(-)
diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
index 45355bdb4ec7..f401623f315d 100644
--- a/include/linux/userfaultfd_k.h
+++ b/include/linux/userfaultfd_k.h
@@ -9,6 +9,18 @@
#ifndef _LINUX_USERFAULTFD_K_H
#define _LINUX_USERFAULTFD_K_H
+#include <linux/bits.h>
+
+/* Fault reason #PF handler passes to handle_userfault() */
+enum uf_reason {
+ USERFAULT_MISSING = BIT(0),
+ USERFAULT_MINOR = BIT(1),
+ USERFAULT_RWP = BIT(2),
+ USERFAULT_WP = BIT(3),
+};
+#define USERFAULT_ANY (USERFAULT_MISSING | USERFAULT_MINOR | \
+ USERFAULT_RWP | USERFAULT_WP)
+
#ifdef CONFIG_USERFAULTFD
#include <linux/userfaultfd.h> /* linux/include/uapi/linux/userfaultfd.h */
@@ -82,7 +94,7 @@ struct userfaultfd_ctx {
struct mm_struct *mm;
};
-extern vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason);
+vm_fault_t handle_userfault(struct vm_fault *vmf, enum uf_reason reason);
/* VMA userfaultfd operations */
struct vm_uffd_ops {
@@ -333,7 +345,7 @@ static inline bool pte_swp_uffd_any(pte_t pte)
/* mm helpers */
static inline vm_fault_t handle_userfault(struct vm_fault *vmf,
- unsigned long reason)
+ enum uf_reason reason)
{
return VM_FAULT_SIGBUS;
}
diff --git a/include/uapi/linux/userfaultfd.h b/include/uapi/linux/userfaultfd.h
index cea11aad6b54..ed2c42d427b9 100644
--- a/include/uapi/linux/userfaultfd.h
+++ b/include/uapi/linux/userfaultfd.h
@@ -168,9 +168,9 @@ struct uffd_msg {
/* flags for UFFD_EVENT_PAGEFAULT */
#define UFFD_PAGEFAULT_FLAG_WRITE (1<<0) /* If this was a write fault */
-#define UFFD_PAGEFAULT_FLAG_WP (1<<1) /* If reason is VM_UFFD_WP */
-#define UFFD_PAGEFAULT_FLAG_MINOR (1<<2) /* If reason is VM_UFFD_MINOR */
-#define UFFD_PAGEFAULT_FLAG_RWP (1<<3) /* If reason is VM_UFFD_RWP */
+#define UFFD_PAGEFAULT_FLAG_WP (1<<1) /* If reason is uffd-wp */
+#define UFFD_PAGEFAULT_FLAG_MINOR (1<<2) /* If reason is uffd-minor */
+#define UFFD_PAGEFAULT_FLAG_RWP (1<<3) /* If reason is uffd-rwp */
struct uffdio_api {
/* userland asks for an API number and the features to enable */
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index ced400f72d43..46d8497ce90e 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -1410,7 +1410,7 @@ static vm_fault_t __do_huge_pmd_anonymous_page(struct vm_fault *vmf)
spin_unlock(vmf->ptl);
folio_put(folio);
pte_free(vma->vm_mm, pgtable);
- ret = handle_userfault(vmf, VM_UFFD_MISSING);
+ ret = handle_userfault(vmf, USERFAULT_MISSING);
VM_BUG_ON(ret & VM_FAULT_FALLBACK);
return ret;
}
@@ -1556,7 +1556,7 @@ vm_fault_t do_huge_pmd_anonymous_page(struct vm_fault *vmf)
} else if (userfaultfd_missing(vma)) {
spin_unlock(vmf->ptl);
pte_free(vma->vm_mm, pgtable);
- ret = handle_userfault(vmf, VM_UFFD_MISSING);
+ ret = handle_userfault(vmf, USERFAULT_MISSING);
VM_BUG_ON(ret & VM_FAULT_FALLBACK);
} else {
set_huge_zero_folio(pgtable, vma->vm_mm, vma,
@@ -2252,7 +2252,7 @@ vm_fault_t do_huge_pmd_uffd_rwp(struct vm_fault *vmf)
pmd_t pmd;
if (!userfaultfd_rwp_async(vma))
- return handle_userfault(vmf, VM_UFFD_RWP);
+ return handle_userfault(vmf, USERFAULT_RWP);
vmf->ptl = pmd_lock(vma->vm_mm, vmf->pmd);
if (unlikely(!pmd_same(pmdp_get(vmf->pmd), vmf->orig_pmd))) {
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 73d65644be13..5e2ed80c1938 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -5728,7 +5728,7 @@ int hugetlb_add_to_page_cache(struct folio *folio, struct address_space *mapping
static inline vm_fault_t hugetlb_handle_userfault(struct vm_fault *vmf,
struct address_space *mapping,
- unsigned long reason)
+ enum uf_reason reason)
{
u32 hash;
@@ -5821,7 +5821,7 @@ static vm_fault_t hugetlb_no_page(struct address_space *mapping,
}
return hugetlb_handle_userfault(vmf, mapping,
- VM_UFFD_MISSING);
+ USERFAULT_MISSING);
}
if (!(vma->vm_flags & VM_MAYSHARE)) {
@@ -5897,7 +5897,7 @@ static vm_fault_t hugetlb_no_page(struct address_space *mapping,
goto out;
}
return hugetlb_handle_userfault(vmf, mapping,
- VM_UFFD_MINOR);
+ USERFAULT_MINOR);
}
}
@@ -6120,7 +6120,7 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
/* Sync: drop hugetlb locks before blocking in handle_userfault() */
if (!userfaultfd_rwp_async(vma))
- return hugetlb_handle_userfault(&vmf, mapping, VM_UFFD_RWP);
+ return hugetlb_handle_userfault(&vmf, mapping, USERFAULT_RWP);
ptl = huge_pte_lock(h, mm, vmf.pte);
pte = huge_ptep_get(mm, vmf.address, vmf.pte);
@@ -6177,7 +6177,7 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
spin_unlock(vmf.ptl);
hugetlb_vma_unlock_read(vma);
mutex_unlock(&hugetlb_fault_mutex_table[hash]);
- return handle_userfault(&vmf, VM_UFFD_WP);
+ return handle_userfault(&vmf, USERFAULT_WP);
}
vmf.orig_pte = huge_pte_clear_uffd(vmf.orig_pte);
diff --git a/mm/memory.c b/mm/memory.c
index c54943302553..1a9b41704b0c 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -4389,7 +4389,7 @@ static vm_fault_t do_wp_page(struct vm_fault *vmf)
if (userfaultfd_pte_wp(vma, ptep_get(vmf->pte))) {
if (!userfaultfd_wp_async(vma)) {
pte_unmap_unlock(vmf->pte, vmf->ptl);
- return handle_userfault(vmf, VM_UFFD_WP);
+ return handle_userfault(vmf, USERFAULT_WP);
}
/*
@@ -5463,7 +5463,7 @@ static vm_fault_t do_anonymous_page(struct vm_fault *vmf)
/* Deliver the page fault to userland, check inside PT lock */
if (userfaultfd_missing(vma)) {
pte_unmap_unlock(vmf->pte, vmf->ptl);
- return handle_userfault(vmf, VM_UFFD_MISSING);
+ return handle_userfault(vmf, USERFAULT_MISSING);
}
if (vmf_orig_pte_uffd_wp(vmf))
entry = pte_mkuffd(entry);
@@ -5514,7 +5514,7 @@ static vm_fault_t do_anonymous_page(struct vm_fault *vmf)
if (userfaultfd_missing(vma)) {
pte_unmap_unlock(vmf->pte, vmf->ptl);
folio_put(folio);
- return handle_userfault(vmf, VM_UFFD_MISSING);
+ return handle_userfault(vmf, USERFAULT_MISSING);
}
map_anon_folio_pte_pf(folio, vmf->pte, vma, addr,
vmf_orig_pte_uffd_wp(vmf));
@@ -6263,7 +6263,7 @@ static vm_fault_t do_uffd_rwp(struct vm_fault *vmf)
if (!userfaultfd_rwp_async(vmf->vma)) {
/* Sync mode: unmap PTE and deliver to userfaultfd handler */
pte_unmap(vmf->pte);
- return handle_userfault(vmf, VM_UFFD_RWP);
+ return handle_userfault(vmf, USERFAULT_RWP);
}
spin_lock(vmf->ptl);
@@ -6398,7 +6398,7 @@ static inline vm_fault_t wp_huge_pmd(struct vm_fault *vmf)
userfaultfd_huge_pmd_wp(vma, vmf->orig_pmd)) {
if (userfaultfd_wp_async(vmf->vma))
goto split;
- return handle_userfault(vmf, VM_UFFD_WP);
+ return handle_userfault(vmf, USERFAULT_WP);
}
return do_huge_pmd_wp_page(vmf);
}
diff --git a/mm/shmem.c b/mm/shmem.c
index 599665a3d6e7..2138a4e6b549 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -2453,7 +2453,7 @@ static int shmem_get_folio_gfp(struct inode *inode, pgoff_t index,
if (folio && vma && userfaultfd_minor(vma)) {
if (!xa_is_value(folio))
folio_put(folio);
- *fault_type = handle_userfault(vmf, VM_UFFD_MINOR);
+ *fault_type = handle_userfault(vmf, USERFAULT_MINOR);
return 0;
}
@@ -2502,7 +2502,7 @@ static int shmem_get_folio_gfp(struct inode *inode, pgoff_t index,
*/
if (vma && userfaultfd_missing(vma)) {
- *fault_type = handle_userfault(vmf, VM_UFFD_MISSING);
+ *fault_type = handle_userfault(vmf, USERFAULT_MISSING);
return 0;
}
diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index 119304547230..83587d34b189 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -2607,7 +2607,7 @@ static inline void msg_init(struct uffd_msg *msg)
static inline struct uffd_msg userfault_msg(unsigned long address,
unsigned long real_address,
unsigned int flags,
- unsigned long reason,
+ enum uf_reason reason,
unsigned int features)
{
struct uffd_msg msg;
@@ -2629,11 +2629,11 @@ static inline struct uffd_msg userfault_msg(unsigned long address,
*/
if (flags & FAULT_FLAG_WRITE)
msg.arg.pagefault.flags |= UFFD_PAGEFAULT_FLAG_WRITE;
- if (reason & VM_UFFD_WP)
+ if (reason & USERFAULT_WP)
msg.arg.pagefault.flags |= UFFD_PAGEFAULT_FLAG_WP;
- if (reason & VM_UFFD_RWP)
+ if (reason & USERFAULT_RWP)
msg.arg.pagefault.flags |= UFFD_PAGEFAULT_FLAG_RWP;
- if (reason & VM_UFFD_MINOR)
+ if (reason & USERFAULT_MINOR)
msg.arg.pagefault.flags |= UFFD_PAGEFAULT_FLAG_MINOR;
if (features & UFFD_FEATURE_THREAD_ID)
msg.arg.pagefault.feat.ptid = task_pid_vnr(current);
@@ -2647,7 +2647,7 @@ static inline struct uffd_msg userfault_msg(unsigned long address,
*/
static inline bool userfaultfd_huge_must_wait(struct userfaultfd_ctx *ctx,
struct vm_fault *vmf,
- unsigned long reason)
+ enum uf_reason reason)
{
struct vm_area_struct *vma = vmf->vma;
pte_t *ptep, pte;
@@ -2684,13 +2684,13 @@ static inline bool userfaultfd_huge_must_wait(struct userfaultfd_ctx *ctx,
* If VMA has UFFD WP faults enabled and WP fault, wait for userspace to
* resolve the fault.
*/
- if (!huge_pte_write(pte) && (reason & VM_UFFD_WP))
+ if (!huge_pte_write(pte) && (reason & USERFAULT_WP))
return true;
/*
* PTE is still RW-protected (protnone with uffd bit), wait for
* resolution. Plain PROT_NONE without the marker is not an RWP fault.
*/
- if (pte_protnone(pte) && huge_pte_uffd(pte) && (reason & VM_UFFD_RWP))
+ if (pte_protnone(pte) && huge_pte_uffd(pte) && (reason & USERFAULT_RWP))
return true;
return false;
@@ -2698,7 +2698,7 @@ static inline bool userfaultfd_huge_must_wait(struct userfaultfd_ctx *ctx,
#else
static inline bool userfaultfd_huge_must_wait(struct userfaultfd_ctx *ctx,
struct vm_fault *vmf,
- unsigned long reason)
+ enum uf_reason reason)
{
/* Should never get here. */
VM_WARN_ON_ONCE(1);
@@ -2715,7 +2715,7 @@ static inline bool userfaultfd_huge_must_wait(struct userfaultfd_ctx *ctx,
*/
static inline bool userfaultfd_must_wait(struct userfaultfd_ctx *ctx,
struct vm_fault *vmf,
- unsigned long reason)
+ enum uf_reason reason)
{
struct mm_struct *mm = ctx->mm;
unsigned long address = vmf->address;
@@ -2753,10 +2753,10 @@ static inline bool userfaultfd_must_wait(struct userfaultfd_ctx *ctx,
return false;
if (pmd_trans_huge(_pmd)) {
- if (!pmd_write(_pmd) && (reason & VM_UFFD_WP))
+ if (!pmd_write(_pmd) && (reason & USERFAULT_WP))
return true;
if (pmd_protnone(_pmd) && pmd_uffd(_pmd) &&
- (reason & VM_UFFD_RWP))
+ (reason & USERFAULT_RWP))
return true;
return false;
}
@@ -2793,14 +2793,14 @@ static inline bool userfaultfd_must_wait(struct userfaultfd_ctx *ctx,
* If VMA has UFFD WP faults enabled and WP fault, wait for userspace to
* resolve the fault.
*/
- if (!pte_write(ptent) && (reason & VM_UFFD_WP))
+ if (!pte_write(ptent) && (reason & USERFAULT_WP))
goto out;
/*
* PTE is still RW-protected (protnone with uffd bit), wait for
* userspace to resolve. Plain PROT_NONE without the marker is not
* an RWP fault.
*/
- if (pte_protnone(ptent) && pte_uffd(ptent) && (reason & VM_UFFD_RWP))
+ if (pte_protnone(ptent) && pte_uffd(ptent) && (reason & USERFAULT_RWP))
goto out;
ret = false;
@@ -2835,7 +2835,7 @@ static inline unsigned int userfaultfd_get_blocking_state(unsigned int flags)
* fatal_signal_pending()s, and the mmap_lock must be released before
* returning it.
*/
-vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason)
+vm_fault_t handle_userfault(struct vm_fault *vmf, enum uf_reason reason)
{
struct vm_area_struct *vma = vmf->vma;
struct mm_struct *mm = vma->vm_mm;
@@ -2861,7 +2861,7 @@ vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason)
VM_WARN_ON_ONCE(ctx->mm != mm);
/* Any unrecognized flag is a bug. */
- VM_WARN_ON_ONCE(reason & ~__VM_UFFD_FLAGS);
+ VM_WARN_ON_ONCE(reason & ~USERFAULT_ANY);
/* 0 or > 1 flags set is a bug; we expect exactly 1. */
VM_WARN_ON_ONCE(!reason || (reason & (reason - 1)));
--
2.53.0
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH 6/6] userfaultfd: collapse VM_UFFD_{MISSING,WP,MINOR,RWP} into single VM_UFFD
2026-08-23 12:17 [PATCH 0/6] userfaultfd: decouple uffd mode from VMA flags Mike Rapoport (Microsoft)
` (4 preceding siblings ...)
2026-08-23 12:17 ` [PATCH 5/6] userfaultfd: decouple fault reason from VMA flags Mike Rapoport (Microsoft)
@ 2026-08-23 12:17 ` Mike Rapoport (Microsoft)
2026-08-24 7:11 ` Lance Yang
2026-08-25 12:44 ` Lorenzo Stoakes (ARM)
5 siblings, 2 replies; 32+ messages in thread
From: Mike Rapoport (Microsoft) @ 2026-08-23 12:17 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand
Cc: Baolin Wang, Barry Song, Dev Jain, Hugh Dickins, Jann Horn,
Jason Gunthorpe, John Hubbard, Jonathan Corbet, Lance Yang,
Liam R. Howlett, Lorenzo Stoakes, Masami Hiramatsu,
Mathieu Desnoyers, Mike Rapoport, Michal Hocko, Muchun Song,
Nico Pache, Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, Zi Yan, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
Add 'mode' field to struct vm_uffd_state and define UFFD_MODE_ flags.
Use this field to differentiate VMA registration with userfaultfd
instead of relying on VM_UFFD_* flags.
A VMA registered with userfaultfd will have a single VM_UFFD flag set
and its registration mode (MISSING, MINOR, WP, RWP) is determined by
vm_uffd_state.mode.
This frees three vm_flags bits (12, 41, 43).
Update the relevant code to use UFFD_MODE_* instead of VM_UFFD_* flags.
Remove VM_UFFD_WP and VM_UFFD_RWP from VM_COPY_ON_FORK, adding an
explicit userfaultfd_protected() check in vma_needs_copy() instead.
/proc/pid/smaps representation of VmFlags is slightly changed:
- any VMA registered with UFFD shows 'uf'
- the existing userfault markers ('um', 'uw', 'ui', 'ur') are shown after
VmFlags rather than in the middle
Assisted-by: copilot:claude-opus-4.6
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
---
fs/proc/task_mmu.c | 18 +++---
include/linux/mm.h | 67 +++++-----------------
include/linux/mm_types.h | 1 +
include/linux/pgtable.h | 4 +-
include/linux/userfaultfd_k.h | 37 +++++++-----
include/trace/events/mmflags.h | 17 +-----
mm/gup.c | 5 +-
mm/hugetlb.c | 2 +-
mm/khugepaged.c | 2 +-
mm/memory.c | 6 +-
mm/mprotect.c | 2 +-
mm/shmem.c | 2 +-
mm/userfaultfd.c | 123 +++++++++++++++++++++-------------------
tools/testing/vma/include/dup.h | 18 ++----
14 files changed, 134 insertions(+), 170 deletions(-)
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 5c54aebe2118..8d344c6ee14e 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -23,6 +23,7 @@
#include <linux/minmax.h>
#include <linux/overflow.h>
#include <linux/buildid.h>
+#include <linux/userfaultfd_k.h>
#include <asm/elf.h>
#include <asm/tlb.h>
@@ -1216,8 +1217,7 @@ static void show_smap_vma_flags(struct seq_file *m, struct vm_area_struct *vma)
[ilog2(VM_HUGEPAGE)] = "hg",
[ilog2(VM_NOHUGEPAGE)] = "nh",
[ilog2(VM_MERGEABLE)] = "mg",
- [ilog2(VM_UFFD_MISSING)]= "um",
- [ilog2(VM_UFFD_WP)] = "uw",
+ [ilog2(VM_UFFD)] = "uf",
#ifdef CONFIG_ARM64_MTE
[ilog2(VM_MTE)] = "mt",
[ilog2(VM_MTE_ALLOWED)] = "",
@@ -1234,12 +1234,6 @@ static void show_smap_vma_flags(struct seq_file *m, struct vm_area_struct *vma)
[ilog2(VM_PKEY_BIT4)] = "",
#endif
#endif /* CONFIG_ARCH_HAS_PKEYS */
-#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_MINOR
- [ilog2(VM_UFFD_MINOR)] = "ui",
-#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_MINOR */
-#ifdef CONFIG_USERFAULTFD_RWP
- [ilog2(VM_UFFD_RWP)] = "ur",
-#endif
#ifdef CONFIG_ARCH_HAS_USER_SHADOW_STACK
[ilog2(VM_SHADOW_STACK)] = "ss",
#endif
@@ -1259,6 +1253,14 @@ static void show_smap_vma_flags(struct seq_file *m, struct vm_area_struct *vma)
if (vma->vm_flags & (1UL << i))
seq_printf(m, "%s ", mnemonics[i]);
}
+ if (userfaultfd_missing(vma))
+ seq_puts(m, "um ");
+ if (userfaultfd_wp(vma))
+ seq_puts(m, "uw ");
+ if (userfaultfd_minor(vma))
+ seq_puts(m, "ui ");
+ if (userfaultfd_rwp(vma))
+ seq_puts(m, "ur ");
seq_putc(m, '\n');
}
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 4daf9cd6ae8e..416de7663951 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -303,7 +303,7 @@ enum {
DECLARE_VMA_BIT(MAYSHARE, 7),
DECLARE_VMA_BIT(GROWSDOWN, 8), /* general info on the segment */
#ifdef CONFIG_MMU
- DECLARE_VMA_BIT(UFFD_MISSING, 9),/* missing pages tracking */
+ DECLARE_VMA_BIT(UFFD, 9), /* userfaultfd registered */
#else
/* nommu: R/O MAP_PRIVATE mapping that might overlay a file mapping */
DECLARE_VMA_BIT(MAYOVERLAY, 9),
@@ -311,7 +311,7 @@ enum {
/* Page-ranges managed without "struct page", just pure PFN */
DECLARE_VMA_BIT(PFNMAP, 10),
DECLARE_VMA_BIT(MAYBE_GUARD, 11),
- DECLARE_VMA_BIT(UFFD_WP, 12), /* wrprotect pages tracking */
+ /* Bit 12 is free */
DECLARE_VMA_BIT(LOCKED, 13),
DECLARE_VMA_BIT(IO, 14), /* Memory mapped I/O or similar */
DECLARE_VMA_BIT(SEQ_READ, 15), /* App will access data sequentially */
@@ -352,9 +352,8 @@ enum {
#elif defined(CONFIG_64BIT)
DECLARE_VMA_BIT(DROPPABLE, 40),
#endif
- DECLARE_VMA_BIT(UFFD_MINOR, 41),
+ /* Bits 41 and 43 are free */
DECLARE_VMA_BIT(SEALED, 42),
- DECLARE_VMA_BIT(UFFD_RWP, 43),
/* Flags that reuse flags above. */
DECLARE_VMA_BIT_ALIAS(PKEY_BIT0, HIGH_ARCH_0),
DECLARE_VMA_BIT_ALIAS(PKEY_BIT1, HIGH_ARCH_1),
@@ -408,14 +407,14 @@ enum {
#define VM_MAYSHARE INIT_VM_FLAG(MAYSHARE)
#define VM_GROWSDOWN INIT_VM_FLAG(GROWSDOWN)
#ifdef CONFIG_MMU
-#define VM_UFFD_MISSING INIT_VM_FLAG(UFFD_MISSING)
+#define VM_UFFD INIT_VM_FLAG(UFFD)
+#define VMA_UFFD mk_vma_flags(VMA_UFFD_BIT)
#else
-#define VM_UFFD_MISSING VM_NONE
+#define VM_UFFD VM_NONE
#define VM_MAYOVERLAY INIT_VM_FLAG(MAYOVERLAY)
#endif
#define VM_PFNMAP INIT_VM_FLAG(PFNMAP)
#define VM_MAYBE_GUARD INIT_VM_FLAG(MAYBE_GUARD)
-#define VM_UFFD_WP INIT_VM_FLAG(UFFD_WP)
#define VM_LOCKED INIT_VM_FLAG(LOCKED)
#define VM_IO INIT_VM_FLAG(IO)
#define VM_SEQ_READ INIT_VM_FLAG(SEQ_READ)
@@ -499,36 +498,6 @@ enum {
#define VM_MTE VM_NONE
#define VM_MTE_ALLOWED VM_NONE
#endif
-#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_MINOR
-#define VM_UFFD_MINOR INIT_VM_FLAG(UFFD_MINOR)
-#else
-#define VM_UFFD_MINOR VM_NONE
-#endif
-#ifdef CONFIG_USERFAULTFD_RWP
-#define VM_UFFD_RWP INIT_VM_FLAG(UFFD_RWP)
-#else
-#define VM_UFFD_RWP VM_NONE
-#endif
-
-/*
- * vma_flags_t masks for the userfaultfd VMA flags. The two high-bit modes are
- * gated on the same configs as their VM_* flags above -- both of which imply
- * 64BIT -- so an out-of-range bit is never fed to mk_vma_flags() on a build
- * whose bitmap cannot hold it.
- */
-#define VMA_UFFD_MISSING mk_vma_flags(VMA_UFFD_MISSING_BIT)
-#define VMA_UFFD_WP mk_vma_flags(VMA_UFFD_WP_BIT)
-#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_MINOR
-#define VMA_UFFD_MINOR mk_vma_flags(VMA_UFFD_MINOR_BIT)
-#else
-#define VMA_UFFD_MINOR EMPTY_VMA_FLAGS
-#endif
-#ifdef CONFIG_USERFAULTFD_RWP
-#define VMA_UFFD_RWP mk_vma_flags(VMA_UFFD_RWP_BIT)
-#else
-#define VMA_UFFD_RWP EMPTY_VMA_FLAGS
-#endif
-
#ifdef CONFIG_64BIT
#define VM_ALLOW_ANY_UNCACHED INIT_VM_FLAG(ALLOW_ANY_UNCACHED)
#define VM_SEALED INIT_VM_FLAG(SEALED)
@@ -668,32 +637,26 @@ enum {
* reconsistuted upon page fault, so necessitate page table copying upon fork.
*
* Note that these flags should be compared with the DESTINATION VMA not the
- * source: VM_UFFD_WP and VM_UFFD_RWP may be cleared on the destination
+ * source: uffd WP/RWP mode may be cleared on the destination
* (dup_userfaultfd() -> userfaultfd_reset_ctx() when the parent context did
* not negotiate UFFD_FEATURE_EVENT_FORK), while all other flags propagate.
*
* VM_PFNMAP / VM_MIXEDMAP - These contain kernel-mapped data which cannot be
* reasonably reconstructed on page fault.
*
- * VM_UFFD_WP - Encodes metadata about an installed uffd
- * VM_UFFD_RWP write- or read-write-protect handler, which
- * cannot be reconstructed on page fault.
- *
- * We always copy pgtables when dst_vma has the
- * uffd PTE bit in use even if it's file-backed
- * (e.g. shmem). Because when the uffd bit is
- * in use, the pgtable contains the protection
- * information, that's something we can't
- * retrieve from page cache, and skip copying
- * will lose those info.
- *
* VM_MAYBE_GUARD - Could contain page guard region markers which
* by design are a property of the page tables
* only and thus cannot be reconstructed on page
* fault.
+ *
+ * uffd WP/RWP modes - Encode metadata about an installed uffd
+ * write- or read-write-protect handler, which
+ * cannot be reconstructed on page fault.
+ * This is checked separately via
+ * userfaultfd_protected() in vma_needs_copy().
+ *
*/
-#define VM_COPY_ON_FORK (VM_PFNMAP | VM_MIXEDMAP | VM_UFFD_WP | VM_UFFD_RWP | \
- VM_MAYBE_GUARD)
+#define VM_COPY_ON_FORK (VM_PFNMAP | VM_MIXEDMAP | VM_MAYBE_GUARD)
/*
* mapping from the currently active vm_flags protection bits (the
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index d6deb655d82e..8354d1c18b29 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -723,6 +723,7 @@ struct vm_region {
#define NULL_VM_UFFD_STATE ((struct vm_uffd_state) { NULL, })
struct vm_uffd_state {
struct userfaultfd_ctx *ctx;
+ unsigned int mode;
};
#else /* CONFIG_USERFAULTFD */
#define NULL_VM_UFFD_STATE ((struct vm_uffd_state) {})
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index 8c093c119e5a..4b74c298cc14 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -2119,8 +2119,8 @@ static inline int pud_trans_unstable(pud_t *pud)
* In an accessible VMA, pte_protnone() reliably indicates a present
* PROT_NONE page protection. Today the kernel uses such PTEs for two
* purposes: NUMA hinting faults, and userfaultfd RWP tracking on
- * VM_UFFD_RWP VMAs. The two are distinguished by the uffd PTE bit and
- * the VMA flag; see include/linux/userfaultfd_k.h.
+ * uffd-RWP VMAs. The two are distinguished by the uffd PTE bit and
+ * the VMA uffd state; see include/linux/userfaultfd_k.h.
*
* So, to reliably identify PROT_NONE PTEs that require kernel handling,
* looking at the VMA accessibility (and the uffd bit on RWP VMAs) is
diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
index f401623f315d..b4261038d10a 100644
--- a/include/linux/userfaultfd_k.h
+++ b/include/linux/userfaultfd_k.h
@@ -32,12 +32,13 @@ enum uf_reason {
#include <asm-generic/pgtable_uffd.h>
#include <linux/hugetlb_inline.h>
-/* The set of all possible UFFD-related VM flags. */
-#define __VM_UFFD_FLAGS (VM_UFFD_MISSING | VM_UFFD_MINOR | \
- VM_UFFD_WP | VM_UFFD_RWP)
-
-#define __VMA_UFFD_FLAGS mk_vma_flags_from_masks(VMA_UFFD_MISSING, VMA_UFFD_WP, \
- VMA_UFFD_MINOR, VMA_UFFD_RWP)
+/* Per-VMA uffd modes */
+#define UFFD_MODE_MISSING BIT(0)
+#define UFFD_MODE_MINOR BIT(1)
+#define UFFD_MODE_RWP BIT(2)
+#define UFFD_MODE_WP BIT(3)
+#define UFFD_MODE_ALL (UFFD_MODE_MISSING | UFFD_MODE_MINOR | \
+ UFFD_MODE_RWP | UFFD_MODE_WP)
/*
* CAREFUL: Check include/uapi/asm-generic/fcntl.h when defining
@@ -99,7 +100,7 @@ vm_fault_t handle_userfault(struct vm_fault *vmf, enum uf_reason reason);
/* VMA userfaultfd operations */
struct vm_uffd_ops {
/* Checks if a VMA can support userfaultfd */
- bool (*can_userfault)(struct vm_area_struct *vma, vm_flags_t vm_flags);
+ bool (*can_userfault)(struct vm_area_struct *vma, unsigned int mode);
/*
* Called to resolve UFFDIO_CONTINUE request.
* Should return the folio found at pgoff in the VMA's pagecache if it
@@ -174,25 +175,34 @@ int move_pages_huge_pmd(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd, pm
unsigned long dst_addr, unsigned long src_addr);
/* mm helpers */
+static inline unsigned int uffd_mode(const struct vm_area_struct *vma)
+{
+ return vma->vm_uffd_state.mode;
+}
+
static inline bool is_mergeable_vm_uffd_state(struct vm_area_struct *vma,
struct vm_uffd_state vm_ctx)
{
- return vma->vm_uffd_state.ctx == vm_ctx.ctx;
+ return vma->vm_uffd_state.ctx == vm_ctx.ctx &&
+ uffd_mode(vma) == vm_ctx.mode;
}
static inline bool userfaultfd_missing(const struct vm_area_struct *vma)
{
- return vma_test_any_mask(vma, VMA_UFFD_MISSING);
+ return vma_test(vma, VMA_UFFD_BIT) &&
+ (uffd_mode(vma) & UFFD_MODE_MISSING);
}
static inline bool userfaultfd_wp(const struct vm_area_struct *vma)
{
- return vma_test_any_mask(vma, VMA_UFFD_WP);
+ return vma_test(vma, VMA_UFFD_BIT) &&
+ (uffd_mode(vma) & UFFD_MODE_WP);
}
static inline bool userfaultfd_minor(const struct vm_area_struct *vma)
{
- return vma_test_any_mask(vma, VMA_UFFD_MINOR);
+ return vma_test(vma, VMA_UFFD_BIT) &&
+ (uffd_mode(vma) & UFFD_MODE_MINOR);
}
static inline bool userfaultfd_rwp(const struct vm_area_struct *vma)
@@ -203,7 +213,8 @@ static inline bool userfaultfd_rwp(const struct vm_area_struct *vma)
*/
if (!IS_ENABLED(CONFIG_ARCH_HAS_PTE_PROTNONE))
return false;
- return vma_test_single_mask(vma, VMA_UFFD_RWP);
+ return vma_test(vma, VMA_UFFD_BIT) &&
+ (uffd_mode(vma) & UFFD_MODE_RWP);
}
static inline bool userfaultfd_protected(const struct vm_area_struct *vma)
@@ -271,7 +282,7 @@ static inline bool userfaultfd_huge_pmd_rwp(struct vm_area_struct *vma,
static inline bool userfaultfd_armed(struct vm_area_struct *vma)
{
- return vma_test_any_mask(vma, __VMA_UFFD_FLAGS);
+ return vma_test(vma, VMA_UFFD_BIT);
}
static inline bool vma_has_uffd_without_event_remap(struct vm_area_struct *vma)
diff --git a/include/trace/events/mmflags.h b/include/trace/events/mmflags.h
index 935893e5ea53..aacdd90e0a64 100644
--- a/include/trace/events/mmflags.h
+++ b/include/trace/events/mmflags.h
@@ -180,18 +180,6 @@ IF_HAVE_PG_ARCH_3(arch_3)
#define IF_HAVE_VM_SOFTDIRTY(flag,name)
#endif
-#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_MINOR
-# define IF_HAVE_UFFD_MINOR(flag, name) {flag, name},
-#else
-# define IF_HAVE_UFFD_MINOR(flag, name)
-#endif
-
-#ifdef CONFIG_USERFAULTFD_RWP
-# define IF_HAVE_UFFD_RWP(flag, name) {flag, name},
-#else
-# define IF_HAVE_UFFD_RWP(flag, name)
-#endif
-
#if defined(CONFIG_64BIT) || defined(CONFIG_PPC32)
# define IF_HAVE_VM_DROPPABLE(flag, name) {flag, name},
#else
@@ -208,12 +196,9 @@ IF_HAVE_PG_ARCH_3(arch_3)
{VM_MAYEXEC, "mayexec" }, \
{VM_MAYSHARE, "mayshare" }, \
{VM_GROWSDOWN, "growsdown" }, \
- {VM_UFFD_MISSING, "uffd_missing" }, \
-IF_HAVE_UFFD_MINOR(VM_UFFD_MINOR, "uffd_minor" ) \
+ {VM_UFFD, "uffd" }, \
{VM_PFNMAP, "pfnmap" }, \
{VM_MAYBE_GUARD, "maybe_guard" }, \
- {VM_UFFD_WP, "uffd_wp" }, \
-IF_HAVE_UFFD_RWP(VM_UFFD_RWP, "uffd_rwp" ) \
{VM_LOCKED, "locked" }, \
{VM_IO, "io" }, \
{VM_SEQ_READ, "seqread" }, \
diff --git a/mm/gup.c b/mm/gup.c
index 500e2aa99e48..9243c41a0c0e 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -12,6 +12,7 @@
#include <linux/swap.h>
#include <linux/swapops.h>
#include <linux/secretmem.h>
+#include <linux/userfaultfd_k.h>
#include <linux/sched/signal.h>
#include <linux/rwsem.h>
@@ -641,7 +642,7 @@ static inline bool gup_can_follow_protnone(const struct vm_area_struct *vma,
unsigned int flags)
{
/*
- * VM_UFFD_RWP uses protnone as an access-tracking marker, not for
+ * uffd-RWP uses protnone as an access-tracking marker, not for
* NUMA hinting. GUP must always take a fault so the access is
* delivered to userfaultfd, regardless of FOLL_HONOR_NUMA_FAULT.
*
@@ -651,7 +652,7 @@ static inline bool gup_can_follow_protnone(const struct vm_area_struct *vma,
* no progress on protnone in an inaccessible VMA, and the access is
* denied regardless of RWP anyway.
*/
- if (vma_test_single_mask(vma, VMA_UFFD_RWP) && vma_is_accessible(vma))
+ if (userfaultfd_rwp(vma) && vma_is_accessible(vma))
return false;
/*
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 5e2ed80c1938..a15c443474d5 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -4808,7 +4808,7 @@ static vm_fault_t hugetlb_vm_op_fault(struct vm_fault *vmf)
#ifdef CONFIG_USERFAULTFD
static bool hugetlb_can_userfault(struct vm_area_struct *vma,
- vm_flags_t vm_flags)
+ unsigned int mode)
{
return true;
}
diff --git a/mm/khugepaged.c b/mm/khugepaged.c
index 79effd3f3da4..7f590a1d3ca3 100644
--- a/mm/khugepaged.c
+++ b/mm/khugepaged.c
@@ -2112,7 +2112,7 @@ static bool file_backed_vma_is_retractable(struct vm_area_struct *vma)
/*
* When a vma is registered with uffd-wp or RWP, we cannot recycle
* the page table because there may be pte markers installed.
- * VM_UFFD_RWP ranges similarly rely on per-PTE uffd state
+ * uffd-RWP ranges similarly rely on per-PTE uffd state
* and cannot be recycled to a shared PMD. Other vmas can still
* have the same file mapped hugely, but skip this one: it will
* always be mapped in small page size for these registrations.
diff --git a/mm/memory.c b/mm/memory.c
index 1a9b41704b0c..c12ec979199c 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1565,10 +1565,12 @@ vma_needs_copy(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma)
{
/*
* We check against dst_vma as while sane VMA flags will have been
- * copied, VM_UFFD_WP may be set only on dst_vma.
+ * copied, userfaultfd WP/RWP mode may be set only on dst_vma.
*/
if (dst_vma->vm_flags & VM_COPY_ON_FORK)
return true;
+ if (userfaultfd_protected(dst_vma))
+ return true;
/*
* The presence of an anon_vma indicates an anonymous VMA has page
* tables which naturally cannot be reconstituted on page fault.
@@ -6563,7 +6565,7 @@ static vm_fault_t handle_pte_fault(struct vm_fault *vmf)
if (pte_protnone(vmf->orig_pte) && vma_is_accessible(vmf->vma)) {
/*
* RWP-protected PTEs are protnone plus the uffd bit. On a
- * VM_UFFD_RWP VMA, a protnone PTE without the uffd bit is
+ * uffd-RWP VMA, a protnone PTE without the uffd bit is
* NUMA hinting and must still fall through to do_numa_page().
*/
if (userfaultfd_pte_rwp(vmf->vma, vmf->orig_pte))
diff --git a/mm/mprotect.c b/mm/mprotect.c
index 2888ee638d87..b98d4372677b 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -297,7 +297,7 @@ static __always_inline void change_present_ptes(struct mmu_gather *tlb,
ptent = pte_clear_uffd(ptent);
/*
- * The uffd bit on a VM_UFFD_RWP VMA carries PROT_NONE
+ * The uffd bit on a uffd-RWP VMA carries PROT_NONE
* semantics. If mprotect() or NUMA hinting changed the
* base protection, restore PAGE_NONE so the PTE still
* traps on any access. pte_modify() preserves
diff --git a/mm/shmem.c b/mm/shmem.c
index 2138a4e6b549..c8db9f93dde1 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -3220,7 +3220,7 @@ static struct folio *shmem_get_folio_noalloc(struct inode *inode, pgoff_t pgoff)
return folio;
}
-static bool shmem_can_userfault(struct vm_area_struct *vma, vm_flags_t vm_flags)
+static bool shmem_can_userfault(struct vm_area_struct *vma, unsigned int mode)
{
return true;
}
diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index 83587d34b189..193f6e65d875 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -50,10 +50,10 @@ struct mfill_state {
pmd_t *pmd;
};
-static bool anon_can_userfault(struct vm_area_struct *vma, vm_flags_t vm_flags)
+static bool anon_can_userfault(struct vm_area_struct *vma, unsigned int mode)
{
/* anonymous memory does not support MINOR mode */
- if (vm_flags & VM_UFFD_MINOR)
+ if (mode & UFFD_MODE_MINOR)
return false;
return true;
}
@@ -462,7 +462,7 @@ static int mfill_copy_folio_locked(struct folio *folio, unsigned long src_addr)
}
#define MFILL_RETRY_STATE_VMA_FLAGS \
- append_vma_flags(__VMA_UFFD_FLAGS, VMA_SHARED_BIT)
+ append_vma_flags(VMA_UFFD, VMA_SHARED_BIT)
/*
* VMA state saved before dropping the locks in mfill_copy_folio_retry().
@@ -2194,7 +2194,7 @@ static ssize_t move_pages(struct userfaultfd_ctx *ctx, unsigned long dst_start,
return moved ? moved : err;
}
-static bool vma_can_userfault(struct vm_area_struct *vma, vm_flags_t vm_flags,
+static bool vma_can_userfault(struct vm_area_struct *vma, unsigned int mode,
bool wp_async)
{
const struct vm_uffd_ops *ops = vma_uffd_ops(vma);
@@ -2205,13 +2205,11 @@ static bool vma_can_userfault(struct vm_area_struct *vma, vm_flags_t vm_flags,
if (!is_vm_hugetlb_page(vma) && (vma->vm_flags & VM_SPECIAL))
return false;
- vm_flags &= __VM_UFFD_FLAGS;
-
/*
* If WP is the only mode enabled and context is wp async, allow any
* memory type.
*/
- if (wp_async && (vm_flags == VM_UFFD_WP))
+ if (wp_async && (mode == UFFD_MODE_WP))
return true;
/* For any other mode reject VMAs that don't implement vm_uffd_ops */
@@ -2222,19 +2220,31 @@ static bool vma_can_userfault(struct vm_area_struct *vma, vm_flags_t vm_flags,
* If user requested uffd-wp but not enabled pte markers for
* uffd-wp, then only anonymous memory is supported
*/
- if (!uffd_supports_wp_marker() && (vm_flags & VM_UFFD_WP) &&
+ if (!uffd_supports_wp_marker() && (mode & UFFD_MODE_WP) &&
!vma_is_anonymous(vma))
return false;
- return ops->can_userfault(vma, vm_flags);
+ return ops->can_userfault(vma, mode);
}
-static void userfaultfd_set_vm_flags(struct vm_area_struct *vma,
- vm_flags_t vm_flags)
+static void userfaultfd_set_ctx(struct vm_area_struct *vma,
+ struct userfaultfd_ctx *ctx,
+ unsigned int mode)
{
- const bool uffd_wp_changed = (vma->vm_flags ^ vm_flags) & VM_UFFD_WP;
+ const bool uffd_wp_changed = (uffd_mode(vma) ^ mode) & UFFD_MODE_WP;
+
+ vma_start_write(vma);
+
+ vma->vm_uffd_state = (struct vm_uffd_state){
+ .ctx = ctx,
+ .mode = mode,
+ };
+
+ if (mode)
+ vma_set_flags(vma, VMA_UFFD_BIT);
+ else
+ vma_clear_flags(vma, VMA_UFFD_BIT);
- vm_flags_reset(vma, vm_flags);
/*
* For shared mappings, we want to enable writenotify while
* userfaultfd-wp is enabled (see vma_wants_writenotify()). We'll simply
@@ -2244,16 +2254,6 @@ static void userfaultfd_set_vm_flags(struct vm_area_struct *vma,
vma_set_page_prot(vma);
}
-static void userfaultfd_set_ctx(struct vm_area_struct *vma,
- struct userfaultfd_ctx *ctx,
- vm_flags_t vm_flags)
-{
- vma_start_write(vma);
- vma->vm_uffd_state = (struct vm_uffd_state){ctx};
- userfaultfd_set_vm_flags(vma,
- (vma->vm_flags & ~__VM_UFFD_FLAGS) | vm_flags);
-}
-
static void userfaultfd_reset_ctx(struct vm_area_struct *vma)
{
userfaultfd_set_ctx(vma, NULL, 0);
@@ -2269,7 +2269,7 @@ static struct vm_area_struct *userfaultfd_clear_vma(struct vma_iterator *vmi,
bool give_up_on_oom = false;
vma_flags_t new_vma_flags = vma->flags;
- vma_flags_clear_mask(&new_vma_flags, __VMA_UFFD_FLAGS);
+ vma_flags_clear_mask(&new_vma_flags, VMA_UFFD);
/*
* If we are modifying only and not splitting, just give up on the merge
@@ -2313,11 +2313,10 @@ static struct vm_area_struct *userfaultfd_clear_vma(struct vma_iterator *vmi,
/* Assumes mmap write lock taken, and mm_struct pinned. */
static int userfaultfd_register_range(struct userfaultfd_ctx *ctx,
struct vm_area_struct *vma,
- vm_flags_t vm_flags,
+ unsigned int mode,
unsigned long start, unsigned long end,
bool wp_async)
{
- vma_flags_t vma_flags = legacy_to_vma_flags(vm_flags);
VMA_ITERATOR(vmi, ctx->mm, start);
struct vm_area_struct *prev = vma_prev(&vmi);
unsigned long vma_end;
@@ -2329,7 +2328,7 @@ static int userfaultfd_register_range(struct userfaultfd_ctx *ctx,
for_each_vma_range(vmi, vma, end) {
cond_resched();
- VM_WARN_ON_ONCE(!vma_can_userfault(vma, vm_flags, wp_async));
+ VM_WARN_ON_ONCE(!vma_can_userfault(vma, mode, wp_async));
VM_WARN_ON_ONCE(vma->vm_uffd_state.ctx &&
vma->vm_uffd_state.ctx != ctx);
VM_WARN_ON_ONCE(!vma_test(vma, VMA_MAYWRITE_BIT));
@@ -2339,28 +2338,31 @@ static int userfaultfd_register_range(struct userfaultfd_ctx *ctx,
* userfaultfd and with the right tracking mode too.
*/
if (vma->vm_uffd_state.ctx == ctx &&
- vma_test_all_mask(vma, vma_flags))
+ (uffd_mode(vma) & mode) == mode)
goto skip;
/*
* Pre-scan in userfaultfd_register() already rejected mode
- * switches that would drop VM_UFFD_WP or VM_UFFD_RWP, so a
- * stray bit here is a bug.
+ * switches that would drop WP or RWP, so a stray bit here
+ * is a bug.
*/
VM_WARN_ON_ONCE(vma->vm_uffd_state.ctx == ctx &&
- vma->vm_flags & (VM_UFFD_WP | VM_UFFD_RWP) & ~vm_flags);
+ uffd_mode(vma) &
+ (UFFD_MODE_WP | UFFD_MODE_RWP) & ~mode);
if (vma->vm_start > start)
start = vma->vm_start;
vma_end = min(end, vma->vm_end);
new_vma_flags = vma->flags;
- vma_flags_clear_mask(&new_vma_flags, __VMA_UFFD_FLAGS);
- vma_flags_set_mask(&new_vma_flags, vma_flags);
+ vma_flags_set_mask(&new_vma_flags, VMA_UFFD);
vma = vma_modify_flags_uffd(&vmi, prev, vma, start, vma_end,
&new_vma_flags,
- (struct vm_uffd_state){ctx},
+ (struct vm_uffd_state){
+ .ctx = ctx,
+ .mode = mode,
+ },
/* give_up_on_oom = */false);
if (IS_ERR(vma))
return PTR_ERR(vma);
@@ -2370,7 +2372,7 @@ static int userfaultfd_register_range(struct userfaultfd_ctx *ctx,
* the next vma was merged into the current one and
* the current one has not been updated yet.
*/
- userfaultfd_set_ctx(vma, ctx, vm_flags);
+ userfaultfd_set_ctx(vma, ctx, mode);
if (is_vm_hugetlb_page(vma) && uffd_disable_huge_pmd_share(vma))
hugetlb_unshare_all_pmds(vma);
@@ -2420,7 +2422,7 @@ static void userfaultfd_release_all(struct mm_struct *mm,
for_each_vma(vmi, vma) {
cond_resched();
VM_WARN_ON_ONCE(!!vma->vm_uffd_state.ctx ^
- !!(vma->vm_flags & __VM_UFFD_FLAGS));
+ vma_test(vma, VMA_UFFD_BIT));
if (vma->vm_uffd_state.ctx != ctx) {
prev = vma;
continue;
@@ -2876,9 +2878,9 @@ vm_fault_t handle_userfault(struct vm_fault *vmf, enum uf_reason reason)
* NOTE: it should become possible to return VM_FAULT_RETRY
* even if FAULT_FLAG_TRIED is set without leading to gup()
* -EBUSY failures, if the userfaultfd is to be extended for
- * VM_UFFD_WP tracking and we intend to arm the userfault
+ * WP tracking and we intend to arm the userfault
* without first stopping userland access to the memory. For
- * VM_UFFD_MISSING userfaults this is enough for now.
+ * MISSING userfaults this is enough for now.
*/
if (unlikely(!(vmf->flags & FAULT_FLAG_ALLOW_RETRY))) {
/*
@@ -3723,7 +3725,7 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
int ret;
struct uffdio_register uffdio_register;
struct uffdio_register __user *user_uffdio_register;
- vm_flags_t vm_flags;
+ unsigned int mode;
bool found;
bool basic_ioctls;
unsigned long start, end;
@@ -3742,21 +3744,22 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
goto out;
if (uffdio_register.mode & ~UFFD_API_REGISTER_MODES)
goto out;
- vm_flags = 0;
+ mode = 0;
if (uffdio_register.mode & UFFDIO_REGISTER_MODE_MISSING)
- vm_flags |= VM_UFFD_MISSING;
+ mode |= UFFD_MODE_MISSING;
if (uffdio_register.mode & UFFDIO_REGISTER_MODE_WP) {
if (!pgtable_supports_uffd())
goto out;
- vm_flags |= VM_UFFD_WP;
+ mode |= UFFD_MODE_WP;
}
if (uffdio_register.mode & UFFDIO_REGISTER_MODE_RWP) {
- if (!pgtable_supports_uffd() || VM_UFFD_RWP == VM_NONE)
+ if (!pgtable_supports_uffd() ||
+ !IS_ENABLED(CONFIG_USERFAULTFD_RWP))
goto out;
if (!(userfaultfd_features(ctx) & UFFD_FEATURE_RWP))
goto out;
- vm_flags |= VM_UFFD_RWP;
+ mode |= UFFD_MODE_RWP;
}
/*
@@ -3764,14 +3767,14 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
* cannot coexist in the same VMA — the bit would carry ambiguous
* semantics. Reject the combination up front.
*/
- if ((vm_flags & VM_UFFD_WP) && (vm_flags & VM_UFFD_RWP))
+ if ((mode & UFFD_MODE_WP) && (mode & UFFD_MODE_RWP))
goto out;
if (uffdio_register.mode & UFFDIO_REGISTER_MODE_MINOR) {
#ifndef CONFIG_HAVE_ARCH_USERFAULTFD_MINOR
goto out;
#endif
- vm_flags |= VM_UFFD_MINOR;
+ mode |= UFFD_MODE_MINOR;
}
ret = validate_range(mm, uffdio_register.range.start,
@@ -3814,11 +3817,11 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
cond_resched();
VM_WARN_ON_ONCE(!!cur->vm_uffd_state.ctx ^
- !!(cur->vm_flags & __VM_UFFD_FLAGS));
+ vma_test(cur, VMA_UFFD_BIT));
/* check not compatible vmas */
ret = -EINVAL;
- if (!vma_can_userfault(cur, vm_flags, wp_async))
+ if (!vma_can_userfault(cur, mode, wp_async))
goto out_unlock;
/*
@@ -3829,7 +3832,7 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
* mprotect() must still be unregisterable, so this is not
* part of vma_can_userfault().
*/
- if ((vm_flags & VM_UFFD_RWP) && !vma_is_accessible(cur))
+ if ((mode & UFFD_MODE_RWP) && !vma_is_accessible(cur))
goto out_unlock;
/*
@@ -3857,7 +3860,8 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
if (end & (vma_hpagesize - 1))
goto out_unlock;
}
- if ((vm_flags & VM_UFFD_WP) && !(cur->vm_flags & VM_MAYWRITE))
+ if ((mode & UFFD_MODE_WP) &&
+ !vma_test(cur, VMA_MAYWRITE_BIT))
goto out_unlock;
/*
@@ -3872,13 +3876,13 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
goto out_unlock;
/*
- * Mode switches that drop VM_UFFD_WP or VM_UFFD_RWP would
- * leave PTE markers without the flag that describes them;
+ * Mode switches that drop WP or RWP would leave PTE markers
+ * without the mode that describes them;
* subsequent mprotect() would then promote stale markers
* into the other mode. Require an unregister first.
*/
if (cur->vm_uffd_state.ctx == ctx &&
- cur->vm_flags & (VM_UFFD_WP | VM_UFFD_RWP) & ~vm_flags)
+ uffd_mode(cur) & (UFFD_MODE_WP | UFFD_MODE_RWP) & ~mode)
goto out_unlock;
/*
@@ -3891,7 +3895,7 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
} for_each_vma_range(vmi, cur, end);
VM_WARN_ON_ONCE(!found);
- ret = userfaultfd_register_range(ctx, vma, vm_flags, start, end,
+ ret = userfaultfd_register_range(ctx, vma, mode, start, end,
wp_async);
out_unlock:
@@ -3986,7 +3990,7 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
cond_resched();
VM_WARN_ON_ONCE(!!cur->vm_uffd_state.ctx ^
- !!(cur->vm_flags & __VM_UFFD_FLAGS));
+ vma_test(cur, VMA_UFFD_BIT));
/*
* Prevent unregistering through a different userfaultfd than
@@ -4003,7 +4007,7 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
* provides for more strict behavior to notice
* unregistration errors.
*/
- if (!vma_can_userfault(cur, cur->vm_flags, wp_async))
+ if (!vma_can_userfault(cur, uffd_mode(cur), wp_async))
goto out_unlock;
found = true;
@@ -4024,7 +4028,8 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
goto skip;
VM_WARN_ON_ONCE(vma->vm_uffd_state.ctx != ctx);
- VM_WARN_ON_ONCE(!vma_can_userfault(vma, vma->vm_flags, wp_async));
+ VM_WARN_ON_ONCE(!vma_can_userfault(vma, uffd_mode(vma),
+ wp_async));
VM_WARN_ON_ONCE(!(vma->vm_flags & VM_MAYWRITE));
if (vma->vm_start > start)
@@ -4329,12 +4334,12 @@ static __u64 uffd_api_available_features(void)
UFFD_FEATURE_WP_ASYNC);
/*
* RWP needs both PROT_NONE support and the uffd PTE bit. The
- * VM_UFFD_RWP check covers compile-time unavailability; the
+ * IS_ENABLED check covers compile-time unavailability; the
* pgtable_supports_uffd() check covers runtime (e.g. riscv
* without the SVRSW60T59B extension) where the PTE bit is declared
* but not actually usable.
*/
- if (VM_UFFD_RWP == VM_NONE || !pgtable_supports_uffd())
+ if (!IS_ENABLED(CONFIG_USERFAULTFD_RWP) || !pgtable_supports_uffd())
f &= ~(UFFD_FEATURE_RWP | UFFD_FEATURE_RWP_ASYNC);
return f;
}
diff --git a/tools/testing/vma/include/dup.h b/tools/testing/vma/include/dup.h
index 1a01c3529d22..05a39c14eab2 100644
--- a/tools/testing/vma/include/dup.h
+++ b/tools/testing/vma/include/dup.h
@@ -109,7 +109,7 @@ enum {
DECLARE_VMA_BIT(MAYSHARE, 7),
DECLARE_VMA_BIT(GROWSDOWN, 8), /* general info on the segment */
#ifdef CONFIG_MMU
- DECLARE_VMA_BIT(UFFD_MISSING, 9),/* missing pages tracking */
+ DECLARE_VMA_BIT(UFFD, 9), /* userfaultfd registered */
#else
/* nommu: R/O MAP_PRIVATE mapping that might overlay a file mapping */
DECLARE_VMA_BIT(MAYOVERLAY, 9),
@@ -117,7 +117,7 @@ enum {
/* Page-ranges managed without "struct page", just pure PFN */
DECLARE_VMA_BIT(PFNMAP, 10),
DECLARE_VMA_BIT(MAYBE_GUARD, 11),
- DECLARE_VMA_BIT(UFFD_WP, 12), /* wrprotect pages tracking */
+ /* Bit 12 is free */
DECLARE_VMA_BIT(LOCKED, 13),
DECLARE_VMA_BIT(IO, 14), /* Memory mapped I/O or similar */
DECLARE_VMA_BIT(SEQ_READ, 15), /* App will access data sequentially */
@@ -158,7 +158,7 @@ enum {
#else
DECLARE_VMA_BIT(DROPPABLE, 40),
#endif
- DECLARE_VMA_BIT(UFFD_MINOR, 41),
+ /* Bit 41 is free */
DECLARE_VMA_BIT(SEALED, 42),
/* Flags that reuse flags above. */
DECLARE_VMA_BIT_ALIAS(PKEY_BIT0, HIGH_ARCH_0),
@@ -211,14 +211,13 @@ enum {
#define VM_MAYSHARE INIT_VM_FLAG(MAYSHARE)
#define VM_GROWSDOWN INIT_VM_FLAG(GROWSDOWN)
#ifdef CONFIG_MMU
-#define VM_UFFD_MISSING INIT_VM_FLAG(UFFD_MISSING)
+#define VM_UFFD INIT_VM_FLAG(UFFD)
#else
-#define VM_UFFD_MISSING VM_NONE
+#define VM_UFFD VM_NONE
#define VM_MAYOVERLAY INIT_VM_FLAG(MAYOVERLAY)
#endif
#define VM_PFNMAP INIT_VM_FLAG(PFNMAP)
#define VM_MAYBE_GUARD INIT_VM_FLAG(MAYBE_GUARD)
-#define VM_UFFD_WP INIT_VM_FLAG(UFFD_WP)
#define VM_LOCKED INIT_VM_FLAG(LOCKED)
#define VM_IO INIT_VM_FLAG(IO)
#define VM_SEQ_READ INIT_VM_FLAG(SEQ_READ)
@@ -297,11 +296,6 @@ enum {
#define VM_MTE VM_NONE
#define VM_MTE_ALLOWED VM_NONE
#endif
-#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_MINOR
-#define VM_UFFD_MINOR INIT_VM_FLAG(UFFD_MINOR)
-#else
-#define VM_UFFD_MINOR VM_NONE
-#endif
#ifdef CONFIG_64BIT
#define VM_ALLOW_ANY_UNCACHED INIT_VM_FLAG(ALLOW_ANY_UNCACHED)
#define VM_SEALED INIT_VM_FLAG(SEALED)
@@ -387,7 +381,7 @@ enum {
#define VMA_IGNORE_MERGE_FLAGS VMA_STICKY_FLAGS
-#define VM_COPY_ON_FORK (VM_PFNMAP | VM_MIXEDMAP | VM_UFFD_WP | VM_MAYBE_GUARD)
+#define VM_COPY_ON_FORK (VM_PFNMAP | VM_MIXEDMAP | VM_MAYBE_GUARD)
#define pgprot_val(x) ((x).pgprot)
#define __pgprot(x) ((pgprot_t) { (x) } )
--
2.53.0
^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: [PATCH 2/6] userfaultfd: constify VMA parameter of userfaultfd_*() helpers
2026-08-23 12:17 ` [PATCH 2/6] userfaultfd: constify VMA parameter of userfaultfd_*() helpers Mike Rapoport (Microsoft)
@ 2026-08-23 21:03 ` Barry Song
2026-08-24 15:03 ` Lorenzo Stoakes (ARM)
2026-08-25 2:03 ` Zi Yan
2 siblings, 0 replies; 32+ messages in thread
From: Barry Song @ 2026-08-23 21:03 UTC (permalink / raw)
To: Mike Rapoport (Microsoft)
Cc: Andrew Morton, David Hildenbrand, Baolin Wang, Dev Jain,
Hugh Dickins, Jann Horn, Jason Gunthorpe, John Hubbard,
Jonathan Corbet, Lance Yang, Liam R. Howlett, Lorenzo Stoakes,
Masami Hiramatsu, Mathieu Desnoyers, Michal Hocko, Muchun Song,
Nico Pache, Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, Zi Yan, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
On Sun, Aug 23, 2026 at 8:18 PM Mike Rapoport (Microsoft)
<rppt@kernel.org> wrote:
>
> userfaultfd_{missing,wp,minor,rwp}() and userfaultfd_protected() only
> read the VMA.
>
> Make their vma parameter const.
>
> No functional change.
>
> Assisted-by: copilot:claude-opus-5
> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> ---
LGTM, thanks!
Reviewed-by: Barry Song <baohua@kernel.org>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 1/6] mm/gup: move gup_can_follow_protnone() to gup.c
2026-08-23 12:17 ` [PATCH 1/6] mm/gup: move gup_can_follow_protnone() to gup.c Mike Rapoport (Microsoft)
@ 2026-08-23 21:03 ` Barry Song
2026-08-24 14:42 ` David Hildenbrand (Arm)
` (2 subsequent siblings)
3 siblings, 0 replies; 32+ messages in thread
From: Barry Song @ 2026-08-23 21:03 UTC (permalink / raw)
To: Mike Rapoport (Microsoft)
Cc: Andrew Morton, David Hildenbrand, Baolin Wang, Dev Jain,
Hugh Dickins, Jann Horn, Jason Gunthorpe, John Hubbard,
Jonathan Corbet, Lance Yang, Liam R. Howlett, Lorenzo Stoakes,
Masami Hiramatsu, Mathieu Desnoyers, Michal Hocko, Muchun Song,
Nico Pache, Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, Zi Yan, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
On Sun, Aug 23, 2026 at 8:17 PM Mike Rapoport (Microsoft)
<rppt@kernel.org> wrote:
>
> gup_can_follow_protnone() is defined in include/linux/mm.h but only used
> by mm/gup.c.
>
> First, there is no reason to have it in already gigantic header.
>
> Next, the upcoming refactoring of userfaultfd flags will make
> gup_can_follow_protnone() depend on userfaultfd_k.h which would cause a
> cyclic header dependency.
>
> Move gup_can_follow_protnone() to mm/gup.c.
>
> No functional change.
>
> Assisted-by: copilot:claude-opus-5
> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> ---
LGTM, thanks!
Reviewed-by: Barry Song <baohua@kernel.org>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 3/6] userfaultfd: use userfaultfd_*() helpers instead of open coded flag tests
2026-08-23 12:17 ` [PATCH 3/6] userfaultfd: use userfaultfd_*() helpers instead of open coded flag tests Mike Rapoport (Microsoft)
@ 2026-08-23 21:14 ` Barry Song
2026-08-24 15:10 ` Lorenzo Stoakes (ARM)
1 sibling, 0 replies; 32+ messages in thread
From: Barry Song @ 2026-08-23 21:14 UTC (permalink / raw)
To: Mike Rapoport (Microsoft)
Cc: Andrew Morton, David Hildenbrand, Baolin Wang, Dev Jain,
Hugh Dickins, Jann Horn, Jason Gunthorpe, John Hubbard,
Jonathan Corbet, Lance Yang, Liam R. Howlett, Lorenzo Stoakes,
Masami Hiramatsu, Mathieu Desnoyers, Michal Hocko, Muchun Song,
Nico Pache, Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, Zi Yan, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
On Sun, Aug 23, 2026 at 8:18 PM Mike Rapoport (Microsoft)
<rppt@kernel.org> wrote:
>
> Move userfaultfd_{missing,wp,minor,rwp}() and userfaultfd_protected()
> ahead of uffd_disable_huge_pmd_share() and uffd_disable_fault_around()
> and make the latter two use the helpers rather than open coded VMA flag
> masks.
>
> Convert open coded VMA flag test in mfill_get_vma() to userfaultfd_wp()
> as well.
>
> With every user of the per-VMA uffd modes going through the helpers,
> their underlying representation can be changed in the next step.
>
> No functional change.
>
> Assisted-by: copilot:claude-opus-5
> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
LGTM,
Reviewed-by: Barry Song <baohua@kernel.org>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 6/6] userfaultfd: collapse VM_UFFD_{MISSING,WP,MINOR,RWP} into single VM_UFFD
2026-08-23 12:17 ` [PATCH 6/6] userfaultfd: collapse VM_UFFD_{MISSING,WP,MINOR,RWP} into single VM_UFFD Mike Rapoport (Microsoft)
@ 2026-08-24 7:11 ` Lance Yang
2026-08-24 8:17 ` Mike Rapoport
2026-08-25 12:44 ` Lorenzo Stoakes (ARM)
1 sibling, 1 reply; 32+ messages in thread
From: Lance Yang @ 2026-08-24 7:11 UTC (permalink / raw)
To: rppt
Cc: akpm, david, baolin.wang, baohua, dev.jain, hughd, jannh, jgg,
jhubbard, corbet, liam, ljs, mhiramat, mathieu.desnoyers, mhocko,
muchun.song, nico.pache, osalvador, pfalcato, peterx,
ryan.roberts, shakeel.butt, skhan, rostedt, surenb, usama.arif,
vbabka, ziy, linux-doc, linux-fsdevel, linux-kernel, linux-mm,
linux-trace-kernel, Lance Yang
On Sun, Aug 23, 2026 at 03:17:43PM +0300, Mike Rapoport (Microsoft) wrote:
[...]
>diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
>index 83587d34b189..193f6e65d875 100644
>--- a/mm/userfaultfd.c
>+++ b/mm/userfaultfd.c
>@@ -50,10 +50,10 @@ struct mfill_state {
> pmd_t *pmd;
> };
>
>-static bool anon_can_userfault(struct vm_area_struct *vma, vm_flags_t vm_flags)
>+static bool anon_can_userfault(struct vm_area_struct *vma, unsigned int mode)
> {
> /* anonymous memory does not support MINOR mode */
>- if (vm_flags & VM_UFFD_MINOR)
>+ if (mode & UFFD_MODE_MINOR)
> return false;
> return true;
> }
>@@ -462,7 +462,7 @@ static int mfill_copy_folio_locked(struct folio *folio, unsigned long src_addr)
> }
>
> #define MFILL_RETRY_STATE_VMA_FLAGS \
>- append_vma_flags(__VMA_UFFD_FLAGS, VMA_SHARED_BIT)
>+ append_vma_flags(VMA_UFFD, VMA_SHARED_BIT)
Looks like this drops registration mode from the retry snapshot. Assume a
shared shmem VMA is registered for MISSING and COPY reaches
mfill_copy_folio_retry(). While locks are dropped, the same userfaultfd|
can re-register the range for MINOR. VMA_UFFD, VM_SHARED, ops, file and
pgoff all stay unchanged, so the old COPY can continue instead of
returning -EAGAIN ... no?
The snapshot and comparison bracket the unlocked copy:
static int mfill_copy_folio_retry(struct mfill_state *mfill_state,
struct folio *folio)
{
...
mfill_retry_state_save(&retry_state, mfill_state->vma);
/* retry copying with mm_lock dropped */
mfill_put_vma(mfill_state);
...
/* reget VMA and PMD, they could change underneath us */
err = mfill_get_vma(mfill_state);
if (err)
return err;
if (mfill_retry_state_changed(&retry_state, mfill_state->vma))
return -EAGAIN;
...
}
Since mode now lives in vm_uffd_state.mode, could we save it before
mfill_put_vma() and compare it after mfill_get_vma()? The UFFD flags
comment also needs an update, since the mask no longer contains per mode
flags.
Maybe something like this?
---8<---
diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index 193f6e65d875..5e3c86fe8aee 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -493,7 +493,7 @@ static bool mfill_retry_state_changed(struct mfill_retry_state *state,
vma_flags_t flags = vma_flags_and_mask(&vma->flags,
MFILL_RETRY_STATE_VMA_FLAGS);
- /* Have any UFFD flags (missing, WP, minor) changed? */
+ /* Has UFFD registration or VMA sharing changed? */
if (!vma_flags_same_pair(&state->flags, &flags))
return true;
@@ -528,6 +528,7 @@ static int mfill_copy_folio_retry(struct mfill_state *mfill_state,
struct mfill_retry_state retry_state = { 0 };
struct mfill_retry_state *for_free __free(retry_put) = &retry_state;
unsigned long src_addr = mfill_state->src_addr;
+ unsigned int saved_mode = uffd_mode(mfill_state->vma);
void *kaddr;
int err;
@@ -549,7 +550,8 @@ static int mfill_copy_folio_retry(struct mfill_state *mfill_state,
if (err)
return err;
- if (mfill_retry_state_changed(&retry_state, mfill_state->vma))
+ if (saved_mode != uffd_mode(mfill_state->vma) ||
+ mfill_retry_state_changed(&retry_state, mfill_state->vma))
return -EAGAIN;
err = mfill_establish_pmd(mfill_state);
---
Cheers, Lance
^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: [PATCH 5/6] userfaultfd: decouple fault reason from VMA flags
2026-08-23 12:17 ` [PATCH 5/6] userfaultfd: decouple fault reason from VMA flags Mike Rapoport (Microsoft)
@ 2026-08-24 8:12 ` Muchun Song
2026-08-24 14:46 ` David Hildenbrand (Arm)
2026-08-24 16:28 ` Lorenzo Stoakes (ARM)
2 siblings, 0 replies; 32+ messages in thread
From: Muchun Song @ 2026-08-24 8:12 UTC (permalink / raw)
To: Mike Rapoport (Microsoft)
Cc: Andrew Morton, David Hildenbrand, Baolin Wang, Barry Song,
Dev Jain, Hugh Dickins, Jann Horn, Jason Gunthorpe, John Hubbard,
Jonathan Corbet, Lance Yang, Liam R. Howlett, Lorenzo Stoakes,
Masami Hiramatsu, Mathieu Desnoyers, Michal Hocko, Nico Pache,
Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, Zi Yan, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
> On Aug 23, 2026, at 20:17, Mike Rapoport (Microsoft) <rppt@kernel.org> wrote:
>
> Introduce enum uffd_reason to define reasons for user faults rather than
> overload VM_UFFD_* VMA flags for that.
>
> Using a dedicated enum makes the code clearer and decoupling the fault
> reason from VMA flags clears the way for moving the uffd mode bits out
> of VMA namespace.
>
> No functional change.
>
> Assisted-by: copilot:claude-opus-4.6
> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Acked-by: Muchun Song <muchun.song@linux.dev> # for HugeTLB.
Thanks.
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 6/6] userfaultfd: collapse VM_UFFD_{MISSING,WP,MINOR,RWP} into single VM_UFFD
2026-08-24 7:11 ` Lance Yang
@ 2026-08-24 8:17 ` Mike Rapoport
2026-08-24 8:27 ` Lance Yang
0 siblings, 1 reply; 32+ messages in thread
From: Mike Rapoport @ 2026-08-24 8:17 UTC (permalink / raw)
To: Lance Yang
Cc: akpm, david, baolin.wang, baohua, dev.jain, hughd, jannh, jgg,
jhubbard, corbet, liam, ljs, mhiramat, mathieu.desnoyers, mhocko,
muchun.song, nico.pache, osalvador, pfalcato, peterx,
ryan.roberts, shakeel.butt, skhan, rostedt, surenb, usama.arif,
vbabka, ziy, linux-doc, linux-fsdevel, linux-kernel, linux-mm,
linux-trace-kernel
Hi Lance,
On Mon, Aug 24, 2026 at 03:11:26PM +0800, Lance Yang wrote:
>
> On Sun, Aug 23, 2026 at 03:17:43PM +0300, Mike Rapoport (Microsoft) wrote:
> [...]
> >diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
> >index 83587d34b189..193f6e65d875 100644
> >--- a/mm/userfaultfd.c
> >+++ b/mm/userfaultfd.c
> >@@ -50,10 +50,10 @@ struct mfill_state {
> > pmd_t *pmd;
> > };
> >
> >-static bool anon_can_userfault(struct vm_area_struct *vma, vm_flags_t vm_flags)
> >+static bool anon_can_userfault(struct vm_area_struct *vma, unsigned int mode)
> > {
> > /* anonymous memory does not support MINOR mode */
> >- if (vm_flags & VM_UFFD_MINOR)
> >+ if (mode & UFFD_MODE_MINOR)
> > return false;
> > return true;
> > }
> >@@ -462,7 +462,7 @@ static int mfill_copy_folio_locked(struct folio *folio, unsigned long src_addr)
> > }
> >
> > #define MFILL_RETRY_STATE_VMA_FLAGS \
> >- append_vma_flags(__VMA_UFFD_FLAGS, VMA_SHARED_BIT)
> >+ append_vma_flags(VMA_UFFD, VMA_SHARED_BIT)
>
> Looks like this drops registration mode from the retry snapshot. Assume a
> shared shmem VMA is registered for MISSING and COPY reaches
> mfill_copy_folio_retry(). While locks are dropped, the same userfaultfd|
> can re-register the range for MINOR. VMA_UFFD, VM_SHARED, ops, file and
> pgoff all stay unchanged, so the old COPY can continue instead of
> returning -EAGAIN ... no?
Good catch, thanks!
> Maybe something like this?
I prefer to add mode to the retry_state:
diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index 193f6e65d875..a0377f7ecc69 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -471,6 +471,7 @@ static int mfill_copy_folio_locked(struct folio *folio, unsigned long src_addr)
*/
struct mfill_retry_state {
const struct vm_uffd_ops *ops;
+ unsigned long mode;
struct file *file;
vma_flags_t flags;
pgoff_t pgoff;
@@ -482,6 +483,7 @@ static void mfill_retry_state_save(struct mfill_retry_state *s,
s->flags = vma_flags_and_mask(&vma->flags, MFILL_RETRY_STATE_VMA_FLAGS);
s->ops = vma_uffd_ops(vma);
s->pgoff = vma_start_pgoff(vma);
+ s->mode = uffd_mode(vma);
if (vma->vm_file)
s->file = get_file(vma->vm_file);
@@ -493,8 +495,9 @@ static bool mfill_retry_state_changed(struct mfill_retry_state *state,
vma_flags_t flags = vma_flags_and_mask(&vma->flags,
MFILL_RETRY_STATE_VMA_FLAGS);
- /* Have any UFFD flags (missing, WP, minor) changed? */
- if (!vma_flags_same_pair(&state->flags, &flags))
+ /* UFFD registration mode or VMA sharing changed */
+ if (!vma_flags_same_pair(&state->flags, &flags) ||
+ s->mode != uffd_mode(vma))
return true;
/* VMA type or effective uffd_ops changed while the lock was dropped */
> Cheers, Lance
--
Sincerely yours,
Mike.
^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: [PATCH 6/6] userfaultfd: collapse VM_UFFD_{MISSING,WP,MINOR,RWP} into single VM_UFFD
2026-08-24 8:17 ` Mike Rapoport
@ 2026-08-24 8:27 ` Lance Yang
0 siblings, 0 replies; 32+ messages in thread
From: Lance Yang @ 2026-08-24 8:27 UTC (permalink / raw)
To: Mike Rapoport
Cc: akpm, david, baolin.wang, baohua, dev.jain, hughd, jannh, jgg,
jhubbard, corbet, liam, ljs, mhiramat, mathieu.desnoyers, mhocko,
muchun.song, nico.pache, osalvador, pfalcato, peterx,
ryan.roberts, shakeel.butt, skhan, rostedt, surenb, usama.arif,
vbabka, ziy, linux-doc, linux-fsdevel, linux-kernel, linux-mm,
linux-trace-kernel
On 2026/8/24 16:17, Mike Rapoport wrote:
> Hi Lance,
>
> On Mon, Aug 24, 2026 at 03:11:26PM +0800, Lance Yang wrote:
>>
>> On Sun, Aug 23, 2026 at 03:17:43PM +0300, Mike Rapoport (Microsoft) wrote:
>> [...]
>>> diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
>>> index 83587d34b189..193f6e65d875 100644
>>> --- a/mm/userfaultfd.c
>>> +++ b/mm/userfaultfd.c
>>> @@ -50,10 +50,10 @@ struct mfill_state {
>>> pmd_t *pmd;
>>> };
>>>
>>> -static bool anon_can_userfault(struct vm_area_struct *vma, vm_flags_t vm_flags)
>>> +static bool anon_can_userfault(struct vm_area_struct *vma, unsigned int mode)
>>> {
>>> /* anonymous memory does not support MINOR mode */
>>> - if (vm_flags & VM_UFFD_MINOR)
>>> + if (mode & UFFD_MODE_MINOR)
>>> return false;
>>> return true;
>>> }
>>> @@ -462,7 +462,7 @@ static int mfill_copy_folio_locked(struct folio *folio, unsigned long src_addr)
>>> }
>>>
>>> #define MFILL_RETRY_STATE_VMA_FLAGS \
>>> - append_vma_flags(__VMA_UFFD_FLAGS, VMA_SHARED_BIT)
>>> + append_vma_flags(VMA_UFFD, VMA_SHARED_BIT)
>>
>> Looks like this drops registration mode from the retry snapshot. Assume a
>> shared shmem VMA is registered for MISSING and COPY reaches
>> mfill_copy_folio_retry(). While locks are dropped, the same userfaultfd|
>> can re-register the range for MINOR. VMA_UFFD, VM_SHARED, ops, file and
>> pgoff all stay unchanged, so the old COPY can continue instead of
>> returning -EAGAIN ... no?
>
> Good catch, thanks!
Cheers!
>
>> Maybe something like this?
>
> I prefer to add mode to the retry_state:
>
> diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
> index 193f6e65d875..a0377f7ecc69 100644
> --- a/mm/userfaultfd.c
> +++ b/mm/userfaultfd.c
> @@ -471,6 +471,7 @@ static int mfill_copy_folio_locked(struct folio *folio, unsigned long src_addr)
> */
> struct mfill_retry_state {
> const struct vm_uffd_ops *ops;
> + unsigned long mode;
> struct file *file;
> vma_flags_t flags;
> pgoff_t pgoff;
> @@ -482,6 +483,7 @@ static void mfill_retry_state_save(struct mfill_retry_state *s,
> s->flags = vma_flags_and_mask(&vma->flags, MFILL_RETRY_STATE_VMA_FLAGS);
> s->ops = vma_uffd_ops(vma);
> s->pgoff = vma_start_pgoff(vma);
> + s->mode = uffd_mode(vma);
>
> if (vma->vm_file)
> s->file = get_file(vma->vm_file);
> @@ -493,8 +495,9 @@ static bool mfill_retry_state_changed(struct mfill_retry_state *state,
> vma_flags_t flags = vma_flags_and_mask(&vma->flags,
> MFILL_RETRY_STATE_VMA_FLAGS);
>
> - /* Have any UFFD flags (missing, WP, minor) changed? */
> - if (!vma_flags_same_pair(&state->flags, &flags))
> + /* UFFD registration mode or VMA sharing changed */
> + if (!vma_flags_same_pair(&state->flags, &flags) ||
> + s->mode != uffd_mode(vma))
I assume you meant
s/s->mode/state->mode/
With that, LGTM :)
> return true;
>
> /* VMA type or effective uffd_ops changed while the lock was dropped */
>
>> Cheers, Lance
>
Cheers, Lance
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 1/6] mm/gup: move gup_can_follow_protnone() to gup.c
2026-08-23 12:17 ` [PATCH 1/6] mm/gup: move gup_can_follow_protnone() to gup.c Mike Rapoport (Microsoft)
2026-08-23 21:03 ` Barry Song
@ 2026-08-24 14:42 ` David Hildenbrand (Arm)
2026-08-25 10:10 ` Mike Rapoport
2026-08-24 14:59 ` Lorenzo Stoakes (ARM)
2026-08-25 2:03 ` Zi Yan
3 siblings, 1 reply; 32+ messages in thread
From: David Hildenbrand (Arm) @ 2026-08-24 14:42 UTC (permalink / raw)
To: Mike Rapoport (Microsoft), Andrew Morton
Cc: Baolin Wang, Barry Song, Dev Jain, Hugh Dickins, Jann Horn,
Jason Gunthorpe, John Hubbard, Jonathan Corbet, Lance Yang,
Liam R. Howlett, Lorenzo Stoakes, Masami Hiramatsu,
Mathieu Desnoyers, Michal Hocko, Muchun Song, Nico Pache,
Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, Zi Yan, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
On 8/23/26 14:17, Mike Rapoport (Microsoft) wrote:
> gup_can_follow_protnone() is defined in include/linux/mm.h but only used
> by mm/gup.c.
>
> First, there is no reason to have it in already gigantic header.
Once upon a time there was a user in mm/huge_memory.c, in a beautifully named
function called follow_trans_huge_pmd().
>
> Next, the upcoming refactoring of userfaultfd flags will make
> gup_can_follow_protnone() depend on userfaultfd_k.h which would cause a
> cyclic header dependency.
>
> Move gup_can_follow_protnone() to mm/gup.c.
>
> No functional change.
>
> Assisted-by: copilot:claude-opus-5
> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> ---
[...]
> typedef int (*pte_fn_t)(pte_t *pte, unsigned long addr, void *data);
> extern int apply_to_page_range(struct mm_struct *mm, unsigned long address,
> unsigned long size, pte_fn_t fn, void *data);
> diff --git a/mm/gup.c b/mm/gup.c
> index eb898ea1ee22..500e2aa99e48 100644
> --- a/mm/gup.c
> +++ b/mm/gup.c
> @@ -633,6 +633,44 @@ static struct page *no_page_table(struct vm_area_struct *vma,
> return NULL;
> }
>
> +/*
> + * Indicates whether GUP can follow a PROT_NONE mapped page, or whether
> + * a (NUMA hinting or userfaultfd RWP) fault is required.
> + */
> +static inline bool gup_can_follow_protnone(const struct vm_area_struct *vma,
> + unsigned int flags)
While at it, could switch to double-tab here.
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
--
Cheers,
David
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 4/6] userfaultfd: rename vm_userfaultfd_ctx to vm_uffd_state
2026-08-23 12:17 ` [PATCH 4/6] userfaultfd: rename vm_userfaultfd_ctx to vm_uffd_state Mike Rapoport (Microsoft)
@ 2026-08-24 14:43 ` David Hildenbrand (Arm)
2026-08-24 15:42 ` Lorenzo Stoakes (ARM)
1 sibling, 0 replies; 32+ messages in thread
From: David Hildenbrand (Arm) @ 2026-08-24 14:43 UTC (permalink / raw)
To: Mike Rapoport (Microsoft), Andrew Morton
Cc: Baolin Wang, Barry Song, Dev Jain, Hugh Dickins, Jann Horn,
Jason Gunthorpe, John Hubbard, Jonathan Corbet, Lance Yang,
Liam R. Howlett, Lorenzo Stoakes, Masami Hiramatsu,
Mathieu Desnoyers, Michal Hocko, Muchun Song, Nico Pache,
Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, Zi Yan, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
On 8/23/26 14:17, Mike Rapoport (Microsoft) wrote:
> Rename struct vm_userfaultfd_ctx to vm_uffd_state to better reflect that
> it will represent the userfaultfd state for a VMA rather than just a
> context pointer.
>
> This is a preparatory step for extending the struct with a mode field.
>
> Mechanical rename, no functional change.
>
> Assisted-by: copilot:claude-opus-4.6
> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> ---
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
--
Cheers,
David
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 5/6] userfaultfd: decouple fault reason from VMA flags
2026-08-23 12:17 ` [PATCH 5/6] userfaultfd: decouple fault reason from VMA flags Mike Rapoport (Microsoft)
2026-08-24 8:12 ` Muchun Song
@ 2026-08-24 14:46 ` David Hildenbrand (Arm)
2026-08-24 16:28 ` Lorenzo Stoakes (ARM)
2 siblings, 0 replies; 32+ messages in thread
From: David Hildenbrand (Arm) @ 2026-08-24 14:46 UTC (permalink / raw)
To: Mike Rapoport (Microsoft), Andrew Morton
Cc: Baolin Wang, Barry Song, Dev Jain, Hugh Dickins, Jann Horn,
Jason Gunthorpe, John Hubbard, Jonathan Corbet, Lance Yang,
Liam R. Howlett, Lorenzo Stoakes, Masami Hiramatsu,
Mathieu Desnoyers, Michal Hocko, Muchun Song, Nico Pache,
Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, Zi Yan, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
On 8/23/26 14:17, Mike Rapoport (Microsoft) wrote:
> Introduce enum uffd_reason to define reasons for user faults rather than
> overload VM_UFFD_* VMA flags for that.
>
> Using a dedicated enum makes the code clearer and decoupling the fault
> reason from VMA flags clears the way for moving the uffd mode bits out
> of VMA namespace.
>
> No functional change.
>
> Assisted-by: copilot:claude-opus-4.6
> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> ---
> include/linux/userfaultfd_k.h | 16 ++++++++++++++--
> include/uapi/linux/userfaultfd.h | 6 +++---
> mm/huge_memory.c | 6 +++---
> mm/hugetlb.c | 10 +++++-----
> mm/memory.c | 10 +++++-----
> mm/shmem.c | 4 ++--
> mm/userfaultfd.c | 30 +++++++++++++++---------------
> 7 files changed, 47 insertions(+), 35 deletions(-)
>
> diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
> index 45355bdb4ec7..f401623f315d 100644
> --- a/include/linux/userfaultfd_k.h
> +++ b/include/linux/userfaultfd_k.h
> @@ -9,6 +9,18 @@
> #ifndef _LINUX_USERFAULTFD_K_H
> #define _LINUX_USERFAULTFD_K_H
>
> +#include <linux/bits.h>
> +
> +/* Fault reason #PF handler passes to handle_userfault() */
> +enum uf_reason {
Can we just call this "userfault_reason" or "uffd_reason" ? Maybe the latter is
actually what we want?
--
Cheers,
David
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 1/6] mm/gup: move gup_can_follow_protnone() to gup.c
2026-08-23 12:17 ` [PATCH 1/6] mm/gup: move gup_can_follow_protnone() to gup.c Mike Rapoport (Microsoft)
2026-08-23 21:03 ` Barry Song
2026-08-24 14:42 ` David Hildenbrand (Arm)
@ 2026-08-24 14:59 ` Lorenzo Stoakes (ARM)
2026-08-25 2:03 ` Zi Yan
3 siblings, 0 replies; 32+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-08-24 14:59 UTC (permalink / raw)
To: Mike Rapoport (Microsoft)
Cc: Andrew Morton, David Hildenbrand, Baolin Wang, Barry Song,
Dev Jain, Hugh Dickins, Jann Horn, Jason Gunthorpe, John Hubbard,
Jonathan Corbet, Lance Yang, Liam R. Howlett, Masami Hiramatsu,
Mathieu Desnoyers, Michal Hocko, Muchun Song, Nico Pache,
Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, Zi Yan, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
On Sun, Aug 23, 2026 at 03:17:38PM +0300, Mike Rapoport (Microsoft) wrote:
> gup_can_follow_protnone() is defined in include/linux/mm.h but only used
> by mm/gup.c.
>
> First, there is no reason to have it in already gigantic header.
>
> Next, the upcoming refactoring of userfaultfd flags will make
> gup_can_follow_protnone() depend on userfaultfd_k.h which would cause a
> cyclic header dependency.
>
> Move gup_can_follow_protnone() to mm/gup.c.
>
> No functional change.
>
> Assisted-by: copilot:claude-opus-5
> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
LGTM so:
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
> ---
> include/linux/mm.h | 38 --------------------------------------
> mm/gup.c | 38 ++++++++++++++++++++++++++++++++++++++
> 2 files changed, 38 insertions(+), 38 deletions(-)
>
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 0829e0d3b2d1..4daf9cd6ae8e 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -4860,44 +4860,6 @@ static inline int vm_fault_to_errno(vm_fault_t vm_fault, int foll_flags)
> return 0;
> }
>
> -/*
> - * Indicates whether GUP can follow a PROT_NONE mapped page, or whether
> - * a (NUMA hinting or userfaultfd RWP) fault is required.
> - */
> -static inline bool gup_can_follow_protnone(const struct vm_area_struct *vma,
> - unsigned int flags)
> -{
> - /*
> - * VM_UFFD_RWP uses protnone as an access-tracking marker, not for
> - * NUMA hinting. GUP must always take a fault so the access is
> - * delivered to userfaultfd, regardless of FOLL_HONOR_NUMA_FAULT.
> - *
> - * Only do so while the VMA is accessible. If it has been made
> - * inaccessible (e.g. mprotect(PROT_NONE)), fall through to the guard
> - * below: forcing a fault there would loop, as handle_mm_fault() makes
> - * no progress on protnone in an inaccessible VMA, and the access is
> - * denied regardless of RWP anyway.
> - */
> - if (vma_test_single_mask(vma, VMA_UFFD_RWP) && vma_is_accessible(vma))
> - return false;
> -
> - /*
> - * If callers don't want to honor NUMA hinting faults, no need to
> - * determine if we would actually have to trigger a NUMA hinting fault.
> - */
> - if (!(flags & FOLL_HONOR_NUMA_FAULT))
> - return true;
> -
> - /*
> - * NUMA hinting faults don't apply in inaccessible (PROT_NONE) VMAs.
> - *
> - * Requiring a fault here even for inaccessible VMAs would mean that
> - * FOLL_FORCE cannot make any progress, because handle_mm_fault()
> - * refuses to process NUMA hinting faults in inaccessible VMAs.
> - */
> - return !vma_is_accessible(vma);
> -}
> -
> typedef int (*pte_fn_t)(pte_t *pte, unsigned long addr, void *data);
> extern int apply_to_page_range(struct mm_struct *mm, unsigned long address,
> unsigned long size, pte_fn_t fn, void *data);
> diff --git a/mm/gup.c b/mm/gup.c
> index eb898ea1ee22..500e2aa99e48 100644
> --- a/mm/gup.c
> +++ b/mm/gup.c
> @@ -633,6 +633,44 @@ static struct page *no_page_table(struct vm_area_struct *vma,
> return NULL;
> }
>
> +/*
> + * Indicates whether GUP can follow a PROT_NONE mapped page, or whether
> + * a (NUMA hinting or userfaultfd RWP) fault is required.
> + */
> +static inline bool gup_can_follow_protnone(const struct vm_area_struct *vma,
> + unsigned int flags)
> +{
> + /*
> + * VM_UFFD_RWP uses protnone as an access-tracking marker, not for
> + * NUMA hinting. GUP must always take a fault so the access is
> + * delivered to userfaultfd, regardless of FOLL_HONOR_NUMA_FAULT.
> + *
> + * Only do so while the VMA is accessible. If it has been made
> + * inaccessible (e.g. mprotect(PROT_NONE)), fall through to the guard
> + * below: forcing a fault there would loop, as handle_mm_fault() makes
> + * no progress on protnone in an inaccessible VMA, and the access is
> + * denied regardless of RWP anyway.
> + */
> + if (vma_test_single_mask(vma, VMA_UFFD_RWP) && vma_is_accessible(vma))
> + return false;
> +
> + /*
> + * If callers don't want to honor NUMA hinting faults, no need to
> + * determine if we would actually have to trigger a NUMA hinting fault.
> + */
> + if (!(flags & FOLL_HONOR_NUMA_FAULT))
> + return true;
> +
> + /*
> + * NUMA hinting faults don't apply in inaccessible (PROT_NONE) VMAs.
> + *
> + * Requiring a fault here even for inaccessible VMAs would mean that
> + * FOLL_FORCE cannot make any progress, because handle_mm_fault()
> + * refuses to process NUMA hinting faults in inaccessible VMAs.
> + */
> + return !vma_is_accessible(vma);
> +}
> +
> #ifdef CONFIG_PGTABLE_HAS_HUGE_LEAVES
> /* FOLL_FORCE can write to even unwritable PUDs in COW mappings. */
> static inline bool can_follow_write_pud(pud_t pud, struct page *page,
>
> --
> 2.53.0
>
--
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 2/6] userfaultfd: constify VMA parameter of userfaultfd_*() helpers
2026-08-23 12:17 ` [PATCH 2/6] userfaultfd: constify VMA parameter of userfaultfd_*() helpers Mike Rapoport (Microsoft)
2026-08-23 21:03 ` Barry Song
@ 2026-08-24 15:03 ` Lorenzo Stoakes (ARM)
2026-08-25 2:03 ` Zi Yan
2 siblings, 0 replies; 32+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-08-24 15:03 UTC (permalink / raw)
To: Mike Rapoport (Microsoft)
Cc: Andrew Morton, David Hildenbrand, Baolin Wang, Barry Song,
Dev Jain, Hugh Dickins, Jann Horn, Jason Gunthorpe, John Hubbard,
Jonathan Corbet, Lance Yang, Liam R. Howlett, Masami Hiramatsu,
Mathieu Desnoyers, Michal Hocko, Muchun Song, Nico Pache,
Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, Zi Yan, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
On Sun, Aug 23, 2026 at 03:17:39PM +0300, Mike Rapoport (Microsoft) wrote:
> userfaultfd_{missing,wp,minor,rwp}() and userfaultfd_protected() only
> read the VMA.
>
> Make their vma parameter const.
>
> No functional change.
>
> Assisted-by: copilot:claude-opus-5
> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
LGTM and compiles GTM so:
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
> ---
> include/linux/userfaultfd_k.h | 20 ++++++++++----------
> 1 file changed, 10 insertions(+), 10 deletions(-)
>
> diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
> index a4351cffc60c..3396d270b159 100644
> --- a/include/linux/userfaultfd_k.h
> +++ b/include/linux/userfaultfd_k.h
> @@ -204,22 +204,22 @@ static inline bool uffd_disable_fault_around(struct vm_area_struct *vma)
> VMA_UFFD_MINOR));
> }
>
> -static inline bool userfaultfd_missing(struct vm_area_struct *vma)
> +static inline bool userfaultfd_missing(const struct vm_area_struct *vma)
> {
> return vma_test_any_mask(vma, VMA_UFFD_MISSING);
> }
>
> -static inline bool userfaultfd_wp(struct vm_area_struct *vma)
> +static inline bool userfaultfd_wp(const struct vm_area_struct *vma)
> {
> return vma_test_any_mask(vma, VMA_UFFD_WP);
> }
>
> -static inline bool userfaultfd_minor(struct vm_area_struct *vma)
> +static inline bool userfaultfd_minor(const struct vm_area_struct *vma)
> {
> return vma_test_any_mask(vma, VMA_UFFD_MINOR);
> }
>
> -static inline bool userfaultfd_rwp(struct vm_area_struct *vma)
> +static inline bool userfaultfd_rwp(const struct vm_area_struct *vma)
> {
> /*
> * Callers gate PAGE_NONE usage on this; PAGE_NONE is a BUILD_BUG()
> @@ -230,7 +230,7 @@ static inline bool userfaultfd_rwp(struct vm_area_struct *vma)
> return vma_test_single_mask(vma, VMA_UFFD_RWP);
> }
>
> -static inline bool userfaultfd_protected(struct vm_area_struct *vma)
> +static inline bool userfaultfd_protected(const struct vm_area_struct *vma)
> {
> return userfaultfd_wp(vma) || userfaultfd_rwp(vma);
> }
> @@ -353,27 +353,27 @@ static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
> return true;
> }
>
> -static inline bool userfaultfd_missing(struct vm_area_struct *vma)
> +static inline bool userfaultfd_missing(const struct vm_area_struct *vma)
> {
> return false;
> }
>
> -static inline bool userfaultfd_wp(struct vm_area_struct *vma)
> +static inline bool userfaultfd_wp(const struct vm_area_struct *vma)
> {
> return false;
> }
>
> -static inline bool userfaultfd_minor(struct vm_area_struct *vma)
> +static inline bool userfaultfd_minor(const struct vm_area_struct *vma)
> {
> return false;
> }
>
> -static inline bool userfaultfd_rwp(struct vm_area_struct *vma)
> +static inline bool userfaultfd_rwp(const struct vm_area_struct *vma)
> {
> return false;
> }
>
> -static inline bool userfaultfd_protected(struct vm_area_struct *vma)
> +static inline bool userfaultfd_protected(const struct vm_area_struct *vma)
> {
> return false;
> }
>
> --
> 2.53.0
>
--
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 3/6] userfaultfd: use userfaultfd_*() helpers instead of open coded flag tests
2026-08-23 12:17 ` [PATCH 3/6] userfaultfd: use userfaultfd_*() helpers instead of open coded flag tests Mike Rapoport (Microsoft)
2026-08-23 21:14 ` Barry Song
@ 2026-08-24 15:10 ` Lorenzo Stoakes (ARM)
2026-08-25 11:19 ` Mike Rapoport
1 sibling, 1 reply; 32+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-08-24 15:10 UTC (permalink / raw)
To: Mike Rapoport (Microsoft)
Cc: Andrew Morton, David Hildenbrand, Baolin Wang, Barry Song,
Dev Jain, Hugh Dickins, Jann Horn, Jason Gunthorpe, John Hubbard,
Jonathan Corbet, Lance Yang, Liam R. Howlett, Masami Hiramatsu,
Mathieu Desnoyers, Michal Hocko, Muchun Song, Nico Pache,
Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, Zi Yan, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
On Sun, Aug 23, 2026 at 03:17:40PM +0300, Mike Rapoport (Microsoft) wrote:
> Move userfaultfd_{missing,wp,minor,rwp}() and userfaultfd_protected()
> ahead of uffd_disable_huge_pmd_share() and uffd_disable_fault_around()
> and make the latter two use the helpers rather than open coded VMA flag
> masks.
>
> Convert open coded VMA flag test in mfill_get_vma() to userfaultfd_wp()
> as well.
It'd be better to do the moves and the reworks separately. We don't have a limit
on patch count :)
>
> With every user of the per-VMA uffd modes going through the helpers,
> their underlying representation can be changed in the next step.
>
> No functional change.
There is a functional change, or at least seems to be, see below.
>
> Assisted-by: copilot:claude-opus-5
> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> ---
> include/linux/userfaultfd_k.h | 70 +++++++++++++++++++++----------------------
> mm/userfaultfd.c | 2 +-
> 2 files changed, 35 insertions(+), 37 deletions(-)
>
> diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
> index 3396d270b159..d8262e3dc134 100644
> --- a/include/linux/userfaultfd_k.h
> +++ b/include/linux/userfaultfd_k.h
> @@ -168,42 +168,6 @@ static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
> return vma->vm_userfaultfd_ctx.ctx == vm_ctx.ctx;
> }
>
> -/*
> - * Never enable huge pmd sharing on some uffd registered vmas:
> - *
> - * - VM_UFFD_WP and VM_UFFD_RWP VMAs, because the write protect / access
> - * tracking information is per pgtable entry.
> - *
> - * - VM_UFFD_MINOR VMAs, because otherwise we would never get minor faults for
> - * VMAs which share huge pmds. (If you have two mappings to the same
> - * underlying pages, and fault in the non-UFFD-registered one with a write,
> - * with huge pmd sharing this would *also* setup the second UFFD-registered
> - * mapping, and we'd not get minor faults.)
> - */
> -static inline bool uffd_disable_huge_pmd_share(struct vm_area_struct *vma)
> -{
> - return vma_test_any_mask(vma,
> - mk_vma_flags_from_masks(VMA_UFFD_WP, VMA_UFFD_RWP,
> - VMA_UFFD_MINOR));
> -}
> -
> -/*
> - * Don't do fault around for WP, RWP or MINOR registered uffd range. For
> - * MINOR registered range, fault around will be a total disaster and ptes can
> - * be installed without notifications; for WP it should mostly be fine as long
> - * as the fault around checks for pte_none() before the installation, however
> - * to be super safe we just forbid it; for RWP, pre-faulted neighbours would
> - * be indistinguishable from accessed pages in PAGEMAP_SCAN (PAGE_IS_ACCESSED)
> - * and pollute the tracked working set, so each page must be populated by its
> - * own fault.
> - */
> -static inline bool uffd_disable_fault_around(struct vm_area_struct *vma)
> -{
> - return vma_test_any_mask(vma,
> - mk_vma_flags_from_masks(VMA_UFFD_WP, VMA_UFFD_RWP,
> - VMA_UFFD_MINOR));
> -}
> -
> static inline bool userfaultfd_missing(const struct vm_area_struct *vma)
> {
> return vma_test_any_mask(vma, VMA_UFFD_MISSING);
> @@ -235,6 +199,40 @@ static inline bool userfaultfd_protected(const struct vm_area_struct *vma)
> return userfaultfd_wp(vma) || userfaultfd_rwp(vma);
> }
>
> +/*
> + * Never enable huge pmd sharing on some uffd registered vmas:
> + *
> + * - uffd-WP and uffd-RWP VMAs, because the write protect / access tracking
> + * information is per pgtable entry.
> + *
> + * - uffd-MINOR VMAs, because otherwise we would never get minor faults for
> + * VMAs which share huge pmds. (If you have two mappings to the same
> + * underlying pages, and fault in the non-UFFD-registered one with a write,
> + * with huge pmd sharing this would *also* setup the second UFFD-registered
> + * mapping, and we'd not get minor faults.)
> + */
> +static inline bool uffd_disable_huge_pmd_share(struct vm_area_struct *vma)
> +{
> + return userfaultfd_minor(vma) || userfaultfd_wp(vma) ||
> + userfaultfd_rwp(vma);
> +}
> +
> +/*
> + * Don't do fault around for WP, RWP or MINOR registered uffd range. For
> + * MINOR registered range, fault around will be a total disaster and ptes can
> + * be installed without notifications; for WP it should mostly be fine as long
> + * as the fault around checks for pte_none() before the installation, however
> + * to be super safe we just forbid it; for RWP, pre-faulted neighbours would
> + * be indistinguishable from accessed pages in PAGEMAP_SCAN (PAGE_IS_ACCESSED)
> + * and pollute the tracked working set, so each page must be populated by its
> + * own fault.
> + */
> +static inline bool uffd_disable_fault_around(struct vm_area_struct *vma)
> +{
> + return userfaultfd_minor(vma) || userfaultfd_wp(vma) ||
> + userfaultfd_rwp(vma);
This is changing the logic.
Before we were testing only the flags, now we have:
static inline bool userfaultfd_rwp(const struct vm_area_struct *vma)
{
/*
* Callers gate PAGE_NONE usage on this; PAGE_NONE is a BUILD_BUG()
* without CONFIG_ARCH_HAS_PTE_PROTNONE, so fold to false.
*/
if (!IS_ENABLED(CONFIG_ARCH_HAS_PTE_PROTNONE))
return false;
return vma_test_single_mask(vma, VMA_UFFD_RWP);
}
I.e. adding in a CONFIG_ARCH_HAS_PTE_PROTNONE check.
BTW side-note these:
static inline bool userfaultfd_missing(const struct vm_area_struct *vma)
{
return vma_test_any_mask(vma, VMA_UFFD_MISSING);
}
static inline bool userfaultfd_wp(const struct vm_area_struct *vma)
{
return vma_test_any_mask(vma, VMA_UFFD_WP);
}
static inline bool userfaultfd_minor(const struct vm_area_struct *vma)
{
return vma_test_any_mask(vma, VMA_UFFD_MINOR);
}
Should all use vma_test_single_mask() really :)
> +}
> +
> static inline bool userfaultfd_pte_wp(struct vm_area_struct *vma,
> pte_t pte)
> {
> diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
> index 74f04c323c50..32003aa04943 100644
> --- a/mm/userfaultfd.c
> +++ b/mm/userfaultfd.c
> @@ -261,7 +261,7 @@ static int mfill_get_vma(struct mfill_state *state)
> * validate 'mode' now that we know the dst_vma: don't allow
> * a wrprotect copy if the userfaultfd didn't register as WP.
> */
> - if ((flags & MFILL_ATOMIC_WP) && !(dst_vma->vm_flags & VM_UFFD_WP))
> + if ((flags & MFILL_ATOMIC_WP) && !userfaultfd_wp(dst_vma))
> goto out_unlock;
>
> if (is_vm_hugetlb_page(dst_vma))
>
> --
> 2.53.0
>
--
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 4/6] userfaultfd: rename vm_userfaultfd_ctx to vm_uffd_state
2026-08-23 12:17 ` [PATCH 4/6] userfaultfd: rename vm_userfaultfd_ctx to vm_uffd_state Mike Rapoport (Microsoft)
2026-08-24 14:43 ` David Hildenbrand (Arm)
@ 2026-08-24 15:42 ` Lorenzo Stoakes (ARM)
1 sibling, 0 replies; 32+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-08-24 15:42 UTC (permalink / raw)
To: Mike Rapoport (Microsoft)
Cc: Andrew Morton, David Hildenbrand, Baolin Wang, Barry Song,
Dev Jain, Hugh Dickins, Jann Horn, Jason Gunthorpe, John Hubbard,
Jonathan Corbet, Lance Yang, Liam R. Howlett, Masami Hiramatsu,
Mathieu Desnoyers, Michal Hocko, Muchun Song, Nico Pache,
Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, Zi Yan, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
On Sun, Aug 23, 2026 at 03:17:41PM +0300, Mike Rapoport (Microsoft) wrote:
> Rename struct vm_userfaultfd_ctx to vm_uffd_state to better reflect that
> it will represent the userfaultfd state for a VMA rather than just a
> context pointer.
>
> This is a preparatory step for extending the struct with a mode field.
>
> Mechanical rename, no functional change.
>
> Assisted-by: copilot:claude-opus-4.6
> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
LGTM and compiles GTM so:
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
> ---
> Documentation/mm/process_addrs.rst | 4 +--
> include/linux/mm_types.h | 10 +++---
> include/linux/userfaultfd_k.h | 24 ++++++-------
> mm/mremap.c | 4 +--
> mm/userfaultfd.c | 74 +++++++++++++++++++-------------------
> mm/vma.c | 4 +--
> mm/vma.h | 6 ++--
> mm/vma_init.c | 4 +--
> tools/testing/vma/include/dup.h | 2 +-
> tools/testing/vma/include/stubs.h | 6 ++--
> 10 files changed, 69 insertions(+), 69 deletions(-)
>
> diff --git a/Documentation/mm/process_addrs.rst b/Documentation/mm/process_addrs.rst
> index a7296f251799..481e9435e4e8 100644
> --- a/Documentation/mm/process_addrs.rst
> +++ b/Documentation/mm/process_addrs.rst
> @@ -229,8 +229,8 @@ These are the core fields which describe the MM the VMA belongs to and its attri
> NUMA balancing in relation to this VMA. lock.
> Updated under mmap read lock by
> :c:func:`!task_numa_work`.
> - :c:member:`!vm_userfaultfd_ctx` CONFIG_USERFAULTFD Userfaultfd context wrapper object of mmap write,
> - type :c:type:`!vm_userfaultfd_ctx`, VMA write.
> + :c:member:`!vm_uffd_state` CONFIG_USERFAULTFD Userfaultfd context wrapper object of mmap write,
> + type :c:type:`!vm_uffd_state`, VMA write.
> either of zero size if userfaultfd is
> disabled, or containing a pointer
> to an underlying
> diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
> index 6d815f6440c9..d6deb655d82e 100644
> --- a/include/linux/mm_types.h
> +++ b/include/linux/mm_types.h
> @@ -720,13 +720,13 @@ struct vm_region {
> };
>
> #ifdef CONFIG_USERFAULTFD
> -#define NULL_VM_UFFD_CTX ((struct vm_userfaultfd_ctx) { NULL, })
> -struct vm_userfaultfd_ctx {
> +#define NULL_VM_UFFD_STATE ((struct vm_uffd_state) { NULL, })
> +struct vm_uffd_state {
> struct userfaultfd_ctx *ctx;
> };
> #else /* CONFIG_USERFAULTFD */
> -#define NULL_VM_UFFD_CTX ((struct vm_userfaultfd_ctx) {})
> -struct vm_userfaultfd_ctx {};
> +#define NULL_VM_UFFD_STATE ((struct vm_uffd_state) {})
> +struct vm_uffd_state {};
> #endif /* CONFIG_USERFAULTFD */
>
> struct anon_vma_name {
> @@ -1071,7 +1071,7 @@ struct vm_area_struct {
> */
> struct anon_vma_name *anon_name;
> #endif
> - struct vm_userfaultfd_ctx vm_userfaultfd_ctx;
> + struct vm_uffd_state vm_uffd_state;
> #ifdef __HAVE_PFNMAP_TRACKING
> struct pfnmap_track_ctx *pfnmap_track_ctx;
> #endif
> diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
> index d8262e3dc134..45355bdb4ec7 100644
> --- a/include/linux/userfaultfd_k.h
> +++ b/include/linux/userfaultfd_k.h
> @@ -162,10 +162,10 @@ int move_pages_huge_pmd(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd, pm
> unsigned long dst_addr, unsigned long src_addr);
>
> /* mm helpers */
> -static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
> - struct vm_userfaultfd_ctx vm_ctx)
> +static inline bool is_mergeable_vm_uffd_state(struct vm_area_struct *vma,
> + struct vm_uffd_state vm_ctx)
> {
> - return vma->vm_userfaultfd_ctx.ctx == vm_ctx.ctx;
> + return vma->vm_uffd_state.ctx == vm_ctx.ctx;
> }
>
> static inline bool userfaultfd_missing(const struct vm_area_struct *vma)
> @@ -264,7 +264,7 @@ static inline bool userfaultfd_armed(struct vm_area_struct *vma)
>
> static inline bool vma_has_uffd_without_event_remap(struct vm_area_struct *vma)
> {
> - struct userfaultfd_ctx *uffd_ctx = vma->vm_userfaultfd_ctx.ctx;
> + struct userfaultfd_ctx *uffd_ctx = vma->vm_uffd_state.ctx;
>
> return uffd_ctx && (uffd_ctx->features & UFFD_FEATURE_EVENT_REMAP) == 0;
> }
> @@ -274,11 +274,11 @@ extern void dup_userfaultfd_complete(struct list_head *);
> void dup_userfaultfd_fail(struct list_head *);
>
> extern void mremap_userfaultfd_prep(struct vm_area_struct *,
> - struct vm_userfaultfd_ctx *);
> -extern void mremap_userfaultfd_complete(struct vm_userfaultfd_ctx *,
> + struct vm_uffd_state *);
> +extern void mremap_userfaultfd_complete(struct vm_uffd_state *,
> unsigned long from, unsigned long to,
> unsigned long len);
> -void mremap_userfaultfd_fail(struct vm_userfaultfd_ctx *);
> +void mremap_userfaultfd_fail(struct vm_uffd_state *);
>
> extern bool userfaultfd_remove(struct vm_area_struct *vma,
> unsigned long start,
> @@ -345,8 +345,8 @@ static inline long uffd_wp_range(struct vm_area_struct *vma,
> return false;
> }
>
> -static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
> - struct vm_userfaultfd_ctx vm_ctx)
> +static inline bool is_mergeable_vm_uffd_state(struct vm_area_struct *vma,
> + struct vm_uffd_state vm_ctx)
> {
> return true;
> }
> @@ -420,18 +420,18 @@ static inline void dup_userfaultfd_fail(struct list_head *l)
> }
>
> static inline void mremap_userfaultfd_prep(struct vm_area_struct *vma,
> - struct vm_userfaultfd_ctx *ctx)
> + struct vm_uffd_state *ctx)
> {
> }
>
> -static inline void mremap_userfaultfd_complete(struct vm_userfaultfd_ctx *ctx,
> +static inline void mremap_userfaultfd_complete(struct vm_uffd_state *ctx,
> unsigned long from,
> unsigned long to,
> unsigned long len)
> {
> }
>
> -static inline void mremap_userfaultfd_fail(struct vm_userfaultfd_ctx *ctx)
> +static inline void mremap_userfaultfd_fail(struct vm_uffd_state *ctx)
> {
> }
>
> diff --git a/mm/mremap.c b/mm/mremap.c
> index e8df5cdb0ac9..a4a38f30b255 100644
> --- a/mm/mremap.c
> +++ b/mm/mremap.c
> @@ -56,7 +56,7 @@ struct vma_remap_struct {
> unsigned long new_addr; /* Optionally, desired new address. */
>
> /* uffd state. */
> - struct vm_userfaultfd_ctx *uf;
> + struct vm_uffd_state *uf;
> struct list_head *uf_unmap_early;
> struct list_head *uf_unmap;
>
> @@ -2033,7 +2033,7 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len,
> unsigned long, new_len, unsigned long, flags,
> unsigned long, new_addr)
> {
> - struct vm_userfaultfd_ctx uf = NULL_VM_UFFD_CTX;
> + struct vm_uffd_state uf = NULL_VM_UFFD_STATE;
> LIST_HEAD(uf_unmap_early);
> LIST_HEAD(uf_unmap);
> /*
> diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
> index 32003aa04943..119304547230 100644
> --- a/mm/userfaultfd.c
> +++ b/mm/userfaultfd.c
> @@ -99,7 +99,7 @@ bool validate_dst_vma(struct vm_area_struct *dst_vma, unsigned long dst_end)
> * enforce the VM_MAYWRITE check done at uffd registration
> * time.
> */
> - if (!dst_vma->vm_userfaultfd_ctx.ctx)
> + if (!dst_vma->vm_uffd_state.ctx)
> return false;
>
> return true;
> @@ -1812,8 +1812,8 @@ static int validate_move_areas(struct userfaultfd_ctx *ctx,
> return -EINVAL;
>
> /* Ensure dst_vma is registered in uffd we are operating on */
> - if (!dst_vma->vm_userfaultfd_ctx.ctx ||
> - dst_vma->vm_userfaultfd_ctx.ctx != ctx)
> + if (!dst_vma->vm_uffd_state.ctx ||
> + dst_vma->vm_uffd_state.ctx != ctx)
> return -EINVAL;
>
> /* Only allow moving across anonymous vmas */
> @@ -2249,7 +2249,7 @@ static void userfaultfd_set_ctx(struct vm_area_struct *vma,
> vm_flags_t vm_flags)
> {
> vma_start_write(vma);
> - vma->vm_userfaultfd_ctx = (struct vm_userfaultfd_ctx){ctx};
> + vma->vm_uffd_state = (struct vm_uffd_state){ctx};
> userfaultfd_set_vm_flags(vma,
> (vma->vm_flags & ~__VM_UFFD_FLAGS) | vm_flags);
> }
> @@ -2296,7 +2296,7 @@ static struct vm_area_struct *userfaultfd_clear_vma(struct vma_iterator *vmi,
> }
>
> ret = vma_modify_flags_uffd(vmi, prev, vma, start, end,
> - &new_vma_flags, NULL_VM_UFFD_CTX,
> + &new_vma_flags, NULL_VM_UFFD_STATE,
> give_up_on_oom);
>
> /*
> @@ -2330,15 +2330,15 @@ static int userfaultfd_register_range(struct userfaultfd_ctx *ctx,
> cond_resched();
>
> VM_WARN_ON_ONCE(!vma_can_userfault(vma, vm_flags, wp_async));
> - VM_WARN_ON_ONCE(vma->vm_userfaultfd_ctx.ctx &&
> - vma->vm_userfaultfd_ctx.ctx != ctx);
> + VM_WARN_ON_ONCE(vma->vm_uffd_state.ctx &&
> + vma->vm_uffd_state.ctx != ctx);
> VM_WARN_ON_ONCE(!vma_test(vma, VMA_MAYWRITE_BIT));
>
> /*
> * Nothing to do: this vma is already registered into this
> * userfaultfd and with the right tracking mode too.
> */
> - if (vma->vm_userfaultfd_ctx.ctx == ctx &&
> + if (vma->vm_uffd_state.ctx == ctx &&
> vma_test_all_mask(vma, vma_flags))
> goto skip;
>
> @@ -2347,7 +2347,7 @@ static int userfaultfd_register_range(struct userfaultfd_ctx *ctx,
> * switches that would drop VM_UFFD_WP or VM_UFFD_RWP, so a
> * stray bit here is a bug.
> */
> - VM_WARN_ON_ONCE(vma->vm_userfaultfd_ctx.ctx == ctx &&
> + VM_WARN_ON_ONCE(vma->vm_uffd_state.ctx == ctx &&
> vma->vm_flags & (VM_UFFD_WP | VM_UFFD_RWP) & ~vm_flags);
>
> if (vma->vm_start > start)
> @@ -2360,7 +2360,7 @@ static int userfaultfd_register_range(struct userfaultfd_ctx *ctx,
>
> vma = vma_modify_flags_uffd(&vmi, prev, vma, start, vma_end,
> &new_vma_flags,
> - (struct vm_userfaultfd_ctx){ctx},
> + (struct vm_uffd_state){ctx},
> /* give_up_on_oom = */false);
> if (IS_ERR(vma))
> return PTR_ERR(vma);
> @@ -2389,10 +2389,10 @@ static void userfaultfd_release_new(struct userfaultfd_ctx *ctx)
> struct vm_area_struct *vma;
> VMA_ITERATOR(vmi, mm, 0);
>
> - /* the various vma->vm_userfaultfd_ctx still points to it */
> + /* the various vma->vm_uffd_state still points to it */
> mmap_write_lock(mm);
> for_each_vma(vmi, vma) {
> - if (vma->vm_userfaultfd_ctx.ctx == ctx)
> + if (vma->vm_uffd_state.ctx == ctx)
> userfaultfd_reset_ctx(vma);
> }
> mmap_write_unlock(mm);
> @@ -2419,9 +2419,9 @@ static void userfaultfd_release_all(struct mm_struct *mm,
> prev = NULL;
> for_each_vma(vmi, vma) {
> cond_resched();
> - VM_WARN_ON_ONCE(!!vma->vm_userfaultfd_ctx.ctx ^
> + VM_WARN_ON_ONCE(!!vma->vm_uffd_state.ctx ^
> !!(vma->vm_flags & __VM_UFFD_FLAGS));
> - if (vma->vm_userfaultfd_ctx.ctx != ctx) {
> + if (vma->vm_uffd_state.ctx != ctx) {
> prev = vma;
> continue;
> }
> @@ -2512,7 +2512,7 @@ static bool userfaultfd_rwp_async_ctx(struct userfaultfd_ctx *ctx)
> */
> bool userfaultfd_wp_unpopulated(struct vm_area_struct *vma)
> {
> - struct userfaultfd_ctx *ctx = vma->vm_userfaultfd_ctx.ctx;
> + struct userfaultfd_ctx *ctx = vma->vm_uffd_state.ctx;
>
> if (!ctx)
> return false;
> @@ -2854,7 +2854,7 @@ vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason)
>
> assert_fault_locked(vmf);
>
> - ctx = vma->vm_userfaultfd_ctx.ctx;
> + ctx = vma->vm_uffd_state.ctx;
> if (!ctx)
> goto out;
>
> @@ -3094,7 +3094,7 @@ int dup_userfaultfd(struct vm_area_struct *vma, struct list_head *fcs)
> struct userfaultfd_ctx *ctx = NULL, *octx;
> struct userfaultfd_fork_ctx *fctx;
>
> - octx = vma->vm_userfaultfd_ctx.ctx;
> + octx = vma->vm_uffd_state.ctx;
> if (!octx)
> return 0;
>
> @@ -3138,7 +3138,7 @@ int dup_userfaultfd(struct vm_area_struct *vma, struct list_head *fcs)
> list_add_tail(&fctx->list, fcs);
> }
>
> - vma->vm_userfaultfd_ctx.ctx = ctx;
> + vma->vm_uffd_state.ctx = ctx;
> return 0;
> }
>
> @@ -3195,11 +3195,11 @@ void dup_userfaultfd_fail(struct list_head *fcs)
> }
>
> void mremap_userfaultfd_prep(struct vm_area_struct *vma,
> - struct vm_userfaultfd_ctx *vm_ctx)
> + struct vm_uffd_state *vm_ctx)
> {
> struct userfaultfd_ctx *ctx;
>
> - ctx = vma->vm_userfaultfd_ctx.ctx;
> + ctx = vma->vm_uffd_state.ctx;
>
> if (!ctx)
> return;
> @@ -3216,7 +3216,7 @@ void mremap_userfaultfd_prep(struct vm_area_struct *vma,
> }
> }
>
> -void mremap_userfaultfd_complete(struct vm_userfaultfd_ctx *vm_ctx,
> +void mremap_userfaultfd_complete(struct vm_uffd_state *vm_ctx,
> unsigned long from, unsigned long to,
> unsigned long len)
> {
> @@ -3236,7 +3236,7 @@ void mremap_userfaultfd_complete(struct vm_userfaultfd_ctx *vm_ctx,
> userfaultfd_event_wait_completion(ctx, &ewq);
> }
>
> -void mremap_userfaultfd_fail(struct vm_userfaultfd_ctx *vm_ctx)
> +void mremap_userfaultfd_fail(struct vm_uffd_state *vm_ctx)
> {
> struct userfaultfd_ctx *ctx = vm_ctx->ctx;
>
> @@ -3255,7 +3255,7 @@ bool userfaultfd_remove(struct vm_area_struct *vma,
> struct userfaultfd_ctx *ctx;
> struct userfaultfd_wait_queue ewq;
>
> - ctx = vma->vm_userfaultfd_ctx.ctx;
> + ctx = vma->vm_uffd_state.ctx;
> if (!ctx || !(ctx->features & UFFD_FEATURE_EVENT_REMOVE))
> return true;
>
> @@ -3293,7 +3293,7 @@ int userfaultfd_unmap_prep(struct vm_area_struct *vma, unsigned long start,
> unsigned long end, struct list_head *unmaps)
> {
> struct userfaultfd_unmap_ctx *unmap_ctx;
> - struct userfaultfd_ctx *ctx = vma->vm_userfaultfd_ctx.ctx;
> + struct userfaultfd_ctx *ctx = vma->vm_uffd_state.ctx;
>
> if (!ctx || !(ctx->features & UFFD_FEATURE_EVENT_UNMAP) ||
> has_unmap_ctx(ctx, unmaps, start, end))
> @@ -3813,7 +3813,7 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
> do {
> cond_resched();
>
> - VM_WARN_ON_ONCE(!!cur->vm_userfaultfd_ctx.ctx ^
> + VM_WARN_ON_ONCE(!!cur->vm_uffd_state.ctx ^
> !!(cur->vm_flags & __VM_UFFD_FLAGS));
>
> /* check not compatible vmas */
> @@ -3867,8 +3867,8 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
> * wouldn't know which one to deliver the userfaults to.
> */
> ret = -EBUSY;
> - if (cur->vm_userfaultfd_ctx.ctx &&
> - cur->vm_userfaultfd_ctx.ctx != ctx)
> + if (cur->vm_uffd_state.ctx &&
> + cur->vm_uffd_state.ctx != ctx)
> goto out_unlock;
>
> /*
> @@ -3877,7 +3877,7 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
> * subsequent mprotect() would then promote stale markers
> * into the other mode. Require an unregister first.
> */
> - if (cur->vm_userfaultfd_ctx.ctx == ctx &&
> + if (cur->vm_uffd_state.ctx == ctx &&
> cur->vm_flags & (VM_UFFD_WP | VM_UFFD_RWP) & ~vm_flags)
> goto out_unlock;
>
> @@ -3985,15 +3985,15 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
> do {
> cond_resched();
>
> - VM_WARN_ON_ONCE(!!cur->vm_userfaultfd_ctx.ctx ^
> + VM_WARN_ON_ONCE(!!cur->vm_uffd_state.ctx ^
> !!(cur->vm_flags & __VM_UFFD_FLAGS));
>
> /*
> * Prevent unregistering through a different userfaultfd than
> * the one used for registration.
> */
> - if (cur->vm_userfaultfd_ctx.ctx &&
> - cur->vm_userfaultfd_ctx.ctx != ctx)
> + if (cur->vm_uffd_state.ctx &&
> + cur->vm_uffd_state.ctx != ctx)
> goto out_unlock;
>
> /*
> @@ -4020,10 +4020,10 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
> cond_resched();
>
> /* VMA not registered with userfaultfd. */
> - if (!vma->vm_userfaultfd_ctx.ctx)
> + if (!vma->vm_uffd_state.ctx)
> goto skip;
>
> - VM_WARN_ON_ONCE(vma->vm_userfaultfd_ctx.ctx != ctx);
> + VM_WARN_ON_ONCE(vma->vm_uffd_state.ctx != ctx);
> VM_WARN_ON_ONCE(!vma_can_userfault(vma, vma->vm_flags, wp_async));
> VM_WARN_ON_ONCE(!(vma->vm_flags & VM_MAYWRITE));
>
> @@ -4041,7 +4041,7 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
> struct userfaultfd_wake_range range;
> range.start = start;
> range.len = vma_end - start;
> - wake_userfault(vma->vm_userfaultfd_ctx.ctx, &range);
> + wake_userfault(vma->vm_uffd_state.ctx, &range);
> }
>
> vma = userfaultfd_clear_vma(&vmi, prev, vma,
> @@ -4382,7 +4382,7 @@ static int userfaultfd_set_mode(struct userfaultfd_ctx *ctx,
> VMA_ITERATOR(vmi, mm, 0);
>
> for_each_vma(vmi, vma) {
> - if (vma->vm_userfaultfd_ctx.ctx == ctx)
> + if (vma->vm_uffd_state.ctx == ctx)
> vma_start_write(vma);
> }
> }
> @@ -4537,12 +4537,12 @@ static inline int userfaultfd_poison(struct userfaultfd_ctx *ctx, unsigned long
>
> bool userfaultfd_wp_async(struct vm_area_struct *vma)
> {
> - return userfaultfd_wp_async_ctx(vma->vm_userfaultfd_ctx.ctx);
> + return userfaultfd_wp_async_ctx(vma->vm_uffd_state.ctx);
> }
>
> bool userfaultfd_rwp_async(struct vm_area_struct *vma)
> {
> - return userfaultfd_rwp_async_ctx(vma->vm_userfaultfd_ctx.ctx);
> + return userfaultfd_rwp_async_ctx(vma->vm_uffd_state.ctx);
> }
>
> static inline unsigned int uffd_ctx_features(__u64 user_features)
> diff --git a/mm/vma.c b/mm/vma.c
> index 35e7a64855fa..f2c65d148498 100644
> --- a/mm/vma.c
> +++ b/mm/vma.c
> @@ -118,7 +118,7 @@ static inline bool is_mergeable_vma(struct vma_merge_struct *vmg, bool merge_nex
> return false;
> if (vma->vm_file != vmg->file)
> return false;
> - if (!is_mergeable_vm_userfaultfd_ctx(vma, vmg->uffd_ctx))
> + if (!is_mergeable_vm_uffd_state(vma, vmg->uffd_ctx))
> return false;
> if (!anon_vma_name_eq(anon_vma_name(vma), vmg->anon_name))
> return false;
> @@ -1837,7 +1837,7 @@ struct vm_area_struct *vma_modify_policy(struct vma_iterator *vmi,
> struct vm_area_struct *vma_modify_flags_uffd(struct vma_iterator *vmi,
> struct vm_area_struct *prev, struct vm_area_struct *vma,
> unsigned long start, unsigned long end,
> - const vma_flags_t *vma_flags, struct vm_userfaultfd_ctx new_ctx,
> + const vma_flags_t *vma_flags, struct vm_uffd_state new_ctx,
> bool give_up_on_oom)
> {
> VMG_VMA_STATE(vmg, vmi, prev, vma, start, end);
> diff --git a/mm/vma.h b/mm/vma.h
> index 024fabe63560..ab23a65750de 100644
> --- a/mm/vma.h
> +++ b/mm/vma.h
> @@ -114,7 +114,7 @@ struct vma_merge_struct {
> struct file *file;
> struct anon_vma *anon_vma;
> struct mempolicy *policy;
> - struct vm_userfaultfd_ctx uffd_ctx;
> + struct vm_uffd_state uffd_ctx;
> struct anon_vma_name *anon_name;
> enum vma_merge_state state;
>
> @@ -349,7 +349,7 @@ static inline void vma_sub_pgoff(struct vm_area_struct *vma, pgoff_t delta)
> .file = vma_->vm_file, \
> .anon_vma = vma_->anon_vma, \
> .policy = vma_policy(vma_), \
> - .uffd_ctx = vma_->vm_userfaultfd_ctx, \
> + .uffd_ctx = vma_->vm_uffd_state, \
> .anon_name = anon_vma_name(vma_), \
> .state = VMA_MERGE_START, \
> }
> @@ -519,7 +519,7 @@ __must_check struct vm_area_struct *vma_modify_policy(struct vma_iterator *vmi,
> __must_check struct vm_area_struct *vma_modify_flags_uffd(struct vma_iterator *vmi,
> struct vm_area_struct *prev, struct vm_area_struct *vma,
> unsigned long start, unsigned long end, const vma_flags_t *vma_flags,
> - struct vm_userfaultfd_ctx new_ctx, bool give_up_on_oom);
> + struct vm_uffd_state new_ctx, bool give_up_on_oom);
>
> __must_check struct vm_area_struct *vma_merge_new_range(struct vma_merge_struct *vmg);
>
> diff --git a/mm/vma_init.c b/mm/vma_init.c
> index baa7e82f47e3..61ddb31318bb 100644
> --- a/mm/vma_init.c
> +++ b/mm/vma_init.c
> @@ -62,8 +62,8 @@ static void vm_area_init_from(const struct vm_area_struct *src,
> * dup_mmap(), but the clone will reinitialize it.
> */
> data_race(memcpy(&dest->shared, &src->shared, sizeof(dest->shared)));
> - memcpy(&dest->vm_userfaultfd_ctx, &src->vm_userfaultfd_ctx,
> - sizeof(dest->vm_userfaultfd_ctx));
> + memcpy(&dest->vm_uffd_state, &src->vm_uffd_state,
> + sizeof(dest->vm_uffd_state));
> #ifdef CONFIG_ANON_VMA_NAME
> dest->anon_name = src->anon_name;
> #endif
> diff --git a/tools/testing/vma/include/dup.h b/tools/testing/vma/include/dup.h
> index 4c58487b764e..1a01c3529d22 100644
> --- a/tools/testing/vma/include/dup.h
> +++ b/tools/testing/vma/include/dup.h
> @@ -634,7 +634,7 @@ struct vm_area_struct {
> */
> struct anon_vma_name *anon_name;
> #endif
> - struct vm_userfaultfd_ctx vm_userfaultfd_ctx;
> + struct vm_uffd_state vm_uffd_state;
> } __randomize_layout;
>
> struct vm_operations_struct {
> diff --git a/tools/testing/vma/include/stubs.h b/tools/testing/vma/include/stubs.h
> index d6136e19a8af..dcd1b1719928 100644
> --- a/tools/testing/vma/include/stubs.h
> +++ b/tools/testing/vma/include/stubs.h
> @@ -33,7 +33,7 @@ struct unmap_desc;
>
> #define ASSERT_EXCLUSIVE_WRITER(x)
>
> -struct vm_userfaultfd_ctx {};
> +struct vm_uffd_state {};
> struct mempolicy {};
> struct mmu_gather {};
> struct mutex {};
> @@ -350,8 +350,8 @@ static inline struct anon_vma_name *anon_vma_name(struct vm_area_struct *vma)
> return NULL;
> }
>
> -static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
> - struct vm_userfaultfd_ctx vm_ctx)
> +static inline bool is_mergeable_vm_uffd_state(struct vm_area_struct *vma,
> + struct vm_uffd_state vm_ctx)
> {
> return true;
> }
>
> --
> 2.53.0
>
--
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 5/6] userfaultfd: decouple fault reason from VMA flags
2026-08-23 12:17 ` [PATCH 5/6] userfaultfd: decouple fault reason from VMA flags Mike Rapoport (Microsoft)
2026-08-24 8:12 ` Muchun Song
2026-08-24 14:46 ` David Hildenbrand (Arm)
@ 2026-08-24 16:28 ` Lorenzo Stoakes (ARM)
2026-08-25 10:37 ` Mike Rapoport
2 siblings, 1 reply; 32+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-08-24 16:28 UTC (permalink / raw)
To: Mike Rapoport (Microsoft)
Cc: Andrew Morton, David Hildenbrand, Baolin Wang, Barry Song,
Dev Jain, Hugh Dickins, Jann Horn, Jason Gunthorpe, John Hubbard,
Jonathan Corbet, Lance Yang, Liam R. Howlett, Masami Hiramatsu,
Mathieu Desnoyers, Michal Hocko, Muchun Song, Nico Pache,
Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, Zi Yan, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
On Sun, Aug 23, 2026 at 03:17:42PM +0300, Mike Rapoport (Microsoft) wrote:
> Introduce enum uffd_reason to define reasons for user faults rather than
> overload VM_UFFD_* VMA flags for that.
>
> Using a dedicated enum makes the code clearer and decoupling the fault
> reason from VMA flags clears the way for moving the uffd mode bits out
> of VMA namespace.
>
> No functional change.
>
> Assisted-by: copilot:claude-opus-4.6
> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> ---
> include/linux/userfaultfd_k.h | 16 ++++++++++++++--
> include/uapi/linux/userfaultfd.h | 6 +++---
> mm/huge_memory.c | 6 +++---
> mm/hugetlb.c | 10 +++++-----
> mm/memory.c | 10 +++++-----
> mm/shmem.c | 4 ++--
> mm/userfaultfd.c | 30 +++++++++++++++---------------
> 7 files changed, 47 insertions(+), 35 deletions(-)
>
> diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
> index 45355bdb4ec7..f401623f315d 100644
> --- a/include/linux/userfaultfd_k.h
> +++ b/include/linux/userfaultfd_k.h
> @@ -9,6 +9,18 @@
> #ifndef _LINUX_USERFAULTFD_K_H
> #define _LINUX_USERFAULTFD_K_H
>
> +#include <linux/bits.h>
> +
> +/* Fault reason #PF handler passes to handle_userfault() */
> +enum uf_reason {
> + USERFAULT_MISSING = BIT(0),
> + USERFAULT_MINOR = BIT(1),
> + USERFAULT_RWP = BIT(2),
> + USERFAULT_WP = BIT(3),
> +};
Hmm your commit message says uffd_reason, uf_reason makes me think of the
character Ulf from House of the Dragon. But not uffd. So as per David let's
rename it :)
I'm also not sure if an enum is the right thing for flag values?
Anything that is parameterised by enum uffd_reason that combines flags will
break any switch statement in there and yada yada.
I wonder if better just as #define's + unsigned long or something?
Or you could do (and this leads to nicer stuff later):
enum uffd_reason {
USERFAULT_MISSING_BIT = 0,
USERFAULT_MINOR_BIT = 1,
USERFAULT_RWP_BIT = 2,
USERFAULT_WP_BIT = 3,
};
#define USERFAULT_MISSING BIT(USERFAULT_MISSING_BIT)
etc.
> +#define USERFAULT_ANY (USERFAULT_MISSING | USERFAULT_MINOR | \
> + USERFAULT_RWP | USERFAULT_WP)
> +
> #ifdef CONFIG_USERFAULTFD
>
> #include <linux/userfaultfd.h> /* linux/include/uapi/linux/userfaultfd.h */
> @@ -82,7 +94,7 @@ struct userfaultfd_ctx {
> struct mm_struct *mm;
> };
>
> -extern vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason);
> +vm_fault_t handle_userfault(struct vm_fault *vmf, enum uf_reason reason);
>
> /* VMA userfaultfd operations */
> struct vm_uffd_ops {
> @@ -333,7 +345,7 @@ static inline bool pte_swp_uffd_any(pte_t pte)
>
> /* mm helpers */
> static inline vm_fault_t handle_userfault(struct vm_fault *vmf,
> - unsigned long reason)
> + enum uf_reason reason)
See above re: enum parameterisation.
> {
> return VM_FAULT_SIGBUS;
> }
> diff --git a/include/uapi/linux/userfaultfd.h b/include/uapi/linux/userfaultfd.h
> index cea11aad6b54..ed2c42d427b9 100644
> --- a/include/uapi/linux/userfaultfd.h
> +++ b/include/uapi/linux/userfaultfd.h
> @@ -168,9 +168,9 @@ struct uffd_msg {
>
> /* flags for UFFD_EVENT_PAGEFAULT */
> #define UFFD_PAGEFAULT_FLAG_WRITE (1<<0) /* If this was a write fault */
> -#define UFFD_PAGEFAULT_FLAG_WP (1<<1) /* If reason is VM_UFFD_WP */
> -#define UFFD_PAGEFAULT_FLAG_MINOR (1<<2) /* If reason is VM_UFFD_MINOR */
> -#define UFFD_PAGEFAULT_FLAG_RWP (1<<3) /* If reason is VM_UFFD_RWP */
> +#define UFFD_PAGEFAULT_FLAG_WP (1<<1) /* If reason is uffd-wp */
> +#define UFFD_PAGEFAULT_FLAG_MINOR (1<<2) /* If reason is uffd-minor */
> +#define UFFD_PAGEFAULT_FLAG_RWP (1<<3) /* If reason is uffd-rwp */
Is it worth retaining the same bit indexes as the reasons?
Reasons:
Bit number
MINOR 0
RWP 1
WP 2
Page fault flags:
Bit number
MINOR 2
RWP 3
WP 1
See below for some actual practical justification...
>
> struct uffdio_api {
> /* userland asks for an API number and the features to enable */
> diff --git a/mm/huge_memory.c b/mm/huge_memory.c
> index ced400f72d43..46d8497ce90e 100644
> --- a/mm/huge_memory.c
> +++ b/mm/huge_memory.c
> @@ -1410,7 +1410,7 @@ static vm_fault_t __do_huge_pmd_anonymous_page(struct vm_fault *vmf)
> spin_unlock(vmf->ptl);
> folio_put(folio);
> pte_free(vma->vm_mm, pgtable);
> - ret = handle_userfault(vmf, VM_UFFD_MISSING);
> + ret = handle_userfault(vmf, USERFAULT_MISSING);
> VM_BUG_ON(ret & VM_FAULT_FALLBACK);
> return ret;
> }
> @@ -1556,7 +1556,7 @@ vm_fault_t do_huge_pmd_anonymous_page(struct vm_fault *vmf)
> } else if (userfaultfd_missing(vma)) {
> spin_unlock(vmf->ptl);
> pte_free(vma->vm_mm, pgtable);
> - ret = handle_userfault(vmf, VM_UFFD_MISSING);
> + ret = handle_userfault(vmf, USERFAULT_MISSING);
> VM_BUG_ON(ret & VM_FAULT_FALLBACK);
> } else {
> set_huge_zero_folio(pgtable, vma->vm_mm, vma,
> @@ -2252,7 +2252,7 @@ vm_fault_t do_huge_pmd_uffd_rwp(struct vm_fault *vmf)
> pmd_t pmd;
>
> if (!userfaultfd_rwp_async(vma))
> - return handle_userfault(vmf, VM_UFFD_RWP);
> + return handle_userfault(vmf, USERFAULT_RWP);
>
> vmf->ptl = pmd_lock(vma->vm_mm, vmf->pmd);
> if (unlikely(!pmd_same(pmdp_get(vmf->pmd), vmf->orig_pmd))) {
> diff --git a/mm/hugetlb.c b/mm/hugetlb.c
> index 73d65644be13..5e2ed80c1938 100644
> --- a/mm/hugetlb.c
> +++ b/mm/hugetlb.c
> @@ -5728,7 +5728,7 @@ int hugetlb_add_to_page_cache(struct folio *folio, struct address_space *mapping
>
> static inline vm_fault_t hugetlb_handle_userfault(struct vm_fault *vmf,
> struct address_space *mapping,
> - unsigned long reason)
> + enum uf_reason reason)
> {
> u32 hash;
>
> @@ -5821,7 +5821,7 @@ static vm_fault_t hugetlb_no_page(struct address_space *mapping,
> }
>
> return hugetlb_handle_userfault(vmf, mapping,
> - VM_UFFD_MISSING);
> + USERFAULT_MISSING);
> }
>
> if (!(vma->vm_flags & VM_MAYSHARE)) {
> @@ -5897,7 +5897,7 @@ static vm_fault_t hugetlb_no_page(struct address_space *mapping,
> goto out;
> }
> return hugetlb_handle_userfault(vmf, mapping,
> - VM_UFFD_MINOR);
> + USERFAULT_MINOR);
> }
> }
>
> @@ -6120,7 +6120,7 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
>
> /* Sync: drop hugetlb locks before blocking in handle_userfault() */
> if (!userfaultfd_rwp_async(vma))
> - return hugetlb_handle_userfault(&vmf, mapping, VM_UFFD_RWP);
> + return hugetlb_handle_userfault(&vmf, mapping, USERFAULT_RWP);
>
> ptl = huge_pte_lock(h, mm, vmf.pte);
> pte = huge_ptep_get(mm, vmf.address, vmf.pte);
> @@ -6177,7 +6177,7 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
> spin_unlock(vmf.ptl);
> hugetlb_vma_unlock_read(vma);
> mutex_unlock(&hugetlb_fault_mutex_table[hash]);
> - return handle_userfault(&vmf, VM_UFFD_WP);
> + return handle_userfault(&vmf, USERFAULT_WP);
> }
>
> vmf.orig_pte = huge_pte_clear_uffd(vmf.orig_pte);
> diff --git a/mm/memory.c b/mm/memory.c
> index c54943302553..1a9b41704b0c 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -4389,7 +4389,7 @@ static vm_fault_t do_wp_page(struct vm_fault *vmf)
> if (userfaultfd_pte_wp(vma, ptep_get(vmf->pte))) {
> if (!userfaultfd_wp_async(vma)) {
> pte_unmap_unlock(vmf->pte, vmf->ptl);
> - return handle_userfault(vmf, VM_UFFD_WP);
> + return handle_userfault(vmf, USERFAULT_WP);
> }
>
> /*
> @@ -5463,7 +5463,7 @@ static vm_fault_t do_anonymous_page(struct vm_fault *vmf)
> /* Deliver the page fault to userland, check inside PT lock */
> if (userfaultfd_missing(vma)) {
> pte_unmap_unlock(vmf->pte, vmf->ptl);
> - return handle_userfault(vmf, VM_UFFD_MISSING);
> + return handle_userfault(vmf, USERFAULT_MISSING);
> }
> if (vmf_orig_pte_uffd_wp(vmf))
> entry = pte_mkuffd(entry);
> @@ -5514,7 +5514,7 @@ static vm_fault_t do_anonymous_page(struct vm_fault *vmf)
> if (userfaultfd_missing(vma)) {
> pte_unmap_unlock(vmf->pte, vmf->ptl);
> folio_put(folio);
> - return handle_userfault(vmf, VM_UFFD_MISSING);
> + return handle_userfault(vmf, USERFAULT_MISSING);
> }
> map_anon_folio_pte_pf(folio, vmf->pte, vma, addr,
> vmf_orig_pte_uffd_wp(vmf));
> @@ -6263,7 +6263,7 @@ static vm_fault_t do_uffd_rwp(struct vm_fault *vmf)
> if (!userfaultfd_rwp_async(vmf->vma)) {
> /* Sync mode: unmap PTE and deliver to userfaultfd handler */
> pte_unmap(vmf->pte);
> - return handle_userfault(vmf, VM_UFFD_RWP);
> + return handle_userfault(vmf, USERFAULT_RWP);
> }
>
> spin_lock(vmf->ptl);
> @@ -6398,7 +6398,7 @@ static inline vm_fault_t wp_huge_pmd(struct vm_fault *vmf)
> userfaultfd_huge_pmd_wp(vma, vmf->orig_pmd)) {
> if (userfaultfd_wp_async(vmf->vma))
> goto split;
> - return handle_userfault(vmf, VM_UFFD_WP);
> + return handle_userfault(vmf, USERFAULT_WP);
> }
> return do_huge_pmd_wp_page(vmf);
> }
> diff --git a/mm/shmem.c b/mm/shmem.c
> index 599665a3d6e7..2138a4e6b549 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -2453,7 +2453,7 @@ static int shmem_get_folio_gfp(struct inode *inode, pgoff_t index,
> if (folio && vma && userfaultfd_minor(vma)) {
> if (!xa_is_value(folio))
> folio_put(folio);
> - *fault_type = handle_userfault(vmf, VM_UFFD_MINOR);
> + *fault_type = handle_userfault(vmf, USERFAULT_MINOR);
> return 0;
> }
>
> @@ -2502,7 +2502,7 @@ static int shmem_get_folio_gfp(struct inode *inode, pgoff_t index,
> */
>
> if (vma && userfaultfd_missing(vma)) {
> - *fault_type = handle_userfault(vmf, VM_UFFD_MISSING);
> + *fault_type = handle_userfault(vmf, USERFAULT_MISSING);
> return 0;
> }
>
> diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
> index 119304547230..83587d34b189 100644
> --- a/mm/userfaultfd.c
> +++ b/mm/userfaultfd.c
> @@ -2607,7 +2607,7 @@ static inline void msg_init(struct uffd_msg *msg)
> static inline struct uffd_msg userfault_msg(unsigned long address,
> unsigned long real_address,
> unsigned int flags,
> - unsigned long reason,
> + enum uf_reason reason,
> unsigned int features)
> {
> struct uffd_msg msg;
> @@ -2629,11 +2629,11 @@ static inline struct uffd_msg userfault_msg(unsigned long address,
> */
> if (flags & FAULT_FLAG_WRITE)
> msg.arg.pagefault.flags |= UFFD_PAGEFAULT_FLAG_WRITE;
> - if (reason & VM_UFFD_WP)
> + if (reason & USERFAULT_WP)
> msg.arg.pagefault.flags |= UFFD_PAGEFAULT_FLAG_WP;
> - if (reason & VM_UFFD_RWP)
> + if (reason & USERFAULT_RWP)
> msg.arg.pagefault.flags |= UFFD_PAGEFAULT_FLAG_RWP;
> - if (reason & VM_UFFD_MINOR)
> + if (reason & USERFAULT_MINOR)
> msg.arg.pagefault.flags |= UFFD_PAGEFAULT_FLAG_MINOR;
With matching flags and unsigned long you could do
msg.arg.pagefault.flags |= reason;
I think?
> if (features & UFFD_FEATURE_THREAD_ID)
> msg.arg.pagefault.feat.ptid = task_pid_vnr(current);
> @@ -2647,7 +2647,7 @@ static inline struct uffd_msg userfault_msg(unsigned long address,
> */
> static inline bool userfaultfd_huge_must_wait(struct userfaultfd_ctx *ctx,
> struct vm_fault *vmf,
> - unsigned long reason)
> + enum uf_reason reason)
> {
> struct vm_area_struct *vma = vmf->vma;
> pte_t *ptep, pte;
> @@ -2684,13 +2684,13 @@ static inline bool userfaultfd_huge_must_wait(struct userfaultfd_ctx *ctx,
> * If VMA has UFFD WP faults enabled and WP fault, wait for userspace to
> * resolve the fault.
> */
> - if (!huge_pte_write(pte) && (reason & VM_UFFD_WP))
> + if (!huge_pte_write(pte) && (reason & USERFAULT_WP))
> return true;
> /*
> * PTE is still RW-protected (protnone with uffd bit), wait for
> * resolution. Plain PROT_NONE without the marker is not an RWP fault.
> */
> - if (pte_protnone(pte) && huge_pte_uffd(pte) && (reason & VM_UFFD_RWP))
> + if (pte_protnone(pte) && huge_pte_uffd(pte) && (reason & USERFAULT_RWP))
> return true;
>
> return false;
> @@ -2698,7 +2698,7 @@ static inline bool userfaultfd_huge_must_wait(struct userfaultfd_ctx *ctx,
> #else
> static inline bool userfaultfd_huge_must_wait(struct userfaultfd_ctx *ctx,
> struct vm_fault *vmf,
> - unsigned long reason)
> + enum uf_reason reason)
> {
> /* Should never get here. */
> VM_WARN_ON_ONCE(1);
> @@ -2715,7 +2715,7 @@ static inline bool userfaultfd_huge_must_wait(struct userfaultfd_ctx *ctx,
> */
> static inline bool userfaultfd_must_wait(struct userfaultfd_ctx *ctx,
> struct vm_fault *vmf,
> - unsigned long reason)
> + enum uf_reason reason)
> {
> struct mm_struct *mm = ctx->mm;
> unsigned long address = vmf->address;
> @@ -2753,10 +2753,10 @@ static inline bool userfaultfd_must_wait(struct userfaultfd_ctx *ctx,
> return false;
>
> if (pmd_trans_huge(_pmd)) {
> - if (!pmd_write(_pmd) && (reason & VM_UFFD_WP))
> + if (!pmd_write(_pmd) && (reason & USERFAULT_WP))
> return true;
> if (pmd_protnone(_pmd) && pmd_uffd(_pmd) &&
> - (reason & VM_UFFD_RWP))
> + (reason & USERFAULT_RWP))
> return true;
> return false;
> }
> @@ -2793,14 +2793,14 @@ static inline bool userfaultfd_must_wait(struct userfaultfd_ctx *ctx,
> * If VMA has UFFD WP faults enabled and WP fault, wait for userspace to
> * resolve the fault.
> */
> - if (!pte_write(ptent) && (reason & VM_UFFD_WP))
> + if (!pte_write(ptent) && (reason & USERFAULT_WP))
I wonder if you could actually
You do this quite a lot and they read a bit horribly with the && and & on the
same sight-line. With the changes to the enum proposed above you could do:
if (!pte_write(ptent) && test_bit(reason, USERFAULT_WP_BIT))
> goto out;
> /*
> * PTE is still RW-protected (protnone with uffd bit), wait for
> * userspace to resolve. Plain PROT_NONE without the marker is not
> * an RWP fault.
> */
> - if (pte_protnone(ptent) && pte_uffd(ptent) && (reason & VM_UFFD_RWP))
> + if (pte_protnone(ptent) && pte_uffd(ptent) && (reason & USERFAULT_RWP))
> goto out;
>
> ret = false;
> @@ -2835,7 +2835,7 @@ static inline unsigned int userfaultfd_get_blocking_state(unsigned int flags)
> * fatal_signal_pending()s, and the mmap_lock must be released before
> * returning it.
> */
> -vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason)
> +vm_fault_t handle_userfault(struct vm_fault *vmf, enum uf_reason reason)
Hmm what was the 'reason' here before? The flags? Maybe more reason (no pun
intended) to keep the values the same?
> {
> struct vm_area_struct *vma = vmf->vma;
> struct mm_struct *mm = vma->vm_mm;
> @@ -2861,7 +2861,7 @@ vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason)
> VM_WARN_ON_ONCE(ctx->mm != mm);
>
> /* Any unrecognized flag is a bug. */
> - VM_WARN_ON_ONCE(reason & ~__VM_UFFD_FLAGS);
> + VM_WARN_ON_ONCE(reason & ~USERFAULT_ANY);
> /* 0 or > 1 flags set is a bug; we expect exactly 1. */
> VM_WARN_ON_ONCE(!reason || (reason & (reason - 1)));
>
>
> --
> 2.53.0
>
--
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 1/6] mm/gup: move gup_can_follow_protnone() to gup.c
2026-08-23 12:17 ` [PATCH 1/6] mm/gup: move gup_can_follow_protnone() to gup.c Mike Rapoport (Microsoft)
` (2 preceding siblings ...)
2026-08-24 14:59 ` Lorenzo Stoakes (ARM)
@ 2026-08-25 2:03 ` Zi Yan
3 siblings, 0 replies; 32+ messages in thread
From: Zi Yan @ 2026-08-25 2:03 UTC (permalink / raw)
To: Mike Rapoport (Microsoft), Andrew Morton, David Hildenbrand
Cc: Baolin Wang, Barry Song, Dev Jain, Hugh Dickins, Jann Horn,
Jason Gunthorpe, John Hubbard, Jonathan Corbet, Lance Yang,
Liam R. Howlett, Lorenzo Stoakes, Masami Hiramatsu,
Mathieu Desnoyers, Michal Hocko, Muchun Song, Nico Pache,
Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
On Sun Aug 23, 2026 at 8:17 AM EDT, Mike Rapoport (Microsoft) wrote:
> gup_can_follow_protnone() is defined in include/linux/mm.h but only used
> by mm/gup.c.
>
> First, there is no reason to have it in already gigantic header.
>
> Next, the upcoming refactoring of userfaultfd flags will make
> gup_can_follow_protnone() depend on userfaultfd_k.h which would cause a
> cyclic header dependency.
>
> Move gup_can_follow_protnone() to mm/gup.c.
>
> No functional change.
>
> Assisted-by: copilot:claude-opus-5
> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> ---
> include/linux/mm.h | 38 --------------------------------------
> mm/gup.c | 38 ++++++++++++++++++++++++++++++++++++++
> 2 files changed, 38 insertions(+), 38 deletions(-)
>
LGTM.
Reviewed-by: Zi Yan <ziy@nvidia.com>
--
Best Regards,
Yan, Zi
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 2/6] userfaultfd: constify VMA parameter of userfaultfd_*() helpers
2026-08-23 12:17 ` [PATCH 2/6] userfaultfd: constify VMA parameter of userfaultfd_*() helpers Mike Rapoport (Microsoft)
2026-08-23 21:03 ` Barry Song
2026-08-24 15:03 ` Lorenzo Stoakes (ARM)
@ 2026-08-25 2:03 ` Zi Yan
2 siblings, 0 replies; 32+ messages in thread
From: Zi Yan @ 2026-08-25 2:03 UTC (permalink / raw)
To: Mike Rapoport (Microsoft), Andrew Morton, David Hildenbrand
Cc: Baolin Wang, Barry Song, Dev Jain, Hugh Dickins, Jann Horn,
Jason Gunthorpe, John Hubbard, Jonathan Corbet, Lance Yang,
Liam R. Howlett, Lorenzo Stoakes, Masami Hiramatsu,
Mathieu Desnoyers, Michal Hocko, Muchun Song, Nico Pache,
Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
On Sun Aug 23, 2026 at 8:17 AM EDT, Mike Rapoport (Microsoft) wrote:
> userfaultfd_{missing,wp,minor,rwp}() and userfaultfd_protected() only
> read the VMA.
>
> Make their vma parameter const.
>
> No functional change.
>
> Assisted-by: copilot:claude-opus-5
> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> ---
> include/linux/userfaultfd_k.h | 20 ++++++++++----------
> 1 file changed, 10 insertions(+), 10 deletions(-)
>
LGTM.
Reviewed-by: Zi Yan <ziy@nvidia.com>
--
Best Regards,
Yan, Zi
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 1/6] mm/gup: move gup_can_follow_protnone() to gup.c
2026-08-24 14:42 ` David Hildenbrand (Arm)
@ 2026-08-25 10:10 ` Mike Rapoport
0 siblings, 0 replies; 32+ messages in thread
From: Mike Rapoport @ 2026-08-25 10:10 UTC (permalink / raw)
To: David Hildenbrand (Arm)
Cc: Andrew Morton, Baolin Wang, Barry Song, Dev Jain, Hugh Dickins,
Jann Horn, Jason Gunthorpe, John Hubbard, Jonathan Corbet,
Lance Yang, Liam R. Howlett, Lorenzo Stoakes, Masami Hiramatsu,
Mathieu Desnoyers, Michal Hocko, Muchun Song, Nico Pache,
Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, Zi Yan, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
On Mon, Aug 24, 2026 at 04:42:56PM +0200, David Hildenbrand (Arm) wrote:
> On 8/23/26 14:17, Mike Rapoport (Microsoft) wrote:
> > gup_can_follow_protnone() is defined in include/linux/mm.h but only used
> > by mm/gup.c.
> >
> > First, there is no reason to have it in already gigantic header.
>
> Once upon a time there was a user in mm/huge_memory.c, in a beautifully named
> function called follow_trans_huge_pmd().
>
> >
> > Next, the upcoming refactoring of userfaultfd flags will make
> > gup_can_follow_protnone() depend on userfaultfd_k.h which would cause a
> > cyclic header dependency.
> >
> > Move gup_can_follow_protnone() to mm/gup.c.
> >
> > No functional change.
> >
> > Assisted-by: copilot:claude-opus-5
> > Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> > ---
>
>
> [...]
>
> > typedef int (*pte_fn_t)(pte_t *pte, unsigned long addr, void *data);
> > extern int apply_to_page_range(struct mm_struct *mm, unsigned long address,
> > unsigned long size, pte_fn_t fn, void *data);
> > diff --git a/mm/gup.c b/mm/gup.c
> > index eb898ea1ee22..500e2aa99e48 100644
> > --- a/mm/gup.c
> > +++ b/mm/gup.c
> > @@ -633,6 +633,44 @@ static struct page *no_page_table(struct vm_area_struct *vma,
> > return NULL;
> > }
> >
> > +/*
> > + * Indicates whether GUP can follow a PROT_NONE mapped page, or whether
> > + * a (NUMA hinting or userfaultfd RWP) fault is required.
> > + */
> > +static inline bool gup_can_follow_protnone(const struct vm_area_struct *vma,
> > + unsigned int flags)
>
> While at it, could switch to double-tab here.
Ok.
> Acked-by: David Hildenbrand (Arm) <david@kernel.org>
>
> --
> Cheers,
>
> David
--
Sincerely yours,
Mike.
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 5/6] userfaultfd: decouple fault reason from VMA flags
2026-08-24 16:28 ` Lorenzo Stoakes (ARM)
@ 2026-08-25 10:37 ` Mike Rapoport
2026-08-25 11:08 ` David Hildenbrand (Arm)
0 siblings, 1 reply; 32+ messages in thread
From: Mike Rapoport @ 2026-08-25 10:37 UTC (permalink / raw)
To: Lorenzo Stoakes (ARM)
Cc: Andrew Morton, David Hildenbrand, Baolin Wang, Barry Song,
Dev Jain, Hugh Dickins, Jann Horn, Jason Gunthorpe, John Hubbard,
Jonathan Corbet, Lance Yang, Liam R. Howlett, Masami Hiramatsu,
Mathieu Desnoyers, Michal Hocko, Muchun Song, Nico Pache,
Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, Zi Yan, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
On Mon, Aug 24, 2026 at 05:28:29PM +0100, Lorenzo Stoakes (ARM) wrote:
> On Sun, Aug 23, 2026 at 03:17:42PM +0300, Mike Rapoport (Microsoft) wrote:
> > Introduce enum uffd_reason to define reasons for user faults rather than
> > overload VM_UFFD_* VMA flags for that.
> >
> > Using a dedicated enum makes the code clearer and decoupling the fault
> > reason from VMA flags clears the way for moving the uffd mode bits out
> > of VMA namespace.
> >
> > No functional change.
> >
> > Assisted-by: copilot:claude-opus-4.6
> > Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> > ---
> > include/linux/userfaultfd_k.h | 16 ++++++++++++++--
> > include/uapi/linux/userfaultfd.h | 6 +++---
> > mm/huge_memory.c | 6 +++---
> > mm/hugetlb.c | 10 +++++-----
> > mm/memory.c | 10 +++++-----
> > mm/shmem.c | 4 ++--
> > mm/userfaultfd.c | 30 +++++++++++++++---------------
> > 7 files changed, 47 insertions(+), 35 deletions(-)
> >
> > diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
> > index 45355bdb4ec7..f401623f315d 100644
> > --- a/include/linux/userfaultfd_k.h
> > +++ b/include/linux/userfaultfd_k.h
> > @@ -9,6 +9,18 @@
> > #ifndef _LINUX_USERFAULTFD_K_H
> > #define _LINUX_USERFAULTFD_K_H
> >
> > +#include <linux/bits.h>
> > +
> > +/* Fault reason #PF handler passes to handle_userfault() */
> > +enum uf_reason {
> > + USERFAULT_MISSING = BIT(0),
> > + USERFAULT_MINOR = BIT(1),
> > + USERFAULT_RWP = BIT(2),
> > + USERFAULT_WP = BIT(3),
> > +};
>
> Hmm your commit message says uffd_reason, uf_reason makes me think of the
> character Ulf from House of the Dragon. But not uffd. So as per David let's
> rename it :)
>
> I'm also not sure if an enum is the right thing for flag values?
I'll ask LLM why it chose it :)
> Anything that is parameterised by enum uffd_reason that combines flags will
> break any switch statement in there and yada yada.
>
> I wonder if better just as #define's + unsigned long or something?
>
> Or you could do (and this leads to nicer stuff later):
>
> enum uffd_reason {
> USERFAULT_MISSING_BIT = 0,
> USERFAULT_MINOR_BIT = 1,
> USERFAULT_RWP_BIT = 2,
> USERFAULT_WP_BIT = 3,
> };
>
> #define USERFAULT_MISSING BIT(USERFAULT_MISSING_BIT)
> etc.
Looks over-engineered to me tbh, if we drop an enum, I'd just
#define FLAG (1 << SHIFT)
and call it a day.
Also see below about aligning with uABI flags.
> > @@ -168,9 +168,9 @@ struct uffd_msg {
> >
> > /* flags for UFFD_EVENT_PAGEFAULT */
> > #define UFFD_PAGEFAULT_FLAG_WRITE (1<<0) /* If this was a write fault */
> > -#define UFFD_PAGEFAULT_FLAG_WP (1<<1) /* If reason is VM_UFFD_WP */
> > -#define UFFD_PAGEFAULT_FLAG_MINOR (1<<2) /* If reason is VM_UFFD_MINOR */
> > -#define UFFD_PAGEFAULT_FLAG_RWP (1<<3) /* If reason is VM_UFFD_RWP */
> > +#define UFFD_PAGEFAULT_FLAG_WP (1<<1) /* If reason is uffd-wp */
> > +#define UFFD_PAGEFAULT_FLAG_MINOR (1<<2) /* If reason is uffd-minor */
> > +#define UFFD_PAGEFAULT_FLAG_RWP (1<<3) /* If reason is uffd-rwp */
>
> Is it worth retaining the same bit indexes as the reasons?
>
> Reasons:
>
> Bit number
> MINOR 0
> RWP 1
> WP 2
>
> Page fault flags:
>
> Bit number
> MINOR 2
> RWP 3
> WP 1
If we go this way, than it must be
#define USERFAULT_MINOR UFFD_PAGEFAULT_FLAG_MINOR
so we won't need to keep them in sync explicitly.
With a caveat of USERFAULT_MISSING that is expressed as "no flags in
uffd_msg" :)
> > @@ -2607,7 +2607,7 @@ static inline void msg_init(struct uffd_msg *msg)
> > static inline struct uffd_msg userfault_msg(unsigned long address,
> > unsigned long real_address,
> > unsigned int flags,
> > - unsigned long reason,
> > + enum uf_reason reason,
> > unsigned int features)
> > {
> > struct uffd_msg msg;
> > @@ -2629,11 +2629,11 @@ static inline struct uffd_msg userfault_msg(unsigned long address,
> > */
> > if (flags & FAULT_FLAG_WRITE)
> > msg.arg.pagefault.flags |= UFFD_PAGEFAULT_FLAG_WRITE;
> > - if (reason & VM_UFFD_WP)
> > + if (reason & USERFAULT_WP)
> > msg.arg.pagefault.flags |= UFFD_PAGEFAULT_FLAG_WP;
> > - if (reason & VM_UFFD_RWP)
> > + if (reason & USERFAULT_RWP)
> > msg.arg.pagefault.flags |= UFFD_PAGEFAULT_FLAG_RWP;
> > - if (reason & VM_UFFD_MINOR)
> > + if (reason & USERFAULT_MINOR)
> > msg.arg.pagefault.flags |= UFFD_PAGEFAULT_FLAG_MINOR;
>
> With matching flags and unsigned long you could do
>
> msg.arg.pagefault.flags |= reason;
>
> I think?
Almost:
msg.arg.pagefault.flags |= (reason & ~USERFAULT_MISSING);
And define USERFAULT_MISSING as (1 << 0) with a comment why it's fine.
I don't feel strongly about it, but my preference is to define reason flags
independently of UFFD_PAGEFAULT_FLAGs and keep the ifs here.
> > @@ -2793,14 +2793,14 @@ static inline bool userfaultfd_must_wait(struct userfaultfd_ctx *ctx,
> > * If VMA has UFFD WP faults enabled and WP fault, wait for userspace to
> > * resolve the fault.
> > */
> > - if (!pte_write(ptent) && (reason & VM_UFFD_WP))
> > + if (!pte_write(ptent) && (reason & USERFAULT_WP))
>
> I wonder if you could actually
>
> You do this quite a lot and they read a bit horribly with the && and & on the
> same sight-line. With the changes to the enum proposed above you could do:
>
> if (!pte_write(ptent) && test_bit(reason, USERFAULT_WP_BIT))
I find && and & perfectly readable and adding _BIT defines looks really
excessive to me.
> > @@ -2835,7 +2835,7 @@ static inline unsigned int userfaultfd_get_blocking_state(unsigned int flags)
> > * fatal_signal_pending()s, and the mmap_lock must be released before
> > * returning it.
> > */
> > -vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason)
> > +vm_fault_t handle_userfault(struct vm_fault *vmf, enum uf_reason reason)
>
> Hmm what was the 'reason' here before? The flags? Maybe more reason (no pun
> intended) to keep the values the same?
The 'reason' before was a VM_UFFD_SOMETHING, we really can't keep the
values the same, but we surely can keep it unsigned long.
> --
> Cheers, Lorenzo
--
Sincerely yours,
Mike.
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 5/6] userfaultfd: decouple fault reason from VMA flags
2026-08-25 10:37 ` Mike Rapoport
@ 2026-08-25 11:08 ` David Hildenbrand (Arm)
2026-08-25 11:38 ` Lorenzo Stoakes (ARM)
0 siblings, 1 reply; 32+ messages in thread
From: David Hildenbrand (Arm) @ 2026-08-25 11:08 UTC (permalink / raw)
To: Mike Rapoport, Lorenzo Stoakes (ARM)
Cc: Andrew Morton, Baolin Wang, Barry Song, Dev Jain, Hugh Dickins,
Jann Horn, Jason Gunthorpe, John Hubbard, Jonathan Corbet,
Lance Yang, Liam R. Howlett, Masami Hiramatsu, Mathieu Desnoyers,
Michal Hocko, Muchun Song, Nico Pache, Oscar Salvador,
Pedro Falcato, Peter Xu, Ryan Roberts, Shakeel Butt, Shuah Khan,
Steven Rostedt, Suren Baghdasaryan, Usama Arif, Vlastimil Babka,
Zi Yan, linux-doc, linux-fsdevel, linux-kernel, linux-mm,
linux-trace-kernel
>>> @@ -2793,14 +2793,14 @@ static inline bool userfaultfd_must_wait(struct userfaultfd_ctx *ctx,
>>> * If VMA has UFFD WP faults enabled and WP fault, wait for userspace to
>>> * resolve the fault.
>>> */
>>> - if (!pte_write(ptent) && (reason & VM_UFFD_WP))
>>> + if (!pte_write(ptent) && (reason & USERFAULT_WP))
>>
>> I wonder if you could actually
>>
>> You do this quite a lot and they read a bit horribly with the && and & on the
>> same sight-line. With the changes to the enum proposed above you could do:
>>
>> if (!pte_write(ptent) && test_bit(reason, USERFAULT_WP_BIT))
>
> I find && and & perfectly readable and adding _BIT defines looks really
> excessive to me.
Yeah, that looks alright to me as well.
--
Cheers,
David
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 3/6] userfaultfd: use userfaultfd_*() helpers instead of open coded flag tests
2026-08-24 15:10 ` Lorenzo Stoakes (ARM)
@ 2026-08-25 11:19 ` Mike Rapoport
2026-08-25 11:26 ` Lorenzo Stoakes (ARM)
0 siblings, 1 reply; 32+ messages in thread
From: Mike Rapoport @ 2026-08-25 11:19 UTC (permalink / raw)
To: Lorenzo Stoakes (ARM)
Cc: Andrew Morton, David Hildenbrand, Baolin Wang, Barry Song,
Dev Jain, Hugh Dickins, Jann Horn, Jason Gunthorpe, John Hubbard,
Jonathan Corbet, Lance Yang, Liam R. Howlett, Masami Hiramatsu,
Mathieu Desnoyers, Michal Hocko, Muchun Song, Nico Pache,
Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, Zi Yan, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
On Mon, Aug 24, 2026 at 04:10:51PM +0100, Lorenzo Stoakes (ARM) wrote:
> On Sun, Aug 23, 2026 at 03:17:40PM +0300, Mike Rapoport (Microsoft) wrote:
> > Move userfaultfd_{missing,wp,minor,rwp}() and userfaultfd_protected()
> > ahead of uffd_disable_huge_pmd_share() and uffd_disable_fault_around()
> > and make the latter two use the helpers rather than open coded VMA flag
> > masks.
> >
> > Convert open coded VMA flag test in mfill_get_vma() to userfaultfd_wp()
> > as well.
>
> It'd be better to do the moves and the reworks separately. We don't have a limit
> on patch count :)
>
> >
> > With every user of the per-VMA uffd modes going through the helpers,
> > their underlying representation can be changed in the next step.
> >
> > No functional change.
>
> There is a functional change, or at least seems to be, see below.
>
> >
> > Assisted-by: copilot:claude-opus-5
> > Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> > ---
> > include/linux/userfaultfd_k.h | 70 +++++++++++++++++++++----------------------
> > mm/userfaultfd.c | 2 +-
> > 2 files changed, 35 insertions(+), 37 deletions(-)
> >
> > diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
> > index 3396d270b159..d8262e3dc134 100644
> > --- a/include/linux/userfaultfd_k.h
> > +++ b/include/linux/userfaultfd_k.h
> > @@ -168,42 +168,6 @@ static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
> > return vma->vm_userfaultfd_ctx.ctx == vm_ctx.ctx;
> > }
> >
> > -/*
> > - * Never enable huge pmd sharing on some uffd registered vmas:
> > - *
> > - * - VM_UFFD_WP and VM_UFFD_RWP VMAs, because the write protect / access
> > - * tracking information is per pgtable entry.
> > - *
> > - * - VM_UFFD_MINOR VMAs, because otherwise we would never get minor faults for
> > - * VMAs which share huge pmds. (If you have two mappings to the same
> > - * underlying pages, and fault in the non-UFFD-registered one with a write,
> > - * with huge pmd sharing this would *also* setup the second UFFD-registered
> > - * mapping, and we'd not get minor faults.)
> > - */
> > -static inline bool uffd_disable_huge_pmd_share(struct vm_area_struct *vma)
> > -{
> > - return vma_test_any_mask(vma,
> > - mk_vma_flags_from_masks(VMA_UFFD_WP, VMA_UFFD_RWP,
> > - VMA_UFFD_MINOR));
> > -}
> > -
> > -/*
> > - * Don't do fault around for WP, RWP or MINOR registered uffd range. For
> > - * MINOR registered range, fault around will be a total disaster and ptes can
> > - * be installed without notifications; for WP it should mostly be fine as long
> > - * as the fault around checks for pte_none() before the installation, however
> > - * to be super safe we just forbid it; for RWP, pre-faulted neighbours would
> > - * be indistinguishable from accessed pages in PAGEMAP_SCAN (PAGE_IS_ACCESSED)
> > - * and pollute the tracked working set, so each page must be populated by its
> > - * own fault.
> > - */
> > -static inline bool uffd_disable_fault_around(struct vm_area_struct *vma)
> > -{
> > - return vma_test_any_mask(vma,
> > - mk_vma_flags_from_masks(VMA_UFFD_WP, VMA_UFFD_RWP,
> > - VMA_UFFD_MINOR));
> > -}
> > -
> > static inline bool userfaultfd_missing(const struct vm_area_struct *vma)
> > {
> > return vma_test_any_mask(vma, VMA_UFFD_MISSING);
> > @@ -235,6 +199,40 @@ static inline bool userfaultfd_protected(const struct vm_area_struct *vma)
> > return userfaultfd_wp(vma) || userfaultfd_rwp(vma);
> > }
> >
> > +/*
> > + * Never enable huge pmd sharing on some uffd registered vmas:
> > + *
> > + * - uffd-WP and uffd-RWP VMAs, because the write protect / access tracking
> > + * information is per pgtable entry.
> > + *
> > + * - uffd-MINOR VMAs, because otherwise we would never get minor faults for
> > + * VMAs which share huge pmds. (If you have two mappings to the same
> > + * underlying pages, and fault in the non-UFFD-registered one with a write,
> > + * with huge pmd sharing this would *also* setup the second UFFD-registered
> > + * mapping, and we'd not get minor faults.)
> > + */
> > +static inline bool uffd_disable_huge_pmd_share(struct vm_area_struct *vma)
> > +{
> > + return userfaultfd_minor(vma) || userfaultfd_wp(vma) ||
> > + userfaultfd_rwp(vma);
> > +}
> > +
> > +/*
> > + * Don't do fault around for WP, RWP or MINOR registered uffd range. For
> > + * MINOR registered range, fault around will be a total disaster and ptes can
> > + * be installed without notifications; for WP it should mostly be fine as long
> > + * as the fault around checks for pte_none() before the installation, however
> > + * to be super safe we just forbid it; for RWP, pre-faulted neighbours would
> > + * be indistinguishable from accessed pages in PAGEMAP_SCAN (PAGE_IS_ACCESSED)
> > + * and pollute the tracked working set, so each page must be populated by its
> > + * own fault.
> > + */
> > +static inline bool uffd_disable_fault_around(struct vm_area_struct *vma)
> > +{
> > + return userfaultfd_minor(vma) || userfaultfd_wp(vma) ||
> > + userfaultfd_rwp(vma);
>
> This is changing the logic.
>
> Before we were testing only the flags, now we have:
>
> static inline bool userfaultfd_rwp(const struct vm_area_struct *vma)
> {
> /*
> * Callers gate PAGE_NONE usage on this; PAGE_NONE is a BUILD_BUG()
> * without CONFIG_ARCH_HAS_PTE_PROTNONE, so fold to false.
> */
> if (!IS_ENABLED(CONFIG_ARCH_HAS_PTE_PROTNONE))
> return false;
> return vma_test_single_mask(vma, VMA_UFFD_RWP);
> }
>
> I.e. adding in a CONFIG_ARCH_HAS_PTE_PROTNONE check.
Without CONFIG_ARCH_HAS_PTE_PROTNONE VMA_UFFD_RWP is hardwired to VM_NONE
so it's functionally the same ;-)
> BTW side-note these:
>
> static inline bool userfaultfd_missing(const struct vm_area_struct *vma)
> {
> return vma_test_any_mask(vma, VMA_UFFD_MISSING);
> }
>
> static inline bool userfaultfd_wp(const struct vm_area_struct *vma)
> {
> return vma_test_any_mask(vma, VMA_UFFD_WP);
> }
>
> static inline bool userfaultfd_minor(const struct vm_area_struct *vma)
> {
> return vma_test_any_mask(vma, VMA_UFFD_MINOR);
> }
>
> Should all use vma_test_single_mask() really :)
These are changed anyway in a later patch.
> --
> Cheers, Lorenzo
--
Sincerely yours,
Mike.
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 3/6] userfaultfd: use userfaultfd_*() helpers instead of open coded flag tests
2026-08-25 11:19 ` Mike Rapoport
@ 2026-08-25 11:26 ` Lorenzo Stoakes (ARM)
0 siblings, 0 replies; 32+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-08-25 11:26 UTC (permalink / raw)
To: Mike Rapoport
Cc: Andrew Morton, David Hildenbrand, Baolin Wang, Barry Song,
Dev Jain, Hugh Dickins, Jann Horn, Jason Gunthorpe, John Hubbard,
Jonathan Corbet, Lance Yang, Liam R. Howlett, Masami Hiramatsu,
Mathieu Desnoyers, Michal Hocko, Muchun Song, Nico Pache,
Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, Zi Yan, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
On Tue, Aug 25, 2026 at 02:19:52PM +0300, Mike Rapoport wrote:
> > > +/*
> > > + * Don't do fault around for WP, RWP or MINOR registered uffd range. For
> > > + * MINOR registered range, fault around will be a total disaster and ptes can
> > > + * be installed without notifications; for WP it should mostly be fine as long
> > > + * as the fault around checks for pte_none() before the installation, however
> > > + * to be super safe we just forbid it; for RWP, pre-faulted neighbours would
> > > + * be indistinguishable from accessed pages in PAGEMAP_SCAN (PAGE_IS_ACCESSED)
> > > + * and pollute the tracked working set, so each page must be populated by its
> > > + * own fault.
> > > + */
> > > +static inline bool uffd_disable_fault_around(struct vm_area_struct *vma)
> > > +{
> > > + return userfaultfd_minor(vma) || userfaultfd_wp(vma) ||
> > > + userfaultfd_rwp(vma);
> >
> > This is changing the logic.
> >
> > Before we were testing only the flags, now we have:
> >
> > static inline bool userfaultfd_rwp(const struct vm_area_struct *vma)
> > {
> > /*
> > * Callers gate PAGE_NONE usage on this; PAGE_NONE is a BUILD_BUG()
> > * without CONFIG_ARCH_HAS_PTE_PROTNONE, so fold to false.
> > */
> > if (!IS_ENABLED(CONFIG_ARCH_HAS_PTE_PROTNONE))
> > return false;
> > return vma_test_single_mask(vma, VMA_UFFD_RWP);
> > }
> >
> > I.e. adding in a CONFIG_ARCH_HAS_PTE_PROTNONE check.
>
> Without CONFIG_ARCH_HAS_PTE_PROTNONE VMA_UFFD_RWP is hardwired to VM_NONE
> so it's functionally the same ;-)
Well then you're explicitly removing logic and not mentioning it anywhere
with a NFC commit.
So please say so in the commit message.
>
> > BTW side-note these:
> >
> > static inline bool userfaultfd_missing(const struct vm_area_struct *vma)
> > {
> > return vma_test_any_mask(vma, VMA_UFFD_MISSING);
> > }
> >
> > static inline bool userfaultfd_wp(const struct vm_area_struct *vma)
> > {
> > return vma_test_any_mask(vma, VMA_UFFD_WP);
> > }
> >
> > static inline bool userfaultfd_minor(const struct vm_area_struct *vma)
> > {
> > return vma_test_any_mask(vma, VMA_UFFD_MINOR);
> > }
> >
> > Should all use vma_test_single_mask() really :)
>
> These are changed anyway in a later patch.
Yup, but you (potentially) break one of them. Will comment there.
>
> > --
> > Cheers, Lorenzo
>
> --
> Sincerely yours,
> Mike.
--
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 5/6] userfaultfd: decouple fault reason from VMA flags
2026-08-25 11:08 ` David Hildenbrand (Arm)
@ 2026-08-25 11:38 ` Lorenzo Stoakes (ARM)
0 siblings, 0 replies; 32+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-08-25 11:38 UTC (permalink / raw)
To: David Hildenbrand (Arm)
Cc: Mike Rapoport, Andrew Morton, Baolin Wang, Barry Song, Dev Jain,
Hugh Dickins, Jann Horn, Jason Gunthorpe, John Hubbard,
Jonathan Corbet, Lance Yang, Liam R. Howlett, Masami Hiramatsu,
Mathieu Desnoyers, Michal Hocko, Muchun Song, Nico Pache,
Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, Zi Yan, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
On Tue, Aug 25, 2026 at 01:08:33PM +0200, David Hildenbrand (Arm) wrote:
>
> >>> @@ -2793,14 +2793,14 @@ static inline bool userfaultfd_must_wait(struct userfaultfd_ctx *ctx,
> >>> * If VMA has UFFD WP faults enabled and WP fault, wait for userspace to
> >>> * resolve the fault.
> >>> */
> >>> - if (!pte_write(ptent) && (reason & VM_UFFD_WP))
> >>> + if (!pte_write(ptent) && (reason & USERFAULT_WP))
> >>
> >> I wonder if you could actually
> >>
> >> You do this quite a lot and they read a bit horribly with the && and & on the
> >> same sight-line. With the changes to the enum proposed above you could do:
> >>
> >> if (!pte_write(ptent) && test_bit(reason, USERFAULT_WP_BIT))
> >
> > I find && and & perfectly readable and adding _BIT defines looks really
> > excessive to me.
>
> Yeah, that looks alright to me as well.
I find the general inconsistent different sets of flags/bits but not
really/naming all a bit of a mess.
But these are largely aesthetic and I don't maintain this file so I guess
you guys can live without my tag here...
>
> --
> Cheers,
>
> David
--
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 6/6] userfaultfd: collapse VM_UFFD_{MISSING,WP,MINOR,RWP} into single VM_UFFD
2026-08-23 12:17 ` [PATCH 6/6] userfaultfd: collapse VM_UFFD_{MISSING,WP,MINOR,RWP} into single VM_UFFD Mike Rapoport (Microsoft)
2026-08-24 7:11 ` Lance Yang
@ 2026-08-25 12:44 ` Lorenzo Stoakes (ARM)
2026-08-25 12:45 ` Lorenzo Stoakes (ARM)
1 sibling, 1 reply; 32+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-08-25 12:44 UTC (permalink / raw)
To: Mike Rapoport (Microsoft)
Cc: Andrew Morton, David Hildenbrand, Baolin Wang, Barry Song,
Dev Jain, Hugh Dickins, Jann Horn, Jason Gunthorpe, John Hubbard,
Jonathan Corbet, Lance Yang, Liam R. Howlett, Masami Hiramatsu,
Mathieu Desnoyers, Michal Hocko, Muchun Song, Nico Pache,
Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, Zi Yan, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
I don't love referring to the legacy flags in the subject but I gues you
have limited space...
On Sun, Aug 23, 2026 at 03:17:43PM +0300, Mike Rapoport (Microsoft) wrote:
> Add 'mode' field to struct vm_uffd_state and define UFFD_MODE_ flags.
Can you mention that you're increasing the size of the VMA by 4 bytes
please? (8 bytes if __HAVE_PFNMAP_TRACKING I believe too).
>
> Use this field to differentiate VMA registration with userfaultfd
> instead of relying on VM_UFFD_* flags.
Here you should reference non-legacy VMA flag names.
>
> A VMA registered with userfaultfd will have a single VM_UFFD flag set
> and its registration mode (MISSING, MINOR, WP, RWP) is determined by
> vm_uffd_state.mode.
>
> This frees three vm_flags bits (12, 41, 43).
Is the primary motivation here to eliminate these flags? We're paying a
cost in VMA bloat here so I think you need to argue for it. I wouldn't say
freeing up VMA flags justifies adding 4 or 8 bytes per VMA.
We've put a lot of effort into reducing VMA size so I think any size
increase in standard shipped 64-bit kernels has to be justified.
Also there's weirdness around the flag behaviour with WP. As I recall
there's strange situations where you have to examine state of the
destination VMA when doing a UFFDIO_MOVE or something like that and there's
just strange edge cases.
I'm guessing the change is just independent of this and in both cases
you're checking for state just in different please?
>
> Update the relevant code to use UFFD_MODE_* instead of VM_UFFD_* flags.
USERFAULT_, UF_, UFFD_... Can we settle on one?
>
> Remove VM_UFFD_WP and VM_UFFD_RWP from VM_COPY_ON_FORK, adding an
> explicit userfaultfd_protected() check in vma_needs_copy() instead.
>
> /proc/pid/smaps representation of VmFlags is slightly changed:
> - any VMA registered with UFFD shows 'uf'
> - the existing userfault markers ('um', 'uw', 'ui', 'ur') are shown after
> VmFlags rather than in the middle
That should all be fine.
>
> Assisted-by: copilot:claude-opus-4.6
> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> ---
> fs/proc/task_mmu.c | 18 +++---
> include/linux/mm.h | 67 +++++-----------------
> include/linux/mm_types.h | 1 +
> include/linux/pgtable.h | 4 +-
> include/linux/userfaultfd_k.h | 37 +++++++-----
> include/trace/events/mmflags.h | 17 +-----
> mm/gup.c | 5 +-
> mm/hugetlb.c | 2 +-
> mm/khugepaged.c | 2 +-
> mm/memory.c | 6 +-
> mm/mprotect.c | 2 +-
> mm/shmem.c | 2 +-
> mm/userfaultfd.c | 123 +++++++++++++++++++++-------------------
> tools/testing/vma/include/dup.h | 18 ++----
> 14 files changed, 134 insertions(+), 170 deletions(-)
>
> diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
> index 5c54aebe2118..8d344c6ee14e 100644
> --- a/fs/proc/task_mmu.c
> +++ b/fs/proc/task_mmu.c
> @@ -23,6 +23,7 @@
> #include <linux/minmax.h>
> #include <linux/overflow.h>
> #include <linux/buildid.h>
> +#include <linux/userfaultfd_k.h>
>
> #include <asm/elf.h>
> #include <asm/tlb.h>
> @@ -1216,8 +1217,7 @@ static void show_smap_vma_flags(struct seq_file *m, struct vm_area_struct *vma)
> [ilog2(VM_HUGEPAGE)] = "hg",
> [ilog2(VM_NOHUGEPAGE)] = "nh",
> [ilog2(VM_MERGEABLE)] = "mg",
> - [ilog2(VM_UFFD_MISSING)]= "um",
> - [ilog2(VM_UFFD_WP)] = "uw",
> + [ilog2(VM_UFFD)] = "uf",
> #ifdef CONFIG_ARM64_MTE
> [ilog2(VM_MTE)] = "mt",
> [ilog2(VM_MTE_ALLOWED)] = "",
> @@ -1234,12 +1234,6 @@ static void show_smap_vma_flags(struct seq_file *m, struct vm_area_struct *vma)
> [ilog2(VM_PKEY_BIT4)] = "",
> #endif
> #endif /* CONFIG_ARCH_HAS_PKEYS */
> -#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_MINOR
> - [ilog2(VM_UFFD_MINOR)] = "ui",
> -#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_MINOR */
> -#ifdef CONFIG_USERFAULTFD_RWP
> - [ilog2(VM_UFFD_RWP)] = "ur",
> -#endif
> #ifdef CONFIG_ARCH_HAS_USER_SHADOW_STACK
> [ilog2(VM_SHADOW_STACK)] = "ss",
> #endif
> @@ -1259,6 +1253,14 @@ static void show_smap_vma_flags(struct seq_file *m, struct vm_area_struct *vma)
> if (vma->vm_flags & (1UL << i))
> seq_printf(m, "%s ", mnemonics[i]);
> }
> + if (userfaultfd_missing(vma))
> + seq_puts(m, "um ");
> + if (userfaultfd_wp(vma))
> + seq_puts(m, "uw ");
> + if (userfaultfd_minor(vma))
> + seq_puts(m, "ui ");
> + if (userfaultfd_rwp(vma))
> + seq_puts(m, "ur ");
Isn't this patch then a bisection hazard where the previous one makes the flags
> seq_putc(m, '\n');
> }
>
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 4daf9cd6ae8e..416de7663951 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -303,7 +303,7 @@ enum {
> DECLARE_VMA_BIT(MAYSHARE, 7),
> DECLARE_VMA_BIT(GROWSDOWN, 8), /* general info on the segment */
> #ifdef CONFIG_MMU
> - DECLARE_VMA_BIT(UFFD_MISSING, 9),/* missing pages tracking */
> + DECLARE_VMA_BIT(UFFD, 9), /* userfaultfd registered */
Since we're getting rid of other flags, can we just have UFFD occupy a flag
that isn't conditional on CONFIG_MMU? Maybe bit 12 instead?
Presumably nommu will never set/use VMA_UFFD_BIT (CONFIG_USERFAULTFD won't
be set) and it'll make everything easier this way.
> #else
> /* nommu: R/O MAP_PRIVATE mapping that might overlay a file mapping */
> DECLARE_VMA_BIT(MAYOVERLAY, 9),
> @@ -311,7 +311,7 @@ enum {
> /* Page-ranges managed without "struct page", just pure PFN */
> DECLARE_VMA_BIT(PFNMAP, 10),
> DECLARE_VMA_BIT(MAYBE_GUARD, 11),
> - DECLARE_VMA_BIT(UFFD_WP, 12), /* wrprotect pages tracking */
> + /* Bit 12 is free */
> DECLARE_VMA_BIT(LOCKED, 13),
> DECLARE_VMA_BIT(IO, 14), /* Memory mapped I/O or similar */
> DECLARE_VMA_BIT(SEQ_READ, 15), /* App will access data sequentially */
> @@ -352,9 +352,8 @@ enum {
> #elif defined(CONFIG_64BIT)
> DECLARE_VMA_BIT(DROPPABLE, 40),
> #endif
> - DECLARE_VMA_BIT(UFFD_MINOR, 41),
> + /* Bits 41 and 43 are free */
> DECLARE_VMA_BIT(SEALED, 42),
> - DECLARE_VMA_BIT(UFFD_RWP, 43),
> /* Flags that reuse flags above. */
> DECLARE_VMA_BIT_ALIAS(PKEY_BIT0, HIGH_ARCH_0),
> DECLARE_VMA_BIT_ALIAS(PKEY_BIT1, HIGH_ARCH_1),
> @@ -408,14 +407,14 @@ enum {
> #define VM_MAYSHARE INIT_VM_FLAG(MAYSHARE)
> #define VM_GROWSDOWN INIT_VM_FLAG(GROWSDOWN)
> #ifdef CONFIG_MMU
> -#define VM_UFFD_MISSING INIT_VM_FLAG(UFFD_MISSING)
> +#define VM_UFFD INIT_VM_FLAG(UFFD)
> +#define VMA_UFFD mk_vma_flags(VMA_UFFD_BIT)
See above, in general it's annoying to figure out whether the flag is
available and it's easy to slip bugs in.
It's also weird to have flags before that were always declared, and now one that
is not.
But I'm not sure you're even using this now?
> #else
> -#define VM_UFFD_MISSING VM_NONE
> +#define VM_UFFD VM_NONE
> #define VM_MAYOVERLAY INIT_VM_FLAG(MAYOVERLAY)
> #endif
> #define VM_PFNMAP INIT_VM_FLAG(PFNMAP)
> #define VM_MAYBE_GUARD INIT_VM_FLAG(MAYBE_GUARD)
> -#define VM_UFFD_WP INIT_VM_FLAG(UFFD_WP)
> #define VM_LOCKED INIT_VM_FLAG(LOCKED)
> #define VM_IO INIT_VM_FLAG(IO)
> #define VM_SEQ_READ INIT_VM_FLAG(SEQ_READ)
> @@ -499,36 +498,6 @@ enum {
> #define VM_MTE VM_NONE
> #define VM_MTE_ALLOWED VM_NONE
> #endif
> -#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_MINOR
> -#define VM_UFFD_MINOR INIT_VM_FLAG(UFFD_MINOR)
> -#else
> -#define VM_UFFD_MINOR VM_NONE
> -#endif
> -#ifdef CONFIG_USERFAULTFD_RWP
> -#define VM_UFFD_RWP INIT_VM_FLAG(UFFD_RWP)
> -#else
> -#define VM_UFFD_RWP VM_NONE
> -#endif
> -
> -/*
> - * vma_flags_t masks for the userfaultfd VMA flags. The two high-bit modes are
> - * gated on the same configs as their VM_* flags above -- both of which imply
> - * 64BIT -- so an out-of-range bit is never fed to mk_vma_flags() on a build
> - * whose bitmap cannot hold it.
> - */
> -#define VMA_UFFD_MISSING mk_vma_flags(VMA_UFFD_MISSING_BIT)
> -#define VMA_UFFD_WP mk_vma_flags(VMA_UFFD_WP_BIT)
> -#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_MINOR
> -#define VMA_UFFD_MINOR mk_vma_flags(VMA_UFFD_MINOR_BIT)
> -#else
> -#define VMA_UFFD_MINOR EMPTY_VMA_FLAGS
> -#endif
> -#ifdef CONFIG_USERFAULTFD_RWP
> -#define VMA_UFFD_RWP mk_vma_flags(VMA_UFFD_RWP_BIT)
> -#else
> -#define VMA_UFFD_RWP EMPTY_VMA_FLAGS
> -#endif
> -
> #ifdef CONFIG_64BIT
> #define VM_ALLOW_ANY_UNCACHED INIT_VM_FLAG(ALLOW_ANY_UNCACHED)
> #define VM_SEALED INIT_VM_FLAG(SEALED)
> @@ -668,32 +637,26 @@ enum {
> * reconsistuted upon page fault, so necessitate page table copying upon fork.
> *
> * Note that these flags should be compared with the DESTINATION VMA not the
> - * source: VM_UFFD_WP and VM_UFFD_RWP may be cleared on the destination
> + * source: uffd WP/RWP mode may be cleared on the destination
> * (dup_userfaultfd() -> userfaultfd_reset_ctx() when the parent context did
> * not negotiate UFFD_FEATURE_EVENT_FORK), while all other flags propagate.
> *
> * VM_PFNMAP / VM_MIXEDMAP - These contain kernel-mapped data which cannot be
> * reasonably reconstructed on page fault.
> *
> - * VM_UFFD_WP - Encodes metadata about an installed uffd
> - * VM_UFFD_RWP write- or read-write-protect handler, which
> - * cannot be reconstructed on page fault.
> - *
> - * We always copy pgtables when dst_vma has the
> - * uffd PTE bit in use even if it's file-backed
> - * (e.g. shmem). Because when the uffd bit is
> - * in use, the pgtable contains the protection
> - * information, that's something we can't
> - * retrieve from page cache, and skip copying
> - * will lose those info.
> - *
> * VM_MAYBE_GUARD - Could contain page guard region markers which
> * by design are a property of the page tables
> * only and thus cannot be reconstructed on page
> * fault.
> + *
> + * uffd WP/RWP modes - Encode metadata about an installed uffd
> + * write- or read-write-protect handler, which
> + * cannot be reconstructed on page fault.
> + * This is checked separately via
> + * userfaultfd_protected() in vma_needs_copy().
> + *
> */
> -#define VM_COPY_ON_FORK (VM_PFNMAP | VM_MIXEDMAP | VM_UFFD_WP | VM_UFFD_RWP | \
> - VM_MAYBE_GUARD)
> +#define VM_COPY_ON_FORK (VM_PFNMAP | VM_MIXEDMAP | VM_MAYBE_GUARD)
Really this should be converted to the new VMA flags model, but I guess
it's outside of the scope of this change.
>
> /*
> * mapping from the currently active vm_flags protection bits (the
> diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
> index d6deb655d82e..8354d1c18b29 100644
> --- a/include/linux/mm_types.h
> +++ b/include/linux/mm_types.h
> @@ -723,6 +723,7 @@ struct vm_region {
> #define NULL_VM_UFFD_STATE ((struct vm_uffd_state) { NULL, })
> struct vm_uffd_state {
> struct userfaultfd_ctx *ctx;
> + unsigned int mode;
> };
Hmm this is adding 4 bytes at least to every VMA is that OK?
I was going to say this adds a cache line but no it shouldn't as it's right
at the end.
VMA size scaling is a real issue though and this increases every VMA by 4
bytes, can't it be put in userfaultfd_ctx? I guess not as it's a per-VMA
thing.
And does all of the NULL stuff now actually still work?
> #else /* CONFIG_USERFAULTFD */
> #define NULL_VM_UFFD_STATE ((struct vm_uffd_state) {})
> diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
> index 8c093c119e5a..4b74c298cc14 100644
> --- a/include/linux/pgtable.h
> +++ b/include/linux/pgtable.h
> @@ -2119,8 +2119,8 @@ static inline int pud_trans_unstable(pud_t *pud)
> * In an accessible VMA, pte_protnone() reliably indicates a present
> * PROT_NONE page protection. Today the kernel uses such PTEs for two
> * purposes: NUMA hinting faults, and userfaultfd RWP tracking on
> - * VM_UFFD_RWP VMAs. The two are distinguished by the uffd PTE bit and
> - * the VMA flag; see include/linux/userfaultfd_k.h.
> + * uffd-RWP VMAs. The two are distinguished by the uffd PTE bit and
> + * the VMA uffd state; see include/linux/userfaultfd_k.h.
> *
> * So, to reliably identify PROT_NONE PTEs that require kernel handling,
> * looking at the VMA accessibility (and the uffd bit on RWP VMAs) is
> diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
> index f401623f315d..b4261038d10a 100644
> --- a/include/linux/userfaultfd_k.h
> +++ b/include/linux/userfaultfd_k.h
> @@ -32,12 +32,13 @@ enum uf_reason {
> #include <asm-generic/pgtable_uffd.h>
> #include <linux/hugetlb_inline.h>
>
> -/* The set of all possible UFFD-related VM flags. */
> -#define __VM_UFFD_FLAGS (VM_UFFD_MISSING | VM_UFFD_MINOR | \
> - VM_UFFD_WP | VM_UFFD_RWP)
> -
> -#define __VMA_UFFD_FLAGS mk_vma_flags_from_masks(VMA_UFFD_MISSING, VMA_UFFD_WP, \
> - VMA_UFFD_MINOR, VMA_UFFD_RWP)
> +/* Per-VMA uffd modes */
> +#define UFFD_MODE_MISSING BIT(0)
> +#define UFFD_MODE_MINOR BIT(1)
> +#define UFFD_MODE_RWP BIT(2)
> +#define UFFD_MODE_WP BIT(3)
> +#define UFFD_MODE_ALL (UFFD_MODE_MISSING | UFFD_MODE_MINOR | \
> + UFFD_MODE_RWP | UFFD_MODE_WP)
An entirely new set of duplicative flags?
And now we're flitting from USERFAULT_ to UFFD_ for some reason...
Mode also seems to me to imply a specific setting not a set of flags.
So you probably want to put the word 'flag' in there somewhere... Or say
'mode_s_'. Since multiple can be set right?
And weird/inconsistent to declare the USERFAULT_xxx as an enum and #define's
here as well as the naming?
I have to say it's confusing.
>
> /*
> * CAREFUL: Check include/uapi/asm-generic/fcntl.h when defining
> @@ -99,7 +100,7 @@ vm_fault_t handle_userfault(struct vm_fault *vmf, enum uf_reason reason);
> /* VMA userfaultfd operations */
> struct vm_uffd_ops {
> /* Checks if a VMA can support userfaultfd */
> - bool (*can_userfault)(struct vm_area_struct *vma, vm_flags_t vm_flags);
> + bool (*can_userfault)(struct vm_area_struct *vma, unsigned int mode);
> /*
> * Called to resolve UFFDIO_CONTINUE request.
> * Should return the folio found at pgoff in the VMA's pagecache if it
> @@ -174,25 +175,34 @@ int move_pages_huge_pmd(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd, pm
> unsigned long dst_addr, unsigned long src_addr);
>
> /* mm helpers */
> +static inline unsigned int uffd_mode(const struct vm_area_struct *vma)
> +{
> + return vma->vm_uffd_state.mode;
> +}
> +
> static inline bool is_mergeable_vm_uffd_state(struct vm_area_struct *vma,
> struct vm_uffd_state vm_ctx)
> {
> - return vma->vm_uffd_state.ctx == vm_ctx.ctx;
> + return vma->vm_uffd_state.ctx == vm_ctx.ctx &&
> + uffd_mode(vma) == vm_ctx.mode;
You see it's things like this that make the naming problematic, now it
seems that mode (whose very name implies a singular state) is being checked
against another which can either be in one mode or another but actually
you're doing a flags check...
> }
>
> static inline bool userfaultfd_missing(const struct vm_area_struct *vma)
> {
> - return vma_test_any_mask(vma, VMA_UFFD_MISSING);
> + return vma_test(vma, VMA_UFFD_BIT) &&
> + (uffd_mode(vma) & UFFD_MODE_MISSING);
This is broken assuming this can be executed in a context where VMA_UFFD can be
VMA_NONE.
You should use vma_test_single_mask(). Or preferably, as above, just always
provide VMA_UFFD_BIT.
The problem is with bits we can't express a VM_NONE equivalent, which is
why VMA_UFFD is defined.
It seems the only places that's used are ones where you could, or already
do, gate on uffd being enabled:
include/linux/mm.h: * vma_flags_t flags = mk_vma_flags_from_masks(VMA_UFFD_WP, VMA_UFFD_MINOR);
(This is a comment that needs updating see my comment at the end of review).
mm/userfaultfd.c: vma_flags_clear_mask(&new_vma_flags, VMA_UFFD);
mm/userfaultfd.c: vma_flags_set_mask(&new_vma_flags, VMA_UFFD);
> }
>
> static inline bool userfaultfd_wp(const struct vm_area_struct *vma)
> {
> - return vma_test_any_mask(vma, VMA_UFFD_WP);
> + return vma_test(vma, VMA_UFFD_BIT) &&
> + (uffd_mode(vma) & UFFD_MODE_WP);
Same comment as above this seems broken.
> }
>
> static inline bool userfaultfd_minor(const struct vm_area_struct *vma)
> {
> - return vma_test_any_mask(vma, VMA_UFFD_MINOR);
> + return vma_test(vma, VMA_UFFD_BIT) &&
> + (uffd_mode(vma) & UFFD_MODE_MINOR);
Same comment as above this seems broken.
> }
>
> static inline bool userfaultfd_rwp(const struct vm_area_struct *vma)
> @@ -203,7 +213,8 @@ static inline bool userfaultfd_rwp(const struct vm_area_struct *vma)
> */
> if (!IS_ENABLED(CONFIG_ARCH_HAS_PTE_PROTNONE))
> return false;
> - return vma_test_single_mask(vma, VMA_UFFD_RWP);
> + return vma_test(vma, VMA_UFFD_BIT) &&
> + (uffd_mode(vma) & UFFD_MODE_RWP);
Same comment as above this seems broken.
Obviously I don't love the &&, & but that seems a moot point.
> }
>
> static inline bool userfaultfd_protected(const struct vm_area_struct *vma)
> @@ -271,7 +282,7 @@ static inline bool userfaultfd_huge_pmd_rwp(struct vm_area_struct *vma,
>
> static inline bool userfaultfd_armed(struct vm_area_struct *vma)
> {
> - return vma_test_any_mask(vma, __VMA_UFFD_FLAGS);
> + return vma_test(vma, VMA_UFFD_BIT);
Same comment as above.
> }
>
> static inline bool vma_has_uffd_without_event_remap(struct vm_area_struct *vma)
> diff --git a/include/trace/events/mmflags.h b/include/trace/events/mmflags.h
> index 935893e5ea53..aacdd90e0a64 100644
> --- a/include/trace/events/mmflags.h
> +++ b/include/trace/events/mmflags.h
> @@ -180,18 +180,6 @@ IF_HAVE_PG_ARCH_3(arch_3)
> #define IF_HAVE_VM_SOFTDIRTY(flag,name)
> #endif
>
> -#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_MINOR
> -# define IF_HAVE_UFFD_MINOR(flag, name) {flag, name},
> -#else
> -# define IF_HAVE_UFFD_MINOR(flag, name)
> -#endif
> -
> -#ifdef CONFIG_USERFAULTFD_RWP
> -# define IF_HAVE_UFFD_RWP(flag, name) {flag, name},
> -#else
> -# define IF_HAVE_UFFD_RWP(flag, name)
> -#endif
> -
> #if defined(CONFIG_64BIT) || defined(CONFIG_PPC32)
> # define IF_HAVE_VM_DROPPABLE(flag, name) {flag, name},
> #else
> @@ -208,12 +196,9 @@ IF_HAVE_PG_ARCH_3(arch_3)
> {VM_MAYEXEC, "mayexec" }, \
> {VM_MAYSHARE, "mayshare" }, \
> {VM_GROWSDOWN, "growsdown" }, \
> - {VM_UFFD_MISSING, "uffd_missing" }, \
> -IF_HAVE_UFFD_MINOR(VM_UFFD_MINOR, "uffd_minor" ) \
> + {VM_UFFD, "uffd" }, \
> {VM_PFNMAP, "pfnmap" }, \
> {VM_MAYBE_GUARD, "maybe_guard" }, \
> - {VM_UFFD_WP, "uffd_wp" }, \
> -IF_HAVE_UFFD_RWP(VM_UFFD_RWP, "uffd_rwp" ) \
> {VM_LOCKED, "locked" }, \
> {VM_IO, "io" }, \
> {VM_SEQ_READ, "seqread" }, \
Shouldn't you update the tracing logic to obtain these from uffd
modes/flags?
> diff --git a/mm/gup.c b/mm/gup.c
> index 500e2aa99e48..9243c41a0c0e 100644
> --- a/mm/gup.c
> +++ b/mm/gup.c
> @@ -12,6 +12,7 @@
> #include <linux/swap.h>
> #include <linux/swapops.h>
> #include <linux/secretmem.h>
> +#include <linux/userfaultfd_k.h>
>
> #include <linux/sched/signal.h>
> #include <linux/rwsem.h>
> @@ -641,7 +642,7 @@ static inline bool gup_can_follow_protnone(const struct vm_area_struct *vma,
> unsigned int flags)
> {
> /*
> - * VM_UFFD_RWP uses protnone as an access-tracking marker, not for
> + * uffd-RWP uses protnone as an access-tracking marker, not for
> * NUMA hinting. GUP must always take a fault so the access is
> * delivered to userfaultfd, regardless of FOLL_HONOR_NUMA_FAULT.
> *
> @@ -651,7 +652,7 @@ static inline bool gup_can_follow_protnone(const struct vm_area_struct *vma,
> * no progress on protnone in an inaccessible VMA, and the access is
> * denied regardless of RWP anyway.
> */
> - if (vma_test_single_mask(vma, VMA_UFFD_RWP) && vma_is_accessible(vma))
> + if (userfaultfd_rwp(vma) && vma_is_accessible(vma))
> return false;
>
> /*
> diff --git a/mm/hugetlb.c b/mm/hugetlb.c
> index 5e2ed80c1938..a15c443474d5 100644
> --- a/mm/hugetlb.c
> +++ b/mm/hugetlb.c
> @@ -4808,7 +4808,7 @@ static vm_fault_t hugetlb_vm_op_fault(struct vm_fault *vmf)
>
> #ifdef CONFIG_USERFAULTFD
> static bool hugetlb_can_userfault(struct vm_area_struct *vma,
> - vm_flags_t vm_flags)
> + unsigned int mode)
> {
> return true;
> }
> diff --git a/mm/khugepaged.c b/mm/khugepaged.c
> index 79effd3f3da4..7f590a1d3ca3 100644
> --- a/mm/khugepaged.c
> +++ b/mm/khugepaged.c
> @@ -2112,7 +2112,7 @@ static bool file_backed_vma_is_retractable(struct vm_area_struct *vma)
> /*
> * When a vma is registered with uffd-wp or RWP, we cannot recycle
> * the page table because there may be pte markers installed.
> - * VM_UFFD_RWP ranges similarly rely on per-PTE uffd state
> + * uffd-RWP ranges similarly rely on per-PTE uffd state
> * and cannot be recycled to a shared PMD. Other vmas can still
> * have the same file mapped hugely, but skip this one: it will
> * always be mapped in small page size for these registrations.
> diff --git a/mm/memory.c b/mm/memory.c
> index 1a9b41704b0c..c12ec979199c 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -1565,10 +1565,12 @@ vma_needs_copy(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma)
> {
> /*
> * We check against dst_vma as while sane VMA flags will have been
> - * copied, VM_UFFD_WP may be set only on dst_vma.
> + * copied, userfaultfd WP/RWP mode may be set only on dst_vma.
> */
> if (dst_vma->vm_flags & VM_COPY_ON_FORK)
> return true;
> + if (userfaultfd_protected(dst_vma))
> + return true;
> /*
> * The presence of an anon_vma indicates an anonymous VMA has page
> * tables which naturally cannot be reconstituted on page fault.
> @@ -6563,7 +6565,7 @@ static vm_fault_t handle_pte_fault(struct vm_fault *vmf)
> if (pte_protnone(vmf->orig_pte) && vma_is_accessible(vmf->vma)) {
> /*
> * RWP-protected PTEs are protnone plus the uffd bit. On a
> - * VM_UFFD_RWP VMA, a protnone PTE without the uffd bit is
> + * uffd-RWP VMA, a protnone PTE without the uffd bit is
> * NUMA hinting and must still fall through to do_numa_page().
> */
> if (userfaultfd_pte_rwp(vmf->vma, vmf->orig_pte))
> diff --git a/mm/mprotect.c b/mm/mprotect.c
> index 2888ee638d87..b98d4372677b 100644
> --- a/mm/mprotect.c
> +++ b/mm/mprotect.c
> @@ -297,7 +297,7 @@ static __always_inline void change_present_ptes(struct mmu_gather *tlb,
> ptent = pte_clear_uffd(ptent);
>
> /*
> - * The uffd bit on a VM_UFFD_RWP VMA carries PROT_NONE
> + * The uffd bit on a uffd-RWP VMA carries PROT_NONE
> * semantics. If mprotect() or NUMA hinting changed the
> * base protection, restore PAGE_NONE so the PTE still
> * traps on any access. pte_modify() preserves
> diff --git a/mm/shmem.c b/mm/shmem.c
> index 2138a4e6b549..c8db9f93dde1 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -3220,7 +3220,7 @@ static struct folio *shmem_get_folio_noalloc(struct inode *inode, pgoff_t pgoff)
> return folio;
> }
>
> -static bool shmem_can_userfault(struct vm_area_struct *vma, vm_flags_t vm_flags)
> +static bool shmem_can_userfault(struct vm_area_struct *vma, unsigned int mode)
> {
> return true;
> }
> diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
> index 83587d34b189..193f6e65d875 100644
> --- a/mm/userfaultfd.c
> +++ b/mm/userfaultfd.c
> @@ -50,10 +50,10 @@ struct mfill_state {
> pmd_t *pmd;
> };
>
> -static bool anon_can_userfault(struct vm_area_struct *vma, vm_flags_t vm_flags)
> +static bool anon_can_userfault(struct vm_area_struct *vma, unsigned int mode)
> {
> /* anonymous memory does not support MINOR mode */
> - if (vm_flags & VM_UFFD_MINOR)
> + if (mode & UFFD_MODE_MINOR)
> return false;
> return true;
> }
> @@ -462,7 +462,7 @@ static int mfill_copy_folio_locked(struct folio *folio, unsigned long src_addr)
> }
>
> #define MFILL_RETRY_STATE_VMA_FLAGS \
> - append_vma_flags(__VMA_UFFD_FLAGS, VMA_SHARED_BIT)
> + append_vma_flags(VMA_UFFD, VMA_SHARED_BIT)
>
> /*
> * VMA state saved before dropping the locks in mfill_copy_folio_retry().
> @@ -2194,7 +2194,7 @@ static ssize_t move_pages(struct userfaultfd_ctx *ctx, unsigned long dst_start,
> return moved ? moved : err;
> }
>
> -static bool vma_can_userfault(struct vm_area_struct *vma, vm_flags_t vm_flags,
> +static bool vma_can_userfault(struct vm_area_struct *vma, unsigned int mode,
> bool wp_async)
> {
> const struct vm_uffd_ops *ops = vma_uffd_ops(vma);
> @@ -2205,13 +2205,11 @@ static bool vma_can_userfault(struct vm_area_struct *vma, vm_flags_t vm_flags,
> if (!is_vm_hugetlb_page(vma) && (vma->vm_flags & VM_SPECIAL))
> return false;
>
> - vm_flags &= __VM_UFFD_FLAGS;
> -
> /*
> * If WP is the only mode enabled and context is wp async, allow any
> * memory type.
> */
> - if (wp_async && (vm_flags == VM_UFFD_WP))
> + if (wp_async && (mode == UFFD_MODE_WP))
Yeah again this is so so confusing and the naming really doesn't help.
I wonder if helpers similar to the vma flag helpers could come in handly.
I know you claim that kind of thing is overengineering but you're
open-coding checks all over the place, then doing a subtle variation like
this which is really really easy to miss.
Something like userfault_test() would be nice.
At any rate 'modes' or 'flags' or something would be clearer here.
> return true;
>
> /* For any other mode reject VMAs that don't implement vm_uffd_ops */
> @@ -2222,19 +2220,31 @@ static bool vma_can_userfault(struct vm_area_struct *vma, vm_flags_t vm_flags,
> * If user requested uffd-wp but not enabled pte markers for
> * uffd-wp, then only anonymous memory is supported
> */
> - if (!uffd_supports_wp_marker() && (vm_flags & VM_UFFD_WP) &&
> + if (!uffd_supports_wp_marker() && (mode & UFFD_MODE_WP) &&
> !vma_is_anonymous(vma))
> return false;
>
> - return ops->can_userfault(vma, vm_flags);
> + return ops->can_userfault(vma, mode);
> }
>
> -static void userfaultfd_set_vm_flags(struct vm_area_struct *vma,
> - vm_flags_t vm_flags)
> +static void userfaultfd_set_ctx(struct vm_area_struct *vma,
> + struct userfaultfd_ctx *ctx,
> + unsigned int mode)
> {
> - const bool uffd_wp_changed = (vma->vm_flags ^ vm_flags) & VM_UFFD_WP;
> + const bool uffd_wp_changed = (uffd_mode(vma) ^ mode) & UFFD_MODE_WP;
> +
> + vma_start_write(vma);
> +
> + vma->vm_uffd_state = (struct vm_uffd_state){
> + .ctx = ctx,
> + .mode = mode,
> + };
> +
> + if (mode)
> + vma_set_flags(vma, VMA_UFFD_BIT);
> + else
> + vma_clear_flags(vma, VMA_UFFD_BIT);
>
> - vm_flags_reset(vma, vm_flags);
> /*
> * For shared mappings, we want to enable writenotify while
> * userfaultfd-wp is enabled (see vma_wants_writenotify()). We'll simply
> @@ -2244,16 +2254,6 @@ static void userfaultfd_set_vm_flags(struct vm_area_struct *vma,
> vma_set_page_prot(vma);
> }
>
> -static void userfaultfd_set_ctx(struct vm_area_struct *vma,
> - struct userfaultfd_ctx *ctx,
> - vm_flags_t vm_flags)
> -{
> - vma_start_write(vma);
> - vma->vm_uffd_state = (struct vm_uffd_state){ctx};
> - userfaultfd_set_vm_flags(vma,
> - (vma->vm_flags & ~__VM_UFFD_FLAGS) | vm_flags);
> -}
> -
> static void userfaultfd_reset_ctx(struct vm_area_struct *vma)
> {
> userfaultfd_set_ctx(vma, NULL, 0);
> @@ -2269,7 +2269,7 @@ static struct vm_area_struct *userfaultfd_clear_vma(struct vma_iterator *vmi,
> bool give_up_on_oom = false;
> vma_flags_t new_vma_flags = vma->flags;
>
> - vma_flags_clear_mask(&new_vma_flags, __VMA_UFFD_FLAGS);
> + vma_flags_clear_mask(&new_vma_flags, VMA_UFFD);
>
> /*
> * If we are modifying only and not splitting, just give up on the merge
> @@ -2313,11 +2313,10 @@ static struct vm_area_struct *userfaultfd_clear_vma(struct vma_iterator *vmi,
> /* Assumes mmap write lock taken, and mm_struct pinned. */
> static int userfaultfd_register_range(struct userfaultfd_ctx *ctx,
> struct vm_area_struct *vma,
> - vm_flags_t vm_flags,
> + unsigned int mode,
> unsigned long start, unsigned long end,
> bool wp_async)
> {
> - vma_flags_t vma_flags = legacy_to_vma_flags(vm_flags);
> VMA_ITERATOR(vmi, ctx->mm, start);
> struct vm_area_struct *prev = vma_prev(&vmi);
> unsigned long vma_end;
> @@ -2329,7 +2328,7 @@ static int userfaultfd_register_range(struct userfaultfd_ctx *ctx,
> for_each_vma_range(vmi, vma, end) {
> cond_resched();
>
> - VM_WARN_ON_ONCE(!vma_can_userfault(vma, vm_flags, wp_async));
> + VM_WARN_ON_ONCE(!vma_can_userfault(vma, mode, wp_async));
> VM_WARN_ON_ONCE(vma->vm_uffd_state.ctx &&
> vma->vm_uffd_state.ctx != ctx);
> VM_WARN_ON_ONCE(!vma_test(vma, VMA_MAYWRITE_BIT));
> @@ -2339,28 +2338,31 @@ static int userfaultfd_register_range(struct userfaultfd_ctx *ctx,
> * userfaultfd and with the right tracking mode too.
> */
> if (vma->vm_uffd_state.ctx == ctx &&
> - vma_test_all_mask(vma, vma_flags))
> + (uffd_mode(vma) & mode) == mode)
> goto skip;
>
> /*
> * Pre-scan in userfaultfd_register() already rejected mode
> - * switches that would drop VM_UFFD_WP or VM_UFFD_RWP, so a
> - * stray bit here is a bug.
> + * switches that would drop WP or RWP, so a stray bit here
> + * is a bug.
> */
> VM_WARN_ON_ONCE(vma->vm_uffd_state.ctx == ctx &&
> - vma->vm_flags & (VM_UFFD_WP | VM_UFFD_RWP) & ~vm_flags);
> + uffd_mode(vma) &
> + (UFFD_MODE_WP | UFFD_MODE_RWP) & ~mode);
>
> if (vma->vm_start > start)
> start = vma->vm_start;
> vma_end = min(end, vma->vm_end);
>
> new_vma_flags = vma->flags;
> - vma_flags_clear_mask(&new_vma_flags, __VMA_UFFD_FLAGS);
> - vma_flags_set_mask(&new_vma_flags, vma_flags);
> + vma_flags_set_mask(&new_vma_flags, VMA_UFFD);
This is oddly arbitrarily using VMA_UFFD inconsistent from all uses of
VMA_UFFD_BIT.
>
> vma = vma_modify_flags_uffd(&vmi, prev, vma, start, vma_end,
> &new_vma_flags,
> - (struct vm_uffd_state){ctx},
> + (struct vm_uffd_state){
> + .ctx = ctx,
> + .mode = mode,
> + },
> /* give_up_on_oom = */false);
> if (IS_ERR(vma))
> return PTR_ERR(vma);
> @@ -2370,7 +2372,7 @@ static int userfaultfd_register_range(struct userfaultfd_ctx *ctx,
> * the next vma was merged into the current one and
> * the current one has not been updated yet.
> */
> - userfaultfd_set_ctx(vma, ctx, vm_flags);
> + userfaultfd_set_ctx(vma, ctx, mode);
>
> if (is_vm_hugetlb_page(vma) && uffd_disable_huge_pmd_share(vma))
> hugetlb_unshare_all_pmds(vma);
> @@ -2420,7 +2422,7 @@ static void userfaultfd_release_all(struct mm_struct *mm,
> for_each_vma(vmi, vma) {
> cond_resched();
> VM_WARN_ON_ONCE(!!vma->vm_uffd_state.ctx ^
> - !!(vma->vm_flags & __VM_UFFD_FLAGS));
> + vma_test(vma, VMA_UFFD_BIT));
> if (vma->vm_uffd_state.ctx != ctx) {
> prev = vma;
> continue;
> @@ -2876,9 +2878,9 @@ vm_fault_t handle_userfault(struct vm_fault *vmf, enum uf_reason reason)
> * NOTE: it should become possible to return VM_FAULT_RETRY
> * even if FAULT_FLAG_TRIED is set without leading to gup()
> * -EBUSY failures, if the userfaultfd is to be extended for
> - * VM_UFFD_WP tracking and we intend to arm the userfault
> + * WP tracking and we intend to arm the userfault
> * without first stopping userland access to the memory. For
> - * VM_UFFD_MISSING userfaults this is enough for now.
> + * MISSING userfaults this is enough for now.
> */
> if (unlikely(!(vmf->flags & FAULT_FLAG_ALLOW_RETRY))) {
> /*
> @@ -3723,7 +3725,7 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
> int ret;
> struct uffdio_register uffdio_register;
> struct uffdio_register __user *user_uffdio_register;
> - vm_flags_t vm_flags;
> + unsigned int mode;
> bool found;
> bool basic_ioctls;
> unsigned long start, end;
> @@ -3742,21 +3744,22 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
> goto out;
> if (uffdio_register.mode & ~UFFD_API_REGISTER_MODES)
> goto out;
> - vm_flags = 0;
> + mode = 0;
> if (uffdio_register.mode & UFFDIO_REGISTER_MODE_MISSING)
> - vm_flags |= VM_UFFD_MISSING;
> + mode |= UFFD_MODE_MISSING;
> if (uffdio_register.mode & UFFDIO_REGISTER_MODE_WP) {
> if (!pgtable_supports_uffd())
> goto out;
>
> - vm_flags |= VM_UFFD_WP;
> + mode |= UFFD_MODE_WP;
> }
> if (uffdio_register.mode & UFFDIO_REGISTER_MODE_RWP) {
> - if (!pgtable_supports_uffd() || VM_UFFD_RWP == VM_NONE)
> + if (!pgtable_supports_uffd() ||
> + !IS_ENABLED(CONFIG_USERFAULTFD_RWP))
> goto out;
> if (!(userfaultfd_features(ctx) & UFFD_FEATURE_RWP))
> goto out;
> - vm_flags |= VM_UFFD_RWP;
> + mode |= UFFD_MODE_RWP;
> }
>
> /*
> @@ -3764,14 +3767,14 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
> * cannot coexist in the same VMA — the bit would carry ambiguous
> * semantics. Reject the combination up front.
> */
> - if ((vm_flags & VM_UFFD_WP) && (vm_flags & VM_UFFD_RWP))
> + if ((mode & UFFD_MODE_WP) && (mode & UFFD_MODE_RWP))
> goto out;
>
> if (uffdio_register.mode & UFFDIO_REGISTER_MODE_MINOR) {
> #ifndef CONFIG_HAVE_ARCH_USERFAULTFD_MINOR
> goto out;
> #endif
> - vm_flags |= VM_UFFD_MINOR;
> + mode |= UFFD_MODE_MINOR;
> }
>
> ret = validate_range(mm, uffdio_register.range.start,
> @@ -3814,11 +3817,11 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
> cond_resched();
>
> VM_WARN_ON_ONCE(!!cur->vm_uffd_state.ctx ^
> - !!(cur->vm_flags & __VM_UFFD_FLAGS));
> + vma_test(cur, VMA_UFFD_BIT));
Same comments as elsewhere re vma_test() on VMA_UFFD_BIT.
>
> /* check not compatible vmas */
> ret = -EINVAL;
> - if (!vma_can_userfault(cur, vm_flags, wp_async))
> + if (!vma_can_userfault(cur, mode, wp_async))
> goto out_unlock;
>
> /*
> @@ -3829,7 +3832,7 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
> * mprotect() must still be unregisterable, so this is not
> * part of vma_can_userfault().
> */
> - if ((vm_flags & VM_UFFD_RWP) && !vma_is_accessible(cur))
> + if ((mode & UFFD_MODE_RWP) && !vma_is_accessible(cur))
> goto out_unlock;
>
> /*
> @@ -3857,7 +3860,8 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
> if (end & (vma_hpagesize - 1))
> goto out_unlock;
> }
> - if ((vm_flags & VM_UFFD_WP) && !(cur->vm_flags & VM_MAYWRITE))
> + if ((mode & UFFD_MODE_WP) &&
> + !vma_test(cur, VMA_MAYWRITE_BIT))
Really weird indentation and I think on one line it's 80 chars anyway?
Thanks for switching to new VMA flags model though!
> goto out_unlock;
>
> /*
> @@ -3872,13 +3876,13 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
> goto out_unlock;
>
> /*
> - * Mode switches that drop VM_UFFD_WP or VM_UFFD_RWP would
> - * leave PTE markers without the flag that describes them;
> + * Mode switches that drop WP or RWP would leave PTE markers
> + * without the mode that describes them;
> * subsequent mprotect() would then promote stale markers
> * into the other mode. Require an unregister first.
> */
> if (cur->vm_uffd_state.ctx == ctx &&
> - cur->vm_flags & (VM_UFFD_WP | VM_UFFD_RWP) & ~vm_flags)
> + uffd_mode(cur) & (UFFD_MODE_WP | UFFD_MODE_RWP) & ~mode)
I mean this is just horrible beyond words aesthetically (and was before
tbf). But you've already rejected this kind of feedback so I guess, yeah I
object. Using bits or wrappers would make this potentially nicer.
Same objection to the use of the word 'mode'. You really need to say flags
here somehow.
> goto out_unlock;
>
> /*
> @@ -3891,7 +3895,7 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
> } for_each_vma_range(vmi, cur, end);
> VM_WARN_ON_ONCE(!found);
>
> - ret = userfaultfd_register_range(ctx, vma, vm_flags, start, end,
> + ret = userfaultfd_register_range(ctx, vma, mode, start, end,
> wp_async);
>
> out_unlock:
> @@ -3986,7 +3990,7 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
> cond_resched();
>
> VM_WARN_ON_ONCE(!!cur->vm_uffd_state.ctx ^
> - !!(cur->vm_flags & __VM_UFFD_FLAGS));
> + vma_test(cur, VMA_UFFD_BIT));
Again you should use vma_test_single_mask(). I'm not sure why you dropped
one for the other unless provably all of these paths are CONFIG_MMU.
But it'd make life a lot easier to just use a bit number that isn't
predicated on CONFIG_MMU.
>
> /*
> * Prevent unregistering through a different userfaultfd than
> @@ -4003,7 +4007,7 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
> * provides for more strict behavior to notice
> * unregistration errors.
> */
> - if (!vma_can_userfault(cur, cur->vm_flags, wp_async))
> + if (!vma_can_userfault(cur, uffd_mode(cur), wp_async))
> goto out_unlock;
>
> found = true;
> @@ -4024,7 +4028,8 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
> goto skip;
>
> VM_WARN_ON_ONCE(vma->vm_uffd_state.ctx != ctx);
> - VM_WARN_ON_ONCE(!vma_can_userfault(vma, vma->vm_flags, wp_async));
> + VM_WARN_ON_ONCE(!vma_can_userfault(vma, uffd_mode(vma),
> + wp_async));
Nit but pretty horrible alignment. Gues it can 't be helped
> VM_WARN_ON_ONCE(!(vma->vm_flags & VM_MAYWRITE));
>
> if (vma->vm_start > start)
> @@ -4329,12 +4334,12 @@ static __u64 uffd_api_available_features(void)
> UFFD_FEATURE_WP_ASYNC);
> /*
> * RWP needs both PROT_NONE support and the uffd PTE bit. The
> - * VM_UFFD_RWP check covers compile-time unavailability; the
> + * IS_ENABLED check covers compile-time unavailability; the
> * pgtable_supports_uffd() check covers runtime (e.g. riscv
> * without the SVRSW60T59B extension) where the PTE bit is declared
> * but not actually usable.
> */
> - if (VM_UFFD_RWP == VM_NONE || !pgtable_supports_uffd())
> + if (!IS_ENABLED(CONFIG_USERFAULTFD_RWP) || !pgtable_supports_uffd())
> f &= ~(UFFD_FEATURE_RWP | UFFD_FEATURE_RWP_ASYNC);
> return f;
> }
> diff --git a/tools/testing/vma/include/dup.h b/tools/testing/vma/include/dup.h
> index 1a01c3529d22..05a39c14eab2 100644
> --- a/tools/testing/vma/include/dup.h
> +++ b/tools/testing/vma/include/dup.h
> @@ -109,7 +109,7 @@ enum {
> DECLARE_VMA_BIT(MAYSHARE, 7),
> DECLARE_VMA_BIT(GROWSDOWN, 8), /* general info on the segment */
> #ifdef CONFIG_MMU
> - DECLARE_VMA_BIT(UFFD_MISSING, 9),/* missing pages tracking */
> + DECLARE_VMA_BIT(UFFD, 9), /* userfaultfd registered */
> #else
> /* nommu: R/O MAP_PRIVATE mapping that might overlay a file mapping */
> DECLARE_VMA_BIT(MAYOVERLAY, 9),
> @@ -117,7 +117,7 @@ enum {
> /* Page-ranges managed without "struct page", just pure PFN */
> DECLARE_VMA_BIT(PFNMAP, 10),
> DECLARE_VMA_BIT(MAYBE_GUARD, 11),
> - DECLARE_VMA_BIT(UFFD_WP, 12), /* wrprotect pages tracking */
> + /* Bit 12 is free */
> DECLARE_VMA_BIT(LOCKED, 13),
> DECLARE_VMA_BIT(IO, 14), /* Memory mapped I/O or similar */
> DECLARE_VMA_BIT(SEQ_READ, 15), /* App will access data sequentially */
> @@ -158,7 +158,7 @@ enum {
> #else
> DECLARE_VMA_BIT(DROPPABLE, 40),
> #endif
> - DECLARE_VMA_BIT(UFFD_MINOR, 41),
> + /* Bit 41 is free */
> DECLARE_VMA_BIT(SEALED, 42),
> /* Flags that reuse flags above. */
> DECLARE_VMA_BIT_ALIAS(PKEY_BIT0, HIGH_ARCH_0),
> @@ -211,14 +211,13 @@ enum {
> #define VM_MAYSHARE INIT_VM_FLAG(MAYSHARE)
> #define VM_GROWSDOWN INIT_VM_FLAG(GROWSDOWN)
> #ifdef CONFIG_MMU
> -#define VM_UFFD_MISSING INIT_VM_FLAG(UFFD_MISSING)
> +#define VM_UFFD INIT_VM_FLAG(UFFD)
> #else
> -#define VM_UFFD_MISSING VM_NONE
> +#define VM_UFFD VM_NONE
> #define VM_MAYOVERLAY INIT_VM_FLAG(MAYOVERLAY)
> #endif
> #define VM_PFNMAP INIT_VM_FLAG(PFNMAP)
> #define VM_MAYBE_GUARD INIT_VM_FLAG(MAYBE_GUARD)
> -#define VM_UFFD_WP INIT_VM_FLAG(UFFD_WP)
> #define VM_LOCKED INIT_VM_FLAG(LOCKED)
> #define VM_IO INIT_VM_FLAG(IO)
> #define VM_SEQ_READ INIT_VM_FLAG(SEQ_READ)
> @@ -297,11 +296,6 @@ enum {
> #define VM_MTE VM_NONE
> #define VM_MTE_ALLOWED VM_NONE
> #endif
> -#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_MINOR
> -#define VM_UFFD_MINOR INIT_VM_FLAG(UFFD_MINOR)
> -#else
> -#define VM_UFFD_MINOR VM_NONE
> -#endif
> #ifdef CONFIG_64BIT
> #define VM_ALLOW_ANY_UNCACHED INIT_VM_FLAG(ALLOW_ANY_UNCACHED)
> #define VM_SEALED INIT_VM_FLAG(SEALED)
> @@ -387,7 +381,7 @@ enum {
>
> #define VMA_IGNORE_MERGE_FLAGS VMA_STICKY_FLAGS
>
> -#define VM_COPY_ON_FORK (VM_PFNMAP | VM_MIXEDMAP | VM_UFFD_WP | VM_MAYBE_GUARD)
> +#define VM_COPY_ON_FORK (VM_PFNMAP | VM_MIXEDMAP | VM_MAYBE_GUARD)
>
> #define pgprot_val(x) ((x).pgprot)
> #define __pgprot(x) ((pgprot_t) { (x) } )
>
> --
> 2.53.0
>
Also, in the mk_vma_flags_from_masks() macro, there's a comment that
explicitly references VMA_UFFD_MINOR:
/*
* Combine pre-computed vma_flags_t masks into one value, e.g.:
*
* vma_flags_t flags = mk_vma_flags_from_masks(VMA_UFFD_WP, VMA_UFFD_MINOR);
*
* Unlike mk_vma_flags(), which takes bit numbers, this takes whole masks --
* each of which may be EMPTY_VMA_FLAGS when its feature is unavailable -- so a
* bit that does not exist on the current build is never materialised.
*/
#define mk_vma_flags_from_masks(...) \
You should change that... Could even be with placeholder flag names potentially.
On the engineering of this - this is one quite big, fiddly patch, if you
abstracted some of the tests into another you could do the change and the
abstraction separately.
Overall I like what you're doing _in general_ but we have to:
a. Figure out whether we want to pay the memory price for this (and the
case has to be made in the commit message.
b. Fix the VMA_UFFD_BIT stuff ideally with a bit that's just always set not
predicated on CONFIG_MMU.
c. Improve the engineering so this stuff actually makes the code clearer
rather than just reimplementing the same old confusing uffd mess.
d. Fix the naming... modes, flags, uffd, userfault, uf, etc. let's stick
with one and be consistent.
IMO before it can move forwards.
--
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 6/6] userfaultfd: collapse VM_UFFD_{MISSING,WP,MINOR,RWP} into single VM_UFFD
2026-08-25 12:44 ` Lorenzo Stoakes (ARM)
@ 2026-08-25 12:45 ` Lorenzo Stoakes (ARM)
0 siblings, 0 replies; 32+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-08-25 12:45 UTC (permalink / raw)
To: Mike Rapoport (Microsoft)
Cc: Andrew Morton, David Hildenbrand, Baolin Wang, Barry Song,
Dev Jain, Hugh Dickins, Jann Horn, Jason Gunthorpe, John Hubbard,
Jonathan Corbet, Lance Yang, Liam R. Howlett, Masami Hiramatsu,
Mathieu Desnoyers, Michal Hocko, Muchun Song, Nico Pache,
Oscar Salvador, Pedro Falcato, Peter Xu, Ryan Roberts,
Shakeel Butt, Shuah Khan, Steven Rostedt, Suren Baghdasaryan,
Usama Arif, Vlastimil Babka, Zi Yan, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, linux-trace-kernel
On Tue, Aug 25, 2026 at 01:44:23PM +0100, Lorenzo Stoakes (ARM) wrote:
> Isn't this patch then a bisection hazard where the previous one makes the flags
Ignore this one, I realised I was wrong and forgot to delete :)
--
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 32+ messages in thread
end of thread, other threads:[~2026-08-25 12:45 UTC | newest]
Thread overview: 32+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-23 12:17 [PATCH 0/6] userfaultfd: decouple uffd mode from VMA flags Mike Rapoport (Microsoft)
2026-08-23 12:17 ` [PATCH 1/6] mm/gup: move gup_can_follow_protnone() to gup.c Mike Rapoport (Microsoft)
2026-08-23 21:03 ` Barry Song
2026-08-24 14:42 ` David Hildenbrand (Arm)
2026-08-25 10:10 ` Mike Rapoport
2026-08-24 14:59 ` Lorenzo Stoakes (ARM)
2026-08-25 2:03 ` Zi Yan
2026-08-23 12:17 ` [PATCH 2/6] userfaultfd: constify VMA parameter of userfaultfd_*() helpers Mike Rapoport (Microsoft)
2026-08-23 21:03 ` Barry Song
2026-08-24 15:03 ` Lorenzo Stoakes (ARM)
2026-08-25 2:03 ` Zi Yan
2026-08-23 12:17 ` [PATCH 3/6] userfaultfd: use userfaultfd_*() helpers instead of open coded flag tests Mike Rapoport (Microsoft)
2026-08-23 21:14 ` Barry Song
2026-08-24 15:10 ` Lorenzo Stoakes (ARM)
2026-08-25 11:19 ` Mike Rapoport
2026-08-25 11:26 ` Lorenzo Stoakes (ARM)
2026-08-23 12:17 ` [PATCH 4/6] userfaultfd: rename vm_userfaultfd_ctx to vm_uffd_state Mike Rapoport (Microsoft)
2026-08-24 14:43 ` David Hildenbrand (Arm)
2026-08-24 15:42 ` Lorenzo Stoakes (ARM)
2026-08-23 12:17 ` [PATCH 5/6] userfaultfd: decouple fault reason from VMA flags Mike Rapoport (Microsoft)
2026-08-24 8:12 ` Muchun Song
2026-08-24 14:46 ` David Hildenbrand (Arm)
2026-08-24 16:28 ` Lorenzo Stoakes (ARM)
2026-08-25 10:37 ` Mike Rapoport
2026-08-25 11:08 ` David Hildenbrand (Arm)
2026-08-25 11:38 ` Lorenzo Stoakes (ARM)
2026-08-23 12:17 ` [PATCH 6/6] userfaultfd: collapse VM_UFFD_{MISSING,WP,MINOR,RWP} into single VM_UFFD Mike Rapoport (Microsoft)
2026-08-24 7:11 ` Lance Yang
2026-08-24 8:17 ` Mike Rapoport
2026-08-24 8:27 ` Lance Yang
2026-08-25 12:44 ` Lorenzo Stoakes (ARM)
2026-08-25 12:45 ` Lorenzo Stoakes (ARM)
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox