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

Commit 6da61809 authored by Mark Fasheh's avatar Mark Fasheh Committed by Jens Axboe
Browse files

[PATCH] Introduce generic_file_splice_write_nolock()



This allows file systems to manage their own i_mutex locking while
still re-using the generic_file_splice_write() logic.

OCFS2 in particular wants this so that it can order cluster locks within
i_mutex.

Signed-off-by: default avatarMark Fasheh <mark.fasheh@oracle.com>
Signed-off-by: default avatarJens Axboe <jens.axboe@oracle.com>
parent 62752ee1
Loading
Loading
Loading
Loading
+66 −14
Original line number Diff line number Diff line
@@ -707,13 +707,12 @@ out_ret:
 * key here is the 'actor' worker passed in that actually moves the data
 * to the wanted destination. See pipe_to_file/pipe_to_sendpage above.
 */
ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
			 loff_t *ppos, size_t len, unsigned int flags,
			 splice_actor *actor)
static ssize_t __splice_from_pipe(struct pipe_inode_info *pipe,
				  struct file *out, loff_t *ppos, size_t len,
				  unsigned int flags, splice_actor *actor)
{
	int ret, do_wakeup, err;
	struct splice_desc sd;
	struct inode *inode = out->f_mapping->host;

	ret = 0;
	do_wakeup = 0;
@@ -723,14 +722,6 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
	sd.file = out;
	sd.pos = *ppos;

	/*
	 * The actor worker might be calling ->prepare_write and
	 * ->commit_write. Most of the time, these expect i_mutex to
	 * be held. Since this may result in an ABBA deadlock with
	 * pipe->inode, we have to order lock acquiry here.
	 */
	inode_double_lock(inode, pipe->inode);

	for (;;) {
		if (pipe->nrbufs) {
			struct pipe_buffer *buf = pipe->bufs + pipe->curbuf;
@@ -803,8 +794,6 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
		pipe_wait(pipe);
	}

	inode_double_unlock(inode, pipe->inode);

	if (do_wakeup) {
		smp_mb();
		if (waitqueue_active(&pipe->wait))
@@ -815,6 +804,69 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
	return ret;
}

ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
			 loff_t *ppos, size_t len, unsigned int flags,
			 splice_actor *actor)
{
	ssize_t ret;
	struct inode *inode = out->f_mapping->host;

	/*
	 * The actor worker might be calling ->prepare_write and
	 * ->commit_write. Most of the time, these expect i_mutex to
	 * be held. Since this may result in an ABBA deadlock with
	 * pipe->inode, we have to order lock acquiry here.
	 */
	inode_double_lock(inode, pipe->inode);
	ret = __splice_from_pipe(pipe, out, ppos, len, flags, actor);
	inode_double_unlock(inode, pipe->inode);

	return ret;
}

/**
 * generic_file_splice_write_nolock - generic_file_splice_write without mutexes
 * @pipe:	pipe info
 * @out:	file to write to
 * @len:	number of bytes to splice
 * @flags:	splice modifier flags
 *
 * Will either move or copy pages (determined by @flags options) from
 * the given pipe inode to the given file. The caller is responsible
 * for acquiring i_mutex on both inodes.
 *
 */
ssize_t
generic_file_splice_write_nolock(struct pipe_inode_info *pipe, struct file *out,
				 loff_t *ppos, size_t len, unsigned int flags)
{
	struct address_space *mapping = out->f_mapping;
	struct inode *inode = mapping->host;
	ssize_t ret;
	int err;

	ret = __splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_file);
	if (ret > 0) {
		*ppos += ret;

		/*
		 * If file or inode is SYNC and we actually wrote some data,
		 * sync it.
		 */
		if (unlikely((out->f_flags & O_SYNC) || IS_SYNC(inode))) {
			err = generic_osync_inode(inode, mapping,
						  OSYNC_METADATA|OSYNC_DATA);

			if (err)
				ret = err;
		}
	}

	return ret;
}

EXPORT_SYMBOL(generic_file_splice_write_nolock);

/**
 * generic_file_splice_write - splice data from a pipe to a file
 * @pipe:	pipe info
+2 −0
Original line number Diff line number Diff line
@@ -1758,6 +1758,8 @@ extern ssize_t generic_file_splice_read(struct file *, loff_t *,
		struct pipe_inode_info *, size_t, unsigned int);
extern ssize_t generic_file_splice_write(struct pipe_inode_info *,
		struct file *, loff_t *, size_t, unsigned int);
extern ssize_t generic_file_splice_write_nolock(struct pipe_inode_info *,
		struct file *, loff_t *, size_t, unsigned int);
extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe,
		struct file *out, loff_t *, size_t len, unsigned int flags);
extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,