Re: [PATCH 6/6] userfaultfd: collapse VM_UFFD_{MISSING,WP,MINOR,RWP} into single VM_UFFD
From: Lance Yang <lance.yang@linux.dev>
Date: 2026-08-24 07:11:44
Also in:
linux-doc, linux-fsdevel, linux-mm, lkml
Subsystem:
memory management, memory management - userfaultfd, the rest · Maintainers:
Andrew Morton, Mike Rapoport, Linus Torvalds
On Sun, Aug 23, 2026 at 03:17:43PM +0300, Mike Rapoport (Microsoft) wrote: [...]
quoted hunk ↗ jump to hunk
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