diff options
| author | Grant Likely <grant.likely@secretlab.ca> | 2012-02-28 13:48:58 -0600 | 
|---|---|---|
| committer | Grant Likely <grant.likely@secretlab.ca> | 2012-02-28 13:48:58 -0600 | 
| commit | b3950d50cfc343b3e7dc5c69c96a61b182fd1e37 (patch) | |
| tree | d54affae2b1e25464493b48aa88cd8d6b4770812 /fs/proc/base.c | |
| parent | daefd89efc279b142bbb054577c2d706da211723 (diff) | |
| parent | 280ad7fda5f95211857fda38960f2b6fdf6edd3e (diff) | |
| download | olio-linux-3.10-b3950d50cfc343b3e7dc5c69c96a61b182fd1e37.tar.xz olio-linux-3.10-b3950d50cfc343b3e7dc5c69c96a61b182fd1e37.zip  | |
Merge branch 'irqdomain/next' into gpio/next
Diffstat (limited to 'fs/proc/base.c')
| -rw-r--r-- | fs/proc/base.c | 126 | 
1 files changed, 46 insertions, 80 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index 9cde9edf9c4..d4548dd49b0 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -198,26 +198,6 @@ static int proc_root_link(struct dentry *dentry, struct path *path)  	return result;  } -static struct mm_struct *mm_access(struct task_struct *task, unsigned int mode) -{ -	struct mm_struct *mm; -	int err; - -	err =  mutex_lock_killable(&task->signal->cred_guard_mutex); -	if (err) -		return ERR_PTR(err); - -	mm = get_task_mm(task); -	if (mm && mm != current->mm && -			!ptrace_may_access(task, mode)) { -		mmput(mm); -		mm = ERR_PTR(-EACCES); -	} -	mutex_unlock(&task->signal->cred_guard_mutex); - -	return mm; -} -  struct mm_struct *mm_for_maps(struct task_struct *task)  {  	return mm_access(task, PTRACE_MODE_READ); @@ -711,6 +691,13 @@ static int mem_open(struct inode* inode, struct file* file)  	if (IS_ERR(mm))  		return PTR_ERR(mm); +	if (mm) { +		/* ensure this mm_struct can't be freed */ +		atomic_inc(&mm->mm_count); +		/* but do not pin its memory */ +		mmput(mm); +	} +  	/* OK to pass negative loff_t, we can catch out-of-range */  	file->f_mode |= FMODE_UNSIGNED_OFFSET;  	file->private_data = mm; @@ -718,57 +705,13 @@ static int mem_open(struct inode* inode, struct file* file)  	return 0;  } -static ssize_t mem_read(struct file * file, char __user * buf, -			size_t count, loff_t *ppos) +static ssize_t mem_rw(struct file *file, char __user *buf, +			size_t count, loff_t *ppos, int write)  { -	int ret; -	char *page; -	unsigned long src = *ppos;  	struct mm_struct *mm = file->private_data; - -	if (!mm) -		return 0; - -	page = (char *)__get_free_page(GFP_TEMPORARY); -	if (!page) -		return -ENOMEM; - -	ret = 0; -  -	while (count > 0) { -		int this_len, retval; - -		this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; -		retval = access_remote_vm(mm, src, page, this_len, 0); -		if (!retval) { -			if (!ret) -				ret = -EIO; -			break; -		} - -		if (copy_to_user(buf, page, retval)) { -			ret = -EFAULT; -			break; -		} -  -		ret += retval; -		src += retval; -		buf += retval; -		count -= retval; -	} -	*ppos = src; - -	free_page((unsigned long) page); -	return ret; -} - -static ssize_t mem_write(struct file * file, const char __user *buf, -			 size_t count, loff_t *ppos) -{ -	int copied; +	unsigned long addr = *ppos; +	ssize_t copied;  	char *page; -	unsigned long dst = *ppos; -	struct mm_struct *mm = file->private_data;  	if (!mm)  		return 0; @@ -778,31 +721,54 @@ static ssize_t mem_write(struct file * file, const char __user *buf,  		return -ENOMEM;  	copied = 0; +	if (!atomic_inc_not_zero(&mm->mm_users)) +		goto free; +  	while (count > 0) { -		int this_len, retval; +		int this_len = min_t(int, count, PAGE_SIZE); -		this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; -		if (copy_from_user(page, buf, this_len)) { +		if (write && copy_from_user(page, buf, this_len)) {  			copied = -EFAULT;  			break;  		} -		retval = access_remote_vm(mm, dst, page, this_len, 1); -		if (!retval) { + +		this_len = access_remote_vm(mm, addr, page, this_len, write); +		if (!this_len) {  			if (!copied)  				copied = -EIO;  			break;  		} -		copied += retval; -		buf += retval; -		dst += retval; -		count -= retval;			 + +		if (!write && copy_to_user(buf, page, this_len)) { +			copied = -EFAULT; +			break; +		} + +		buf += this_len; +		addr += this_len; +		copied += this_len; +		count -= this_len;  	} -	*ppos = dst; +	*ppos = addr; +	mmput(mm); +free:  	free_page((unsigned long) page);  	return copied;  } +static ssize_t mem_read(struct file *file, char __user *buf, +			size_t count, loff_t *ppos) +{ +	return mem_rw(file, buf, count, ppos, 0); +} + +static ssize_t mem_write(struct file *file, const char __user *buf, +			 size_t count, loff_t *ppos) +{ +	return mem_rw(file, (char __user*)buf, count, ppos, 1); +} +  loff_t mem_lseek(struct file *file, loff_t offset, int orig)  {  	switch (orig) { @@ -822,8 +788,8 @@ loff_t mem_lseek(struct file *file, loff_t offset, int orig)  static int mem_release(struct inode *inode, struct file *file)  {  	struct mm_struct *mm = file->private_data; - -	mmput(mm); +	if (mm) +		mmdrop(mm);  	return 0;  }  |