diff options
author | Mark Fasheh <mark.fasheh@oracle.com> | 2006-10-17 18:43:07 +0200 |
---|---|---|
committer | Jens Axboe <axboe@nelson.home.kernel.dk> | 2006-10-19 20:53:08 +0200 |
commit | 6da61809822c22634a3de2dcb3c60283b836a88a (patch) | |
tree | 80bc4105a4eabb221e5b1896b2c8b915a9c90d28 /fs/splice.c | |
parent | 62752ee198dca9209b7dee504763e51b11e9e0ca (diff) | |
download | lwn-6da61809822c22634a3de2dcb3c60283b836a88a.tar.gz lwn-6da61809822c22634a3de2dcb3c60283b836a88a.zip |
[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: Mark Fasheh <mark.fasheh@oracle.com>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'fs/splice.c')
-rw-r--r-- | fs/splice.c | 80 |
1 files changed, 66 insertions, 14 deletions
diff --git a/fs/splice.c b/fs/splice.c index c1072b6940c3..68e20e65c6e1 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -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 |