aboutsummaryrefslogtreecommitdiff
path: root/fs/splice.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2009-04-08 10:35:30 +0200
committerIngo Molnar <mingo@elte.hu>2009-04-08 10:35:30 +0200
commit5ea472a77f8e4811ceee3f44a9deda6ad6e8b789 (patch)
treea9ec5019e2b666a19874fc344ffb0dd5da6bce94 /fs/splice.c
parent6c009ecef8cca28c7c09eb16d0802e37915a76e1 (diff)
parent577c9c456f0e1371cbade38eaf91ae8e8a308555 (diff)
Merge commit 'v2.6.30-rc1' into perfcounters/core
Conflicts: arch/powerpc/include/asm/systbl.h arch/powerpc/include/asm/unistd.h include/linux/init_task.h Merge reason: the conflicts are non-trivial: PowerPC placement of sys_perf_counter_open has to be mixed with the new preadv/pwrite syscalls. Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'fs/splice.c')
-rw-r--r--fs/splice.c25
1 files changed, 20 insertions, 5 deletions
diff --git a/fs/splice.c b/fs/splice.c
index dd727d43e5b..c18aa7e03e2 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -737,10 +737,19 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
* ->write_end. 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.
+ *
+ * Outer lock must be inode->i_mutex, as pipe_wait() will
+ * release and reacquire pipe->inode->i_mutex, AND inode must
+ * never be a pipe.
*/
- inode_double_lock(inode, pipe->inode);
+ WARN_ON(S_ISFIFO(inode->i_mode));
+ mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT);
+ if (pipe->inode)
+ mutex_lock_nested(&pipe->inode->i_mutex, I_MUTEX_CHILD);
ret = __splice_from_pipe(pipe, &sd, actor);
- inode_double_unlock(inode, pipe->inode);
+ if (pipe->inode)
+ mutex_unlock(&pipe->inode->i_mutex);
+ mutex_unlock(&inode->i_mutex);
return ret;
}
@@ -831,11 +840,17 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
};
ssize_t ret;
- inode_double_lock(inode, pipe->inode);
+ 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 (likely(!ret)) {
+ if (pipe->inode)
+ mutex_lock_nested(&pipe->inode->i_mutex, I_MUTEX_CHILD);
ret = __splice_from_pipe(pipe, &sd, pipe_to_file);
- inode_double_unlock(inode, pipe->inode);
+ if (pipe->inode)
+ mutex_unlock(&pipe->inode->i_mutex);
+ }
+ mutex_unlock(&inode->i_mutex);
if (ret > 0) {
unsigned long nr_pages;