|
@@ -202,6 +202,49 @@ static inline struct uffd_msg userfault_msg(unsigned long address,
|
|
|
return msg;
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_HUGETLB_PAGE
|
|
|
+/*
|
|
|
+ * Same functionality as userfaultfd_must_wait below with modifications for
|
|
|
+ * hugepmd ranges.
|
|
|
+ */
|
|
|
+static inline bool userfaultfd_huge_must_wait(struct userfaultfd_ctx *ctx,
|
|
|
+ unsigned long address,
|
|
|
+ unsigned long flags,
|
|
|
+ unsigned long reason)
|
|
|
+{
|
|
|
+ struct mm_struct *mm = ctx->mm;
|
|
|
+ pte_t *pte;
|
|
|
+ bool ret = true;
|
|
|
+
|
|
|
+ VM_BUG_ON(!rwsem_is_locked(&mm->mmap_sem));
|
|
|
+
|
|
|
+ pte = huge_pte_offset(mm, address);
|
|
|
+ if (!pte)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ ret = false;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Lockless access: we're in a wait_event so it's ok if it
|
|
|
+ * changes under us.
|
|
|
+ */
|
|
|
+ if (huge_pte_none(*pte))
|
|
|
+ ret = true;
|
|
|
+ if (!huge_pte_write(*pte) && (reason & VM_UFFD_WP))
|
|
|
+ ret = true;
|
|
|
+out:
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+#else
|
|
|
+static inline bool userfaultfd_huge_must_wait(struct userfaultfd_ctx *ctx,
|
|
|
+ unsigned long address,
|
|
|
+ unsigned long flags,
|
|
|
+ unsigned long reason)
|
|
|
+{
|
|
|
+ return false; /* should never get here */
|
|
|
+}
|
|
|
+#endif /* CONFIG_HUGETLB_PAGE */
|
|
|
+
|
|
|
/*
|
|
|
* Verify the pagetables are still not ok after having reigstered into
|
|
|
* the fault_pending_wqh to avoid userland having to UFFDIO_WAKE any
|
|
@@ -378,8 +421,12 @@ int handle_userfault(struct vm_fault *vmf, unsigned long reason)
|
|
|
set_current_state(blocking_state);
|
|
|
spin_unlock(&ctx->fault_pending_wqh.lock);
|
|
|
|
|
|
- must_wait = userfaultfd_must_wait(ctx, vmf->address, vmf->flags,
|
|
|
- reason);
|
|
|
+ if (!is_vm_hugetlb_page(vmf->vma))
|
|
|
+ must_wait = userfaultfd_must_wait(ctx, vmf->address, vmf->flags,
|
|
|
+ reason);
|
|
|
+ else
|
|
|
+ must_wait = userfaultfd_huge_must_wait(ctx, vmf->address,
|
|
|
+ vmf->flags, reason);
|
|
|
up_read(&mm->mmap_sem);
|
|
|
|
|
|
if (likely(must_wait && !ACCESS_ONCE(ctx->released) &&
|