|
@@ -1805,7 +1805,63 @@ next_page:
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(__get_user_pages);
|
|
EXPORT_SYMBOL(__get_user_pages);
|
|
|
|
|
|
-/**
|
|
|
|
|
|
+/*
|
|
|
|
+ * fixup_user_fault() - manually resolve a user page fault
|
|
|
|
+ * @tsk: the task_struct to use for page fault accounting, or
|
|
|
|
+ * NULL if faults are not to be recorded.
|
|
|
|
+ * @mm: mm_struct of target mm
|
|
|
|
+ * @address: user address
|
|
|
|
+ * @fault_flags:flags to pass down to handle_mm_fault()
|
|
|
|
+ *
|
|
|
|
+ * This is meant to be called in the specific scenario where for locking reasons
|
|
|
|
+ * we try to access user memory in atomic context (within a pagefault_disable()
|
|
|
|
+ * section), this returns -EFAULT, and we want to resolve the user fault before
|
|
|
|
+ * trying again.
|
|
|
|
+ *
|
|
|
|
+ * Typically this is meant to be used by the futex code.
|
|
|
|
+ *
|
|
|
|
+ * The main difference with get_user_pages() is that this function will
|
|
|
|
+ * unconditionally call handle_mm_fault() which will in turn perform all the
|
|
|
|
+ * necessary SW fixup of the dirty and young bits in the PTE, while
|
|
|
|
+ * handle_mm_fault() only guarantees to update these in the struct page.
|
|
|
|
+ *
|
|
|
|
+ * This is important for some architectures where those bits also gate the
|
|
|
|
+ * access permission to the page because they are maintained in software. On
|
|
|
|
+ * such architectures, gup() will not be enough to make a subsequent access
|
|
|
|
+ * succeed.
|
|
|
|
+ *
|
|
|
|
+ * This should be called with the mm_sem held for read.
|
|
|
|
+ */
|
|
|
|
+int fixup_user_fault(struct task_struct *tsk, struct mm_struct *mm,
|
|
|
|
+ unsigned long address, unsigned int fault_flags)
|
|
|
|
+{
|
|
|
|
+ struct vm_area_struct *vma;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ vma = find_extend_vma(mm, address);
|
|
|
|
+ if (!vma || address < vma->vm_start)
|
|
|
|
+ return -EFAULT;
|
|
|
|
+
|
|
|
|
+ ret = handle_mm_fault(mm, vma, address, fault_flags);
|
|
|
|
+ if (ret & VM_FAULT_ERROR) {
|
|
|
|
+ if (ret & VM_FAULT_OOM)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ if (ret & (VM_FAULT_HWPOISON | VM_FAULT_HWPOISON_LARGE))
|
|
|
|
+ return -EHWPOISON;
|
|
|
|
+ if (ret & VM_FAULT_SIGBUS)
|
|
|
|
+ return -EFAULT;
|
|
|
|
+ BUG();
|
|
|
|
+ }
|
|
|
|
+ if (tsk) {
|
|
|
|
+ if (ret & VM_FAULT_MAJOR)
|
|
|
|
+ tsk->maj_flt++;
|
|
|
|
+ else
|
|
|
|
+ tsk->min_flt++;
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
* get_user_pages() - pin user pages in memory
|
|
* get_user_pages() - pin user pages in memory
|
|
* @tsk: the task_struct to use for page fault accounting, or
|
|
* @tsk: the task_struct to use for page fault accounting, or
|
|
* NULL if faults are not to be recorded.
|
|
* NULL if faults are not to be recorded.
|