Re: [PATCH 6/6] userfaultfd: collapse VM_UFFD_{MISSING,WP,MINOR,RWP} into single VM_UFFD
From: Lance Yang
Date: Mon Aug 24 2026 - 03:12:07 EST
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