summaryrefslogtreecommitdiff
path: root/fs/userfaultfd.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/userfaultfd.c')
-rw-r--r--fs/userfaultfd.c14
1 files changed, 12 insertions, 2 deletions
diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c
index a67afdbbf77a..7e40eb9131bd 100644
--- a/fs/userfaultfd.c
+++ b/fs/userfaultfd.c
@@ -251,7 +251,12 @@ static inline bool userfaultfd_huge_must_wait(struct userfaultfd_ctx *ctx,
*/
if (huge_pte_none_mostly(pte))
ret = true;
- if (!huge_pte_write(pte) && (reason & VM_UFFD_WP))
+ /*
+ * Gate the writability check on pte_present(): huge_pte_write() on a
+ * non-present migration entry decodes random offset bits. The
+ * migration completion path re-delivers the fault if still needed.
+ */
+ if (pte_present(pte) && !huge_pte_write(pte) && (reason & VM_UFFD_WP))
ret = true;
out:
return ret;
@@ -326,7 +331,12 @@ again:
ptent = ptep_get(pte);
if (pte_none_mostly(ptent))
ret = true;
- if (!pte_write(ptent) && (reason & VM_UFFD_WP))
+ /*
+ * Gate the writability check on pte_present(): pte_write() on a
+ * non-present swap/migration entry decodes random offset bits. The
+ * page-in path re-delivers the fault if it still needs userspace.
+ */
+ if (pte_present(ptent) && !pte_write(ptent) && (reason & VM_UFFD_WP))
ret = true;
pte_unmap(pte);