diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2016-12-10 23:06:39 -0800 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2016-12-10 23:06:38 -0800 |
commit | 35640cdd7ee81aad5dfa458d279f03b6afc5536a (patch) | |
tree | 100eddeabe699928d773358390a7a30f2561527c | |
parent | b6dff5ca3ca76306ad18b437e484cf3289108a33 (diff) | |
parent | b40f04674056d89de6f98ca944bae8cd4c320b71 (diff) |
Merge "mm: remove gup_flags FOLL_WRITE games from __get_user_pages()"
-rw-r--r-- | include/linux/mm.h | 1 | ||||
-rw-r--r-- | mm/gup.c | 14 |
2 files changed, 13 insertions, 2 deletions
diff --git a/include/linux/mm.h b/include/linux/mm.h index 6c1ea7f327c4..0c4178e5b656 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2128,6 +2128,7 @@ static inline struct page *follow_page(struct vm_area_struct *vma, #define FOLL_MIGRATION 0x400 /* wait for page to replace migration entry */ #define FOLL_TRIED 0x800 /* a retry, previous pass started an IO */ #define FOLL_MLOCK 0x1000 /* lock present pages */ +#define FOLL_COW 0x4000 /* internal GUP flag */ typedef int (*pte_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr, void *data); @@ -58,6 +58,16 @@ static int follow_pfn_pte(struct vm_area_struct *vma, unsigned long address, return -EEXIST; } +/* + * 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) { @@ -92,7 +102,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; } @@ -352,7 +362,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; } |