Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+23 −11
Original line number Diff line number Diff line
@@ -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);
		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);
	}
	mutex_unlock(&inode->i_mutex);

	if (sd.num_spliced)
		ret = sd.num_spliced;

	if (ret > 0) {
		unsigned long nr_pages;