]> git.hungrycats.org Git - linux/commitdiff
splice: fix i_mutex locking in generic_splice_write()
authorMiklos Szeredi <miklos@szeredi.hu>
Tue, 14 Apr 2009 17:48:38 +0000 (19:48 +0200)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 18 May 2009 23:35:23 +0000 (16:35 -0700)
commit eb443e5a25d43996deb62b9bcee1a4ce5dea2ead upstream.

Rearrange locking of i_mutex on destination so it's only held while
buffers are copied with the pipe_to_file() actor, and not while
waiting for more data on the pipe.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
fs/splice.c

index f88614d4a928c035f2c2ff743ad21038f0ebe67b..dcc2fe0a22e8398015b988bd3c580d1b711b6d86 100644 (file)
@@ -894,17 +894,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;