splice: fix i_mutex locking in generic_splice_write()
[linux-2.6.git] / fs / splice.c
index 349576b..a1f595b 100644 (file)
@@ -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);
-               if (pipe->inode)
-                       mutex_unlock(&pipe->inode->i_mutex);
-       }
-       mutex_unlock(&inode->i_mutex);
+       if (pipe->inode)
+               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);
+
+       if (sd.num_spliced)
+               ret = sd.num_spliced;
+
        if (ret > 0) {
                unsigned long nr_pages;