diff options
author | Lorenzo Stoakes <lstoakes@gmail.com> | 2016-10-12 20:20:18 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-19 11:12:13 -0400 |
commit | 442486ec1096781c50227b73f721a63974b0fdda (patch) | |
tree | 3ceb6dcdc8cfdf930f924f6bed75b329c753b61b | |
parent | 9beae1ea89305a9667ceaab6d0bf46a045ad71e7 (diff) |
mm: replace __access_remote_vm() write parameter with gup_flags
This removes the 'write' argument from __access_remote_vm() and replaces
it with 'gup_flags' as use of this function previously silently implied
FOLL_FORCE, whereas after this patch callers explicitly pass this flag.
We make this explicit as use of FOLL_FORCE can result in surprising
behaviour (and hence bugs) within the mm subsystem.
Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | mm/memory.c | 23 | ||||
-rw-r--r-- | mm/nommu.c | 9 |
2 files changed, 21 insertions, 11 deletions
diff --git a/mm/memory.c b/mm/memory.c index 20a9adb7b36e..79ebed3a4c2b 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -3869,14 +3869,11 @@ EXPORT_SYMBOL_GPL(generic_access_phys); | |||
3869 | * given task for page fault accounting. | 3869 | * given task for page fault accounting. |
3870 | */ | 3870 | */ |
3871 | static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, | 3871 | static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, |
3872 | unsigned long addr, void *buf, int len, int write) | 3872 | unsigned long addr, void *buf, int len, unsigned int gup_flags) |
3873 | { | 3873 | { |
3874 | struct vm_area_struct *vma; | 3874 | struct vm_area_struct *vma; |
3875 | void *old_buf = buf; | 3875 | void *old_buf = buf; |
3876 | unsigned int flags = FOLL_FORCE; | 3876 | int write = gup_flags & FOLL_WRITE; |
3877 | |||
3878 | if (write) | ||
3879 | flags |= FOLL_WRITE; | ||
3880 | 3877 | ||
3881 | down_read(&mm->mmap_sem); | 3878 | down_read(&mm->mmap_sem); |
3882 | /* ignore errors, just check how much was successfully transferred */ | 3879 | /* ignore errors, just check how much was successfully transferred */ |
@@ -3886,7 +3883,7 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, | |||
3886 | struct page *page = NULL; | 3883 | struct page *page = NULL; |
3887 | 3884 | ||
3888 | ret = get_user_pages_remote(tsk, mm, addr, 1, | 3885 | ret = get_user_pages_remote(tsk, mm, addr, 1, |
3889 | flags, &page, &vma); | 3886 | gup_flags, &page, &vma); |
3890 | if (ret <= 0) { | 3887 | if (ret <= 0) { |
3891 | #ifndef CONFIG_HAVE_IOREMAP_PROT | 3888 | #ifndef CONFIG_HAVE_IOREMAP_PROT |
3892 | break; | 3889 | break; |
@@ -3945,7 +3942,12 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, | |||
3945 | int access_remote_vm(struct mm_struct *mm, unsigned long addr, | 3942 | int access_remote_vm(struct mm_struct *mm, unsigned long addr, |
3946 | void *buf, int len, int write) | 3943 | void *buf, int len, int write) |
3947 | { | 3944 | { |
3948 | return __access_remote_vm(NULL, mm, addr, buf, len, write); | 3945 | unsigned int flags = FOLL_FORCE; |
3946 | |||
3947 | if (write) | ||
3948 | flags |= FOLL_WRITE; | ||
3949 | |||
3950 | return __access_remote_vm(NULL, mm, addr, buf, len, flags); | ||
3949 | } | 3951 | } |
3950 | 3952 | ||
3951 | /* | 3953 | /* |
@@ -3958,12 +3960,17 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, | |||
3958 | { | 3960 | { |
3959 | struct mm_struct *mm; | 3961 | struct mm_struct *mm; |
3960 | int ret; | 3962 | int ret; |
3963 | unsigned int flags = FOLL_FORCE; | ||
3961 | 3964 | ||
3962 | mm = get_task_mm(tsk); | 3965 | mm = get_task_mm(tsk); |
3963 | if (!mm) | 3966 | if (!mm) |
3964 | return 0; | 3967 | return 0; |
3965 | 3968 | ||
3966 | ret = __access_remote_vm(tsk, mm, addr, buf, len, write); | 3969 | if (write) |
3970 | flags |= FOLL_WRITE; | ||
3971 | |||
3972 | ret = __access_remote_vm(tsk, mm, addr, buf, len, flags); | ||
3973 | |||
3967 | mmput(mm); | 3974 | mmput(mm); |
3968 | 3975 | ||
3969 | return ret; | 3976 | return ret; |
diff --git a/mm/nommu.c b/mm/nommu.c index 70cb844dfd95..bde7df35118b 100644 --- a/mm/nommu.c +++ b/mm/nommu.c | |||
@@ -1809,9 +1809,10 @@ void filemap_map_pages(struct fault_env *fe, | |||
1809 | EXPORT_SYMBOL(filemap_map_pages); | 1809 | EXPORT_SYMBOL(filemap_map_pages); |
1810 | 1810 | ||
1811 | static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, | 1811 | static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, |
1812 | unsigned long addr, void *buf, int len, int write) | 1812 | unsigned long addr, void *buf, int len, unsigned int gup_flags) |
1813 | { | 1813 | { |
1814 | struct vm_area_struct *vma; | 1814 | struct vm_area_struct *vma; |
1815 | int write = gup_flags & FOLL_WRITE; | ||
1815 | 1816 | ||
1816 | down_read(&mm->mmap_sem); | 1817 | down_read(&mm->mmap_sem); |
1817 | 1818 | ||
@@ -1853,7 +1854,8 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, | |||
1853 | int access_remote_vm(struct mm_struct *mm, unsigned long addr, | 1854 | int access_remote_vm(struct mm_struct *mm, unsigned long addr, |
1854 | void *buf, int len, int write) | 1855 | void *buf, int len, int write) |
1855 | { | 1856 | { |
1856 | return __access_remote_vm(NULL, mm, addr, buf, len, write); | 1857 | return __access_remote_vm(NULL, mm, addr, buf, len, |
1858 | write ? FOLL_WRITE : 0); | ||
1857 | } | 1859 | } |
1858 | 1860 | ||
1859 | /* | 1861 | /* |
@@ -1871,7 +1873,8 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, in | |||
1871 | if (!mm) | 1873 | if (!mm) |
1872 | return 0; | 1874 | return 0; |
1873 | 1875 | ||
1874 | len = __access_remote_vm(tsk, mm, addr, buf, len, write); | 1876 | len = __access_remote_vm(tsk, mm, addr, buf, len, |
1877 | write ? FOLL_WRITE : 0); | ||
1875 | 1878 | ||
1876 | mmput(mm); | 1879 | mmput(mm); |
1877 | return len; | 1880 | return len; |