From: Konstantin Khlebnikov khlebnikov@yandex-team.ru
[ Upstream commit 1e426fe28261b03f297992e89da3320b42816f4e ]
This function is used by ptrace and proc files like /proc/pid/cmdline and /proc/pid/environ.
Access_remote_vm never returns error codes, all errors are ignored and only size of successfully read data is returned. So, if current task was killed we'll simply return 0 (bytes read).
Mmap_sem could be locked for a long time or forever if something goes wrong. Using a killable lock permits cleanup of stuck tasks and simplifies investigation.
Link: http://lkml.kernel.org/r/156007494202.3335.16782303099589302087.stgit@buzz Signed-off-by: Konstantin Khlebnikov khlebnikov@yandex-team.ru Reviewed-by: Michal Koutný mkoutny@suse.com Acked-by: Oleg Nesterov oleg@redhat.com Acked-by: Michal Hocko mhocko@suse.com Cc: Alexey Dobriyan adobriyan@gmail.com Cc: Matthew Wilcox willy@infradead.org Cc: Cyrill Gorcunov gorcunov@gmail.com Cc: Kirill Tkhai ktkhai@virtuozzo.com Cc: Al Viro viro@zeniv.linux.org.uk Cc: Roman Gushchin guro@fb.com Signed-off-by: Andrew Morton akpm@linux-foundation.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org Signed-off-by: Sasha Levin sashal@kernel.org --- mm/memory.c | 4 +++- mm/nommu.c | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/mm/memory.c b/mm/memory.c index ab650c21bccd..57402801ab09 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -4260,7 +4260,9 @@ int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, void *old_buf = buf; int write = gup_flags & FOLL_WRITE;
- down_read(&mm->mmap_sem); + if (down_read_killable(&mm->mmap_sem)) + return 0; + /* ignore errors, just check how much was successfully transferred */ while (len) { int bytes, ret, offset; diff --git a/mm/nommu.c b/mm/nommu.c index 749276beb109..1bd91ceadc82 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -1777,7 +1777,8 @@ int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, struct vm_area_struct *vma; int write = gup_flags & FOLL_WRITE;
- down_read(&mm->mmap_sem); + if (down_read_killable(&mm->mmap_sem)) + return 0;
/* the access must start within one of the target process's mappings */ vma = find_vma(mm, addr);