teach sendfile(2) to handle send-to-pipe directly
authorAl Viro <viro@zeniv.linux.org.uk>
Tue, 26 Jan 2021 03:24:28 +0000 (22:24 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Tue, 26 Jan 2021 04:29:36 +0000 (23:29 -0500)
no point going through the intermediate pipe

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/internal.h
fs/read_write.c
fs/splice.c

index 77c50befbfbe96181a616d3ac63ee6a29565d847..cff1f30cfefbe736d3455880f3fedbbba1882ffc 100644 (file)
@@ -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);
index 75f764b434184238a33f3c9bc688bfb395b83cb9..9db7adf160d206d58cefe9c308513f476bc5d6e4 100644 (file)
@@ -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);
index 74f968c65a9382011202acb781d311f3dfd4e34b..b06846f1e6ee2a2d612cd772753b239c0b3a5dc7 100644 (file)
@@ -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)