summaryrefslogtreecommitdiff
path: root/fs/userfaultfd.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/userfaultfd.c')
-rw-r--r--fs/userfaultfd.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c
index 390e4b7d9cb9..dba1172436b7 100644
--- a/fs/userfaultfd.c
+++ b/fs/userfaultfd.c
@@ -254,6 +254,15 @@ static inline bool userfaultfd_huge_must_wait(struct userfaultfd_ctx *ctx,
if (pte_is_uffd_marker(pte))
return true;
/*
+ * Concurrent migration may have replaced the present PTE with a
+ * non-marker swap entry between fault delivery and this lockless
+ * re-check. huge_pte_write() on a swap entry decodes random offset
+ * bits, so gate it on pte_present(). The migration completion path
+ * will re-deliver the fault if it still needs userspace.
+ */
+ if (!pte_present(pte))
+ return false;
+ /*
* If VMA has UFFD WP faults enabled and WP fault, wait for userspace to
* resolve the fault.
*/
@@ -340,6 +349,17 @@ again:
if (pte_is_uffd_marker(ptent))
goto out;
/*
+ * Concurrent swap-out / migration may have replaced the present PTE
+ * with a non-marker swap entry between fault delivery and this
+ * lockless re-check. pte_write() on a swap entry decodes random
+ * offset bits, so gate it on pte_present(). The page-in path will
+ * re-deliver the fault if it still needs userspace.
+ */
+ if (!pte_present(ptent)) {
+ ret = false;
+ goto out;
+ }
+ /*
* If VMA has UFFD WP faults enabled and WP fault, wait for userspace to
* resolve the fault.
*/