[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>
This commit is contained in:
80
fs/splice.c
80
fs/splice.c
@@ -707,13 +707,12 @@ out_ret:
|
|||||||
* key here is the 'actor' worker passed in that actually moves the data
|
* 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.
|
* 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,
|
static ssize_t __splice_from_pipe(struct pipe_inode_info *pipe,
|
||||||
loff_t *ppos, size_t len, unsigned int flags,
|
struct file *out, loff_t *ppos, size_t len,
|
||||||
splice_actor *actor)
|
unsigned int flags, splice_actor *actor)
|
||||||
{
|
{
|
||||||
int ret, do_wakeup, err;
|
int ret, do_wakeup, err;
|
||||||
struct splice_desc sd;
|
struct splice_desc sd;
|
||||||
struct inode *inode = out->f_mapping->host;
|
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
do_wakeup = 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.file = out;
|
||||||
sd.pos = *ppos;
|
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 (;;) {
|
for (;;) {
|
||||||
if (pipe->nrbufs) {
|
if (pipe->nrbufs) {
|
||||||
struct pipe_buffer *buf = pipe->bufs + pipe->curbuf;
|
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);
|
pipe_wait(pipe);
|
||||||
}
|
}
|
||||||
|
|
||||||
inode_double_unlock(inode, pipe->inode);
|
|
||||||
|
|
||||||
if (do_wakeup) {
|
if (do_wakeup) {
|
||||||
smp_mb();
|
smp_mb();
|
||||||
if (waitqueue_active(&pipe->wait))
|
if (waitqueue_active(&pipe->wait))
|
||||||
@@ -815,6 +804,69 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
|
|||||||
return ret;
|
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
|
* generic_file_splice_write - splice data from a pipe to a file
|
||||||
* @pipe: pipe info
|
* @pipe: pipe info
|
||||||
|
@@ -1758,6 +1758,8 @@ extern ssize_t generic_file_splice_read(struct file *, loff_t *,
|
|||||||
struct pipe_inode_info *, size_t, unsigned int);
|
struct pipe_inode_info *, size_t, unsigned int);
|
||||||
extern ssize_t generic_file_splice_write(struct pipe_inode_info *,
|
extern ssize_t generic_file_splice_write(struct pipe_inode_info *,
|
||||||
struct file *, loff_t *, size_t, unsigned int);
|
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,
|
extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe,
|
||||||
struct file *out, loff_t *, size_t len, unsigned int flags);
|
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,
|
extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
|
||||||
|
Reference in New Issue
Block a user