diff options
| author | John Levon <levon@movementarian.org> | 2002-07-23 20:48:18 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2002-07-23 20:48:18 -0700 |
| commit | 3b89dbbd78bb638c2691c5752ed0d54fd1a73fa1 (patch) | |
| tree | 88f26e1fc6a475d408e87d4366a5c1ad38846880 | |
| parent | d4ea8ebe21a50da6876c45d0259259d498d13eaf (diff) | |
[PATCH] consolidate task->mm code + fix
The patch below consolidates some duplicate code, reduces some
indentation, and adds a freeing of a page in mem_read() that could be left
unfreed, as far as I can see.
| -rw-r--r-- | fs/proc/array.c | 22 | ||||
| -rw-r--r-- | fs/proc/base.c | 115 | ||||
| -rw-r--r-- | include/linux/sched.h | 21 | ||||
| -rw-r--r-- | kernel/ptrace.c | 7 |
4 files changed, 81 insertions, 84 deletions
diff --git a/fs/proc/array.c b/fs/proc/array.c index e0b09b3ced45..8001f3faed1b 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -277,15 +277,11 @@ static inline char *task_cap(struct task_struct *p, char *buffer) int proc_pid_status(struct task_struct *task, char * buffer) { char * orig = buffer; - struct mm_struct *mm; + struct mm_struct *mm = get_task_mm(task); buffer = task_name(task, buffer); buffer = task_state(task, buffer); - task_lock(task); - mm = task->mm; - if(mm) - atomic_inc(&mm->mm_users); - task_unlock(task); + if (mm) { buffer = task_mem(mm, buffer); mmput(mm); @@ -481,14 +477,9 @@ static void statm_pgd_range(pgd_t * pgd, unsigned long address, unsigned long en int proc_pid_statm(struct task_struct *task, char * buffer) { - struct mm_struct *mm; int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0; + struct mm_struct *mm = get_task_mm(task); - task_lock(task); - mm = task->mm; - if(mm) - atomic_inc(&mm->mm_users); - task_unlock(task); if (mm) { struct vm_area_struct * vma; down_read(&mm->mmap_sem); @@ -626,11 +617,8 @@ ssize_t proc_pid_read_maps (struct task_struct *task, struct file * file, char * if (!tmp) goto out_free1; - task_lock(task); - mm = task->mm; - if (mm) - atomic_inc(&mm->mm_users); - task_unlock(task); + mm = get_task_mm(task); + retval = 0; if (!mm) goto out_free2; diff --git a/fs/proc/base.c b/fs/proc/base.c index c8a80b066a72..adecdb549162 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -131,16 +131,11 @@ static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsm static int proc_exe_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) { - struct mm_struct * mm; struct vm_area_struct * vma; int result = -ENOENT; struct task_struct *task = proc_task(inode); + struct mm_struct * mm = get_task_mm(task); - task_lock(task); - mm = task->mm; - if (mm) - atomic_inc(&mm->mm_users); - task_unlock(task); if (!mm) goto out; down_read(&mm->mmap_sem); @@ -203,13 +198,8 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf static int proc_pid_environ(struct task_struct *task, char * buffer) { - struct mm_struct *mm; int res = 0; - task_lock(task); - mm = task->mm; - if (mm) - atomic_inc(&mm->mm_users); - task_unlock(task); + struct mm_struct *mm = get_task_mm(task); if (mm) { int len = mm->env_end - mm->env_start; if (len > PAGE_SIZE) @@ -222,38 +212,36 @@ static int proc_pid_environ(struct task_struct *task, char * buffer) static int proc_pid_cmdline(struct task_struct *task, char * buffer) { - struct mm_struct *mm; int res = 0; - task_lock(task); - mm = task->mm; - if (mm) - atomic_inc(&mm->mm_users); - task_unlock(task); - if (mm) { - int len = mm->arg_end - mm->arg_start; - if (len > PAGE_SIZE) - len = PAGE_SIZE; - res = access_process_vm(task, mm->arg_start, buffer, len, 0); - // If the nul at the end of args has been overwritten, then - // assume application is using setproctitle(3). - if ( res > 0 && buffer[res-1] != '\0' ) - { - len = strnlen( buffer, res ); - if ( len < res ) - { - res = len; - } - else - { - len = mm->env_end - mm->env_start; - if (len > PAGE_SIZE - res) - len = PAGE_SIZE - res; - res += access_process_vm(task, mm->env_start, buffer+res, len, 0); - res = strnlen( buffer, res ); - } + int len; + struct mm_struct *mm = get_task_mm(task); + if (!mm) + goto out; + + len = mm->arg_end - mm->arg_start; + + if (len > PAGE_SIZE) + len = PAGE_SIZE; + + res = access_process_vm(task, mm->arg_start, buffer, len, 0); + + // If the nul at the end of args has been overwritten, then + // assume application is using setproctitle(3). + if (res > 0 && buffer[res-1] != '\0') { + len = strnlen(buffer, res); + if (len < res) { + res = len; + } else { + len = mm->env_end - mm->env_start; + if (len > PAGE_SIZE - res) + len = PAGE_SIZE - res; + res += access_process_vm(task, mm->env_start, buffer+res, len, 0); + res = strnlen(buffer, res); } - mmput(mm); } + mmput(mm); + +out: return res; } @@ -421,54 +409,59 @@ static ssize_t mem_read(struct file * file, char * buf, struct task_struct *task = proc_task(file->f_dentry->d_inode); char *page; unsigned long src = *ppos; - int copied = 0; + int ret = -ESRCH; struct mm_struct *mm; - if (!MAY_PTRACE(task)) - return -ESRCH; + goto out; + ret = -ENOMEM; page = (char *)__get_free_page(GFP_USER); if (!page) - return -ENOMEM; + goto out; - task_lock(task); - mm = task->mm; - if (mm) - atomic_inc(&mm->mm_users); - task_unlock(task); + ret = 0; + + mm = get_task_mm(task); if (!mm) - return 0; + goto out_free; - if (file->private_data != (void*)((long)current->self_exec_id) ) { - mmput(mm); - return -EIO; - } - + ret = -EIO; + + if (file->private_data != (void*)((long)current->self_exec_id)) + goto out_put; + ret = 0; + while (count > 0) { int this_len, retval; this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; retval = access_process_vm(task, src, page, this_len, 0); if (!retval) { - if (!copied) - copied = -EIO; + if (!ret) + ret = -EIO; break; } + if (copy_to_user(buf, page, retval)) { - copied = -EFAULT; + ret = -EFAULT; break; } - copied += retval; + + ret += retval; src += retval; buf += retval; count -= retval; } *ppos = src; + +out_put: mmput(mm); +out_free: free_page((unsigned long) page); - return copied; +out: + return ret; } #define mem_write NULL diff --git a/include/linux/sched.h b/include/linux/sched.h index 1d288587e44d..004d2a129ca4 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -810,6 +810,27 @@ static inline char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt, return res; } + +/** + * get_task_mm - acquire a reference to the task's mm + * + * Returns %NULL if the task has no mm. User must release + * the mm via mmput() after use. + */ +static inline struct mm_struct * get_task_mm(struct task_struct * task) +{ + struct mm_struct * mm; + + task_lock(task); + mm = task->mm; + if (mm) + atomic_inc(&mm->mm_users); + task_unlock(task); + + return mm; +} + + /* set thread flags in other task's structures * - see asm/thread_info.h for TIF_xxxx flags available */ diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 1a64a0c03b95..f6d76247cde3 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -124,12 +124,7 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, in struct page *page; void *old_buf = buf; - /* Worry about races with exit() */ - task_lock(tsk); - mm = tsk->mm; - if (mm) - atomic_inc(&mm->mm_users); - task_unlock(tsk); + mm = get_task_mm(tsk); if (!mm) return 0; |
