aboutsummaryrefslogtreecommitdiffstats
path: root/fs/splice.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/splice.c')
-rw-r--r--fs/splice.c142
1 files changed, 138 insertions, 4 deletions
diff --git a/fs/splice.c b/fs/splice.c
index 3bd9cb21b38e..eefd96b1d7fb 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -535,6 +535,21 @@ static ssize_t kernel_readv(struct file *file, const struct iovec *vec,
535 return res; 535 return res;
536} 536}
537 537
538static ssize_t kernel_writev(struct file *file, const struct iovec *vec,
539 unsigned long vlen, loff_t *ppos)
540{
541 mm_segment_t old_fs;
542 ssize_t res;
543
544 old_fs = get_fs();
545 set_fs(get_ds());
546 /* The cast to a user pointer is valid due to the set_fs() */
547 res = vfs_writev(file, (const struct iovec __user *)vec, vlen, ppos);
548 set_fs(old_fs);
549
550 return res;
551}
552
538ssize_t default_file_splice_read(struct file *in, loff_t *ppos, 553ssize_t default_file_splice_read(struct file *in, loff_t *ppos,
539 struct pipe_inode_info *pipe, size_t len, 554 struct pipe_inode_info *pipe, size_t len,
540 unsigned int flags) 555 unsigned int flags)
@@ -988,6 +1003,122 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
988 1003
989EXPORT_SYMBOL(generic_file_splice_write); 1004EXPORT_SYMBOL(generic_file_splice_write);
990 1005
1006static struct pipe_buffer *nth_pipe_buf(struct pipe_inode_info *pipe, int n)
1007{
1008 return &pipe->bufs[(pipe->curbuf + n) % PIPE_BUFFERS];
1009}
1010
1011static ssize_t default_file_splice_write(struct pipe_inode_info *pipe,
1012 struct file *out, loff_t *ppos,
1013 size_t len, unsigned int flags)
1014{
1015 ssize_t ret = 0;
1016 ssize_t total_len = 0;
1017 int do_wakeup = 0;
1018
1019 pipe_lock(pipe);
1020 while (len) {
1021 struct pipe_buffer *buf;
1022 void *data[PIPE_BUFFERS];
1023 struct iovec vec[PIPE_BUFFERS];
1024 unsigned int nr_pages = 0;
1025 unsigned int write_len = 0;
1026 unsigned int now_len = len;
1027 unsigned int this_len;
1028 int i;
1029
1030 BUG_ON(pipe->nrbufs > PIPE_BUFFERS);
1031 for (i = 0; i < pipe->nrbufs && now_len; i++) {
1032 buf = nth_pipe_buf(pipe, i);
1033
1034 ret = buf->ops->confirm(pipe, buf);
1035 if (ret)
1036 break;
1037
1038 data[i] = buf->ops->map(pipe, buf, 0);
1039 this_len = min(buf->len, now_len);
1040 vec[i].iov_base = (void __user *) data[i] + buf->offset;
1041 vec[i].iov_len = this_len;
1042 now_len -= this_len;
1043 write_len += this_len;
1044 nr_pages++;
1045 }
1046
1047 if (nr_pages) {
1048 ret = kernel_writev(out, vec, nr_pages, ppos);
1049 if (ret == 0)
1050 ret = -EIO;
1051 if (ret > 0) {
1052 len -= ret;
1053 total_len += ret;
1054 }
1055 }
1056
1057 for (i = 0; i < nr_pages; i++) {
1058 buf = nth_pipe_buf(pipe, i);
1059 buf->ops->unmap(pipe, buf, data[i]);
1060
1061 if (ret > 0) {
1062 this_len = min_t(unsigned, vec[i].iov_len, ret);
1063 buf->offset += this_len;
1064 buf->len -= this_len;
1065 ret -= this_len;
1066 }
1067 }
1068
1069 if (ret < 0)
1070 break;
1071
1072 while (pipe->nrbufs) {
1073 const struct pipe_buf_operations *ops;
1074
1075 buf = nth_pipe_buf(pipe, 0);
1076 if (buf->len)
1077 break;
1078
1079 ops = buf->ops;
1080 buf->ops = NULL;
1081 ops->release(pipe, buf);
1082 pipe->curbuf = (pipe->curbuf + 1) % PIPE_BUFFERS;
1083 pipe->nrbufs--;
1084 if (pipe->inode)
1085 do_wakeup = 1;
1086 }
1087
1088 if (pipe->nrbufs)
1089 continue;
1090 if (!pipe->writers)
1091 break;
1092 if (!pipe->waiting_writers) {
1093 if (total_len)
1094 break;
1095 }
1096
1097 if (flags & SPLICE_F_NONBLOCK) {
1098 ret = -EAGAIN;
1099 break;
1100 }
1101
1102 if (signal_pending(current)) {
1103 ret = -ERESTARTSYS;
1104 break;
1105 }
1106
1107 if (do_wakeup) {
1108 wakeup_pipe_writers(pipe);
1109 do_wakeup = 0;
1110 }
1111
1112 pipe_wait(pipe);
1113 }
1114 pipe_unlock(pipe);
1115
1116 if (do_wakeup)
1117 wakeup_pipe_writers(pipe);
1118
1119 return total_len ? total_len : ret;
1120}
1121
991/** 1122/**
992 * generic_splice_sendpage - splice data from a pipe to a socket 1123 * generic_splice_sendpage - splice data from a pipe to a socket
993 * @pipe: pipe to splice from 1124 * @pipe: pipe to splice from
@@ -1015,11 +1146,10 @@ EXPORT_SYMBOL(generic_splice_sendpage);
1015static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, 1146static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
1016 loff_t *ppos, size_t len, unsigned int flags) 1147 loff_t *ppos, size_t len, unsigned int flags)
1017{ 1148{
1149 ssize_t (*splice_write)(struct pipe_inode_info *, struct file *,
1150 loff_t *, size_t, unsigned int);
1018 int ret; 1151 int ret;
1019 1152
1020 if (unlikely(!out->f_op || !out->f_op->splice_write))
1021 return -EINVAL;
1022
1023 if (unlikely(!(out->f_mode & FMODE_WRITE))) 1153 if (unlikely(!(out->f_mode & FMODE_WRITE)))
1024 return -EBADF; 1154 return -EBADF;
1025 1155
@@ -1030,7 +1160,11 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
1030 if (unlikely(ret < 0)) 1160 if (unlikely(ret < 0))
1031 return ret; 1161 return ret;
1032 1162
1033 return out->f_op->splice_write(pipe, out, ppos, len, flags); 1163 splice_write = out->f_op->splice_write;
1164 if (!splice_write)
1165 splice_write = default_file_splice_write;
1166
1167 return splice_write(pipe, out, ppos, len, flags);
1034} 1168}
1035 1169
1036/* 1170/*