aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLorenzo Stoakes <lstoakes@gmail.com>2016-10-12 20:20:18 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-10-19 11:12:13 -0400
commit442486ec1096781c50227b73f721a63974b0fdda (patch)
tree3ceb6dcdc8cfdf930f924f6bed75b329c753b61b
parent9beae1ea89305a9667ceaab6d0bf46a045ad71e7 (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.c23
-rw-r--r--mm/nommu.c9
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 */
3871static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, 3871static 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,
3945int access_remote_vm(struct mm_struct *mm, unsigned long addr, 3942int 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,
1809EXPORT_SYMBOL(filemap_map_pages); 1809EXPORT_SYMBOL(filemap_map_pages);
1810 1810
1811static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, 1811static 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,
1853int access_remote_vm(struct mm_struct *mm, unsigned long addr, 1854int 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;