diff options
author | Sumit Semwal <sumit.semwal@linaro.org> | 2020-08-28 12:47:55 +0530 |
---|---|---|
committer | Sumit Semwal <sumit.semwal@linaro.org> | 2020-08-31 19:16:27 +0530 |
commit | 8b0478a367a1738080b17f9de2970b1bc6420444 (patch) | |
tree | cf6be5542d3002ddb2b9b1be566b241e4b2456e0 | |
parent | aa316726042bf5066d1a7649a57ae4c68a509ed0 (diff) |
mm: memory: Add access_remote_vm_locked variant
This allows accessing a remote vm while the mmap_lock is already
held by the caller.
While adding support for anonymous vma naming, show_map_vma()
needs to access the remote vm to get the name of the anonymous vma.
Since show_map_vma() already holds the mmap_lock, so this _locked
variant was required.
Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org>
Change-Id: I88d7823326911322833763618ccd958a4eef8e8c
-rw-r--r-- | include/linux/mm.h | 2 | ||||
-rw-r--r-- | mm/memory.c | 49 |
2 files changed, 45 insertions, 6 deletions
diff --git a/include/linux/mm.h b/include/linux/mm.h index ca6e6a81576b..e9212c0bb5ac 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1708,6 +1708,8 @@ extern int access_remote_vm(struct mm_struct *mm, unsigned long addr, void *buf, int len, unsigned int gup_flags); extern int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, unsigned long addr, void *buf, int len, unsigned int gup_flags); +extern int access_remote_vm_locked(struct mm_struct *mm, unsigned long addr, + void *buf, int len, unsigned int gup_flags); long get_user_pages_remote(struct mm_struct *mm, unsigned long start, unsigned long nr_pages, diff --git a/mm/memory.c b/mm/memory.c index 602f4283122f..207be99390e9 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -4726,17 +4726,17 @@ EXPORT_SYMBOL_GPL(generic_access_phys); /* * Access another process' address space as given in mm. If non-NULL, use the * given task for page fault accounting. + * This variant assumes that the mmap_lock is already held by the caller, so + * doesn't take the mmap_lock. */ -int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, - unsigned long addr, void *buf, int len, unsigned int gup_flags) +int __access_remote_vm_locked(struct task_struct *tsk, struct mm_struct *mm, + unsigned long addr, void *buf, int len, + unsigned int gup_flags) { struct vm_area_struct *vma; void *old_buf = buf; int write = gup_flags & FOLL_WRITE; - if (mmap_read_lock_killable(mm)) - return 0; - /* ignore errors, just check how much was successfully transferred */ while (len) { int bytes, ret, offset; @@ -4785,9 +4785,46 @@ int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, buf += bytes; addr += bytes; } + return buf - old_buf; +} + +/* + * Access another process' address space as given in mm. If non-NULL, use the + * given task for page fault accounting. + */ +int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, + unsigned long addr, void *buf, int len, unsigned int gup_flags) +{ + int ret; + + if (mmap_read_lock_killable(mm)) + return 0; + + ret = __access_remote_vm_locked(tsk, mm, addr, buf, len, gup_flags); mmap_read_unlock(mm); - return buf - old_buf; + return ret; +} + +/** + * access_remote_vm_locked - access another process' address space, without + * taking the mmap_lock. This allows nested calls from callers that already have + * taken the lock. + * + * @mm: the mm_struct of the target address space + * @addr: start address to access + * @buf: source or destination buffer + * @len: number of bytes to transfer + * @gup_flags: flags modifying lookup behaviour + * + * The caller must hold a reference on @mm, as well as hold the mmap_lock + * + * Return: number of bytes copied from source to destination. + */ +int access_remote_vm_locked(struct mm_struct *mm, unsigned long addr, void *buf, + int len, unsigned int gup_flags) +{ + return __access_remote_vm_locked(NULL, mm, addr, buf, len, gup_flags); } /** |