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

Reply via email to