aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorJens Axboe <jens.axboe@oracle.com>2007-06-12 02:43:46 -0400
committerJens Axboe <jens.axboe@oracle.com>2007-07-10 02:04:15 -0400
commit1db60cf2056511c7c8cebcbaee308ef6c79b4728 (patch)
tree4bdb5616abcd48d8b0e08b1fde90f0f4b38a118d /kernel
parent497f9625c2bbd6a8525fb2eedb22a382a6a8253c (diff)
relay: use splice_to_pipe() instead of open-coding the pipe loop
It cleans up the relay splice implementation a lot, and gets rid of a lot of internal pipe knowledge that should not be in there. Plus fixes for padding and partial first page (and lots more) from Tom Zanussi. Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/relay.c146
1 files changed, 55 insertions, 91 deletions
diff --git a/kernel/relay.c b/kernel/relay.c
index 951f29b24e58..dd3bc5b69035 100644
--- a/kernel/relay.c
+++ b/kernel/relay.c
@@ -1032,19 +1032,23 @@ static ssize_t relay_file_read(struct file *filp,
1032 NULL, &desc); 1032 NULL, &desc);
1033} 1033}
1034 1034
1035static void relay_consume_bytes(struct rchan_buf *rbuf, int bytes_consumed)
1036{
1037 rbuf->bytes_consumed += bytes_consumed;
1038
1039 if (rbuf->bytes_consumed >= rbuf->chan->subbuf_size) {
1040 relay_subbufs_consumed(rbuf->chan, rbuf->cpu, 1);
1041 rbuf->bytes_consumed %= rbuf->chan->subbuf_size;
1042 }
1043}
1044
1035static void relay_pipe_buf_release(struct pipe_inode_info *pipe, 1045static void relay_pipe_buf_release(struct pipe_inode_info *pipe,
1036 struct pipe_buffer *buf) 1046 struct pipe_buffer *buf)
1037{ 1047{
1038 struct rchan_buf *rbuf; 1048 struct rchan_buf *rbuf;
1039 1049
1040 rbuf = (struct rchan_buf *)page_private(buf->page); 1050 rbuf = (struct rchan_buf *)page_private(buf->page);
1041 1051 relay_consume_bytes(rbuf, buf->private);
1042 rbuf->bytes_consumed += PAGE_SIZE;
1043
1044 if (rbuf->bytes_consumed == rbuf->chan->subbuf_size) {
1045 relay_subbufs_consumed(rbuf->chan, rbuf->cpu, 1);
1046 rbuf->bytes_consumed = 0;
1047 }
1048} 1052}
1049 1053
1050static struct pipe_buf_operations relay_pipe_buf_ops = { 1054static struct pipe_buf_operations relay_pipe_buf_ops = {
@@ -1067,118 +1071,79 @@ static int subbuf_splice_actor(struct file *in,
1067 unsigned int flags, 1071 unsigned int flags,
1068 int *nonpad_ret) 1072 int *nonpad_ret)
1069{ 1073{
1070 unsigned int pidx, poff; 1074 unsigned int pidx, poff, total_len, subbuf_pages, ret;
1071 unsigned int subbuf_pages;
1072 int ret = 0;
1073 int do_wakeup = 0;
1074 struct rchan_buf *rbuf = in->private_data; 1075 struct rchan_buf *rbuf = in->private_data;
1075 unsigned int subbuf_size = rbuf->chan->subbuf_size; 1076 unsigned int subbuf_size = rbuf->chan->subbuf_size;
1076 size_t read_start = ((size_t)*ppos) % rbuf->chan->alloc_size; 1077 size_t read_start = ((size_t)*ppos) % rbuf->chan->alloc_size;
1077 size_t avail = subbuf_size - read_start % subbuf_size;
1078 size_t read_subbuf = read_start / subbuf_size; 1078 size_t read_subbuf = read_start / subbuf_size;
1079 size_t padding = rbuf->padding[read_subbuf]; 1079 size_t padding = rbuf->padding[read_subbuf];
1080 size_t nonpad_end = read_subbuf * subbuf_size + subbuf_size - padding; 1080 size_t nonpad_end = read_subbuf * subbuf_size + subbuf_size - padding;
1081 struct page *pages[PIPE_BUFFERS];
1082 struct partial_page partial[PIPE_BUFFERS];
1083 struct splice_pipe_desc spd = {
1084 .pages = pages,
1085 .nr_pages = 0,
1086 .partial = partial,
1087 .flags = flags,
1088 .ops = &relay_pipe_buf_ops,
1089 };
1081 1090
1082 if (rbuf->subbufs_produced == rbuf->subbufs_consumed) 1091 if (rbuf->subbufs_produced == rbuf->subbufs_consumed)
1083 return 0; 1092 return 0;
1084 1093
1085 if (len > avail) 1094 /*
1086 len = avail; 1095 * Adjust read len, if longer than what is available
1087 1096 */
1088 if (pipe->inode) 1097 if (len > (subbuf_size - read_start % subbuf_size))
1089 mutex_lock(&pipe->inode->i_mutex); 1098 len = subbuf_size - read_start % subbuf_size;
1090 1099
1091 subbuf_pages = rbuf->chan->alloc_size >> PAGE_SHIFT; 1100 subbuf_pages = rbuf->chan->alloc_size >> PAGE_SHIFT;
1092 pidx = (read_start / PAGE_SIZE) % subbuf_pages; 1101 pidx = (read_start / PAGE_SIZE) % subbuf_pages;
1093 poff = read_start & ~PAGE_MASK; 1102 poff = read_start & ~PAGE_MASK;
1094 1103
1095 for (;;) { 1104 for (total_len = 0; spd.nr_pages < subbuf_pages; spd.nr_pages++) {
1096 unsigned int this_len; 1105 unsigned int this_len, this_end, private;
1097 unsigned int this_end; 1106 unsigned int cur_pos = read_start + total_len;
1098 int newbuf = (pipe->curbuf + pipe->nrbufs) & (PIPE_BUFFERS - 1);
1099 struct pipe_buffer *buf = pipe->bufs + newbuf;
1100 1107
1101 if (!pipe->readers) { 1108 if (!len)
1102 send_sig(SIGPIPE, current, 0);
1103 if (!ret)
1104 ret = -EPIPE;
1105 break; 1109 break;
1106 }
1107
1108 if (pipe->nrbufs < PIPE_BUFFERS) {
1109 this_len = PAGE_SIZE - poff;
1110 if (this_len > avail)
1111 this_len = avail;
1112
1113 buf->page = rbuf->page_array[pidx];
1114 buf->offset = poff;
1115 this_end = read_start + ret + this_len;
1116 if (this_end > nonpad_end) {
1117 if (read_start + ret >= nonpad_end)
1118 buf->len = 0;
1119 else
1120 buf->len = nonpad_end - (read_start + ret);
1121 } else
1122 buf->len = this_len;
1123
1124 *nonpad_ret += buf->len;
1125
1126 buf->ops = &relay_pipe_buf_ops;
1127 pipe->nrbufs++;
1128 1110
1129 avail -= this_len; 1111 this_len = min_t(unsigned long, len, PAGE_SIZE - poff);
1130 ret += this_len; 1112 private = this_len;
1131 poff = 0;
1132 pidx = (pidx + 1) % subbuf_pages;
1133 1113
1134 if (pipe->inode) 1114 spd.pages[spd.nr_pages] = rbuf->page_array[pidx];
1135 do_wakeup = 1; 1115 spd.partial[spd.nr_pages].offset = poff;
1136 1116
1137 if (!avail) 1117 this_end = cur_pos + this_len;
1138 break; 1118 if (this_end >= nonpad_end) {
1139 1119 this_len = nonpad_end - cur_pos;
1140 if (pipe->nrbufs < PIPE_BUFFERS) 1120 private = this_len + padding;
1141 continue;
1142
1143 break;
1144 } 1121 }
1122 spd.partial[spd.nr_pages].len = this_len;
1123 spd.partial[spd.nr_pages].private = private;
1145 1124
1146 if (flags & SPLICE_F_NONBLOCK) { 1125 len -= this_len;
1147 if (!ret) 1126 total_len += this_len;
1148 ret = -EAGAIN; 1127 poff = 0;
1149 break; 1128 pidx = (pidx + 1) % subbuf_pages;
1150 }
1151 1129
1152 if (signal_pending(current)) { 1130 if (this_end >= nonpad_end) {
1153 if (!ret) 1131 spd.nr_pages++;
1154 ret = -ERESTARTSYS;
1155 break; 1132 break;
1156 } 1133 }
1157
1158 if (do_wakeup) {
1159 smp_mb();
1160 if (waitqueue_active(&pipe->wait))
1161 wake_up_interruptible_sync(&pipe->wait);
1162 kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
1163 do_wakeup = 0;
1164 }
1165
1166 pipe->waiting_writers++;
1167 pipe_wait(pipe);
1168 pipe->waiting_writers--;
1169 } 1134 }
1170 1135
1171 if (pipe->inode) 1136 if (!spd.nr_pages)
1172 mutex_unlock(&pipe->inode->i_mutex); 1137 return 0;
1173 1138
1174 if (do_wakeup) { 1139 ret = *nonpad_ret = splice_to_pipe(pipe, &spd);
1175 smp_mb(); 1140 if (ret < 0 || ret < total_len)
1176 if (waitqueue_active(&pipe->wait)) 1141 return ret;
1177 wake_up_interruptible(&pipe->wait);
1178 kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
1179 }
1180 1142
1181 return ret; 1143 if (read_start + ret == nonpad_end)
1144 ret += padding;
1145
1146 return ret;
1182} 1147}
1183 1148
1184static ssize_t relay_file_splice_read(struct file *in, 1149static ssize_t relay_file_splice_read(struct file *in,
@@ -1199,7 +1164,6 @@ static ssize_t relay_file_splice_read(struct file *in,
1199 if (ret < 0) 1164 if (ret < 0)
1200 break; 1165 break;
1201 else if (!ret) { 1166 else if (!ret) {
1202 break;
1203 if (spliced) 1167 if (spliced)
1204 break; 1168 break;
1205 if (flags & SPLICE_F_NONBLOCK) { 1169 if (flags & SPLICE_F_NONBLOCK) {