diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2021-01-25 22:24:28 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2021-01-25 23:29:36 -0500 |
commit | b964bf53e540262f2d12672b3cca10842c0172e7 (patch) | |
tree | 16eb741d38b54ce88cc282331579ecec09115b7a | |
parent | faa97c48c33454ac0107db930a491b692dd1dff1 (diff) | |
download | linux-b964bf53e540262f2d12672b3cca10842c0172e7.tar.bz2 |
teach sendfile(2) to handle send-to-pipe directly
no point going through the intermediate pipe
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/internal.h | 9 | ||||
-rw-r--r-- | fs/read_write.c | 19 | ||||
-rw-r--r-- | 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) |