Thread (49 messages) 49 messages, 9 authors, 2026-08-30

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
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help