no point going through the intermediate pipe

Signed-off-by: Al Viro <[email protected]>
---
 fs/internal.h   |  9 +++++++++
 fs/read_write.c | 19 +++++++++++++------
 fs/splice.c     |  2 +-
 3 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/fs/internal.h b/fs/internal.h
index 77c50befbfbe..cff1f30cfefb 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -15,6 +15,7 @@ struct mount;
 struct shrink_control;
 struct fs_context;
 struct user_namespace;
+struct pipe_inode_info;
 
 /*
  * block_dev.c
@@ -193,3 +194,11 @@ int sb_init_dio_done_wq(struct super_block *sb);
  */
 int do_statx(int dfd, const char __user *filename, unsigned flags,
             unsigned int mask, struct statx __user *buffer);
+
+/*
+ * fs/splice.c:
+ */
+long splice_file_to_pipe(struct file *in,
+                        struct pipe_inode_info *opipe,
+                        loff_t *offset,
+                        size_t len, unsigned int flags);
diff --git a/fs/read_write.c b/fs/read_write.c
index 75f764b43418..9db7adf160d2 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -1188,6 +1188,7 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t 
*ppos,
 {
        struct fd in, out;
        struct inode *in_inode, *out_inode;
+       struct pipe_inode_info *opipe;
        loff_t pos;
        loff_t out_pos;
        ssize_t retval;
@@ -1228,9 +1229,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t 
*ppos,
        in_inode = file_inode(in.file);
        out_inode = file_inode(out.file);
        out_pos = out.file->f_pos;
-       retval = rw_verify_area(WRITE, out.file, &out_pos, count);
-       if (retval < 0)
-               goto fput_out;
 
        if (!max)
                max = min(in_inode->i_sb->s_maxbytes, 
out_inode->i_sb->s_maxbytes);
@@ -1253,9 +1251,18 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t 
*ppos,
        if (in.file->f_flags & O_NONBLOCK)
                fl = SPLICE_F_NONBLOCK;
 #endif
-       file_start_write(out.file);
-       retval = do_splice_direct(in.file, &pos, out.file, &out_pos, count, fl);
-       file_end_write(out.file);
+       opipe = get_pipe_info(out.file, true);
+       if (!opipe) {
+               retval = rw_verify_area(WRITE, out.file, &out_pos, count);
+               if (retval < 0)
+                       goto fput_out;
+               file_start_write(out.file);
+               retval = do_splice_direct(in.file, &pos, out.file, &out_pos,
+                                         count, fl);
+               file_end_write(out.file);
+       } else {
+               retval = splice_file_to_pipe(in.file, opipe, &pos, count, fl);
+       }
 
        if (retval > 0) {
                add_rchar(current, retval);
diff --git a/fs/splice.c b/fs/splice.c
index 74f968c65a93..b06846f1e6ee 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -1002,7 +1002,7 @@ static int splice_pipe_to_pipe(struct pipe_inode_info 
*ipipe,
                               struct pipe_inode_info *opipe,
                               size_t len, unsigned int flags);
 
-static long splice_file_to_pipe(struct file *in,
+long splice_file_to_pipe(struct file *in,
                         struct pipe_inode_info *opipe,
                         loff_t *offset,
                         size_t len, unsigned int flags)
-- 
2.11.0

Reply via email to