Commit eb443e5a authored by Miklos Szeredi's avatar Miklos Szeredi Committed by Jens Axboe

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: default avatarMiklos Szeredi <mszeredi@suse.cz>
Signed-off-by: default avatarJens Axboe <jens.axboe@oracle.com>
parent 2933970b
...@@ -895,17 +895,29 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, ...@@ -895,17 +895,29 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
}; };
ssize_t ret; ssize_t ret;
WARN_ON(S_ISFIFO(inode->i_mode)); if (pipe->inode)
mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT); mutex_lock_nested(&pipe->inode->i_mutex, I_MUTEX_PARENT);
ret = file_remove_suid(out);
if (likely(!ret)) { splice_from_pipe_begin(&sd);
if (pipe->inode) do {
mutex_lock_nested(&pipe->inode->i_mutex, I_MUTEX_CHILD); ret = splice_from_pipe_next(pipe, &sd);
ret = __splice_from_pipe(pipe, &sd, pipe_to_file); if (ret <= 0)
if (pipe->inode) break;
mutex_unlock(&pipe->inode->i_mutex);
} mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
mutex_unlock(&inode->i_mutex); 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) { if (ret > 0) {
unsigned long nr_pages; unsigned long nr_pages;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment