aboutsummaryrefslogtreecommitdiff
path: root/mm
diff options
context:
space:
mode:
authorAlex Shi <alex.shi@linaro.org>2016-10-25 12:30:43 +0800
committerAlex Shi <alex.shi@linaro.org>2016-10-25 12:30:43 +0800
commit4eed929a29a419e367b75ff5e4ab3800d4ce35dd (patch)
tree24b2f7bfff2ceee807c154b0b22c763e70c51648 /mm
parent49a303eef4b10c700f90a9ce35bc944ac54510a6 (diff)
parent0a2aefa1f71da3bb10634918c68f6fb0068c1052 (diff)
Merge branch 'linux-linaro-lsk-v4.1' into linux-linaro-lsk-v4.1-rtlsk-v4.1-16.11-rt
Diffstat (limited to 'mm')
-rw-r--r--mm/gup.c14
1 files changed, 12 insertions, 2 deletions
diff --git a/mm/gup.c b/mm/gup.c
index 6297f6bccfb1..e6de9e74e4ae 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -32,6 +32,16 @@ static struct page *no_page_table(struct vm_area_struct *vma,
return NULL;
}
+/*
+ * FOLL_FORCE can write to even unwritable pte's, but only
+ * after we've gone through a COW cycle and they are dirty.
+ */
+static inline bool can_follow_write_pte(pte_t pte, unsigned int flags)
+{
+ return pte_write(pte) ||
+ ((flags & FOLL_FORCE) && (flags & FOLL_COW) && pte_dirty(pte));
+}
+
static struct page *follow_page_pte(struct vm_area_struct *vma,
unsigned long address, pmd_t *pmd, unsigned int flags)
{
@@ -66,7 +76,7 @@ retry:
}
if ((flags & FOLL_NUMA) && pte_protnone(pte))
goto no_page;
- if ((flags & FOLL_WRITE) && !pte_write(pte)) {
+ if ((flags & FOLL_WRITE) && !can_follow_write_pte(pte, flags)) {
pte_unmap_unlock(ptep, ptl);
return NULL;
}
@@ -315,7 +325,7 @@ static int faultin_page(struct task_struct *tsk, struct vm_area_struct *vma,
* reCOWed by userspace write).
*/
if ((ret & VM_FAULT_WRITE) && !(vma->vm_flags & VM_WRITE))
- *flags &= ~FOLL_WRITE;
+ *flags |= FOLL_COW;
return 0;
}