diff options
| author | Miklos Szeredi <miklos@szeredi.hu> | 2009-04-14 19:48:38 +0200 | 
|---|---|---|
| committer | Jens Axboe <jens.axboe@oracle.com> | 2009-04-15 12:10:11 +0200 | 
| commit | eb443e5a25d43996deb62b9bcee1a4ce5dea2ead (patch) | |
| tree | 7f63bb98302137e249904d608d5bb4b919a987ed | |
| parent | 2933970b960223076d6affcf7a77e2bc546b8102 (diff) | |
| download | olio-linux-3.10-eb443e5a25d43996deb62b9bcee1a4ce5dea2ead.tar.xz olio-linux-3.10-eb443e5a25d43996deb62b9bcee1a4ce5dea2ead.zip  | |
splice: fix i_mutex locking in generic_splice_write()
Rearrange locking of i_mutex on destination so it's only held while
buffers are copied with the pipe_to_file() actor, and not while
waiting for more data on the pipe.
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
| -rw-r--r-- | fs/splice.c | 34 | 
1 files changed, 23 insertions, 11 deletions
diff --git a/fs/splice.c b/fs/splice.c index 349576b2c75..a1f595b9db4 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -895,17 +895,29 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out,  	};  	ssize_t ret; -	WARN_ON(S_ISFIFO(inode->i_mode)); -	mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT); -	ret = file_remove_suid(out); -	if (likely(!ret)) { -		if (pipe->inode) -			mutex_lock_nested(&pipe->inode->i_mutex, I_MUTEX_CHILD); -		ret = __splice_from_pipe(pipe, &sd, pipe_to_file); -		if (pipe->inode) -			mutex_unlock(&pipe->inode->i_mutex); -	} -	mutex_unlock(&inode->i_mutex); +	if (pipe->inode) +		mutex_lock_nested(&pipe->inode->i_mutex, I_MUTEX_PARENT); + +	splice_from_pipe_begin(&sd); +	do { +		ret = splice_from_pipe_next(pipe, &sd); +		if (ret <= 0) +			break; + +		mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD); +		ret = file_remove_suid(out); +		if (!ret) +			ret = splice_from_pipe_feed(pipe, &sd, pipe_to_file); +		mutex_unlock(&inode->i_mutex); +	} while (ret > 0); +	splice_from_pipe_end(pipe, &sd); + +	if (pipe->inode) +		mutex_unlock(&pipe->inode->i_mutex); + +	if (sd.num_spliced) +		ret = sd.num_spliced; +  	if (ret > 0) {  		unsigned long nr_pages;  |