diff options
Diffstat (limited to 'kernel/relay.c')
-rw-r--r-- | kernel/relay.c | 146 |
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 | ||
1035 | static 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 | |||
1035 | static void relay_pipe_buf_release(struct pipe_inode_info *pipe, | 1045 | static 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 | ||
1050 | static struct pipe_buf_operations relay_pipe_buf_ops = { | 1054 | static 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 | ||
1184 | static ssize_t relay_file_splice_read(struct file *in, | 1149 | static 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) { |