aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/relay.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/relay.c')
-rw-r--r--kernel/relay.c205
1 files changed, 155 insertions, 50 deletions
diff --git a/kernel/relay.c b/kernel/relay.c
index 95db8c79fe8f..3b299fb3855c 100644
--- a/kernel/relay.c
+++ b/kernel/relay.c
@@ -21,6 +21,7 @@
21#include <linux/vmalloc.h> 21#include <linux/vmalloc.h>
22#include <linux/mm.h> 22#include <linux/mm.h>
23#include <linux/cpu.h> 23#include <linux/cpu.h>
24#include <linux/splice.h>
24 25
25/* list of open channels, for cpu hotplug */ 26/* list of open channels, for cpu hotplug */
26static DEFINE_MUTEX(relay_channels_mutex); 27static DEFINE_MUTEX(relay_channels_mutex);
@@ -121,6 +122,7 @@ static void *relay_alloc_buf(struct rchan_buf *buf, size_t *size)
121 buf->page_array[i] = alloc_page(GFP_KERNEL); 122 buf->page_array[i] = alloc_page(GFP_KERNEL);
122 if (unlikely(!buf->page_array[i])) 123 if (unlikely(!buf->page_array[i]))
123 goto depopulate; 124 goto depopulate;
125 set_page_private(buf->page_array[i], (unsigned long)buf);
124 } 126 }
125 mem = vmap(buf->page_array, n_pages, VM_MAP, PAGE_KERNEL); 127 mem = vmap(buf->page_array, n_pages, VM_MAP, PAGE_KERNEL);
126 if (!mem) 128 if (!mem)
@@ -970,43 +972,6 @@ static int subbuf_read_actor(size_t read_start,
970 return ret; 972 return ret;
971} 973}
972 974
973/*
974 * subbuf_send_actor - send up to one subbuf's worth of data
975 */
976static int subbuf_send_actor(size_t read_start,
977 struct rchan_buf *buf,
978 size_t avail,
979 read_descriptor_t *desc,
980 read_actor_t actor)
981{
982 unsigned long pidx, poff;
983 unsigned int subbuf_pages;
984 int ret = 0;
985
986 subbuf_pages = buf->chan->alloc_size >> PAGE_SHIFT;
987 pidx = (read_start / PAGE_SIZE) % subbuf_pages;
988 poff = read_start & ~PAGE_MASK;
989 while (avail) {
990 struct page *p = buf->page_array[pidx];
991 unsigned int len;
992
993 len = PAGE_SIZE - poff;
994 if (len > avail)
995 len = avail;
996
997 len = actor(desc, p, poff, len);
998 if (desc->error)
999 break;
1000
1001 avail -= len;
1002 ret += len;
1003 poff = 0;
1004 pidx = (pidx + 1) % subbuf_pages;
1005 }
1006
1007 return ret;
1008}
1009
1010typedef int (*subbuf_actor_t) (size_t read_start, 975typedef int (*subbuf_actor_t) (size_t read_start,
1011 struct rchan_buf *buf, 976 struct rchan_buf *buf,
1012 size_t avail, 977 size_t avail,
@@ -1067,19 +1032,159 @@ static ssize_t relay_file_read(struct file *filp,
1067 NULL, &desc); 1032 NULL, &desc);
1068} 1033}
1069 1034
1070static ssize_t relay_file_sendfile(struct file *filp, 1035static void relay_consume_bytes(struct rchan_buf *rbuf, int bytes_consumed)
1071 loff_t *ppos,
1072 size_t count,
1073 read_actor_t actor,
1074 void *target)
1075{ 1036{
1076 read_descriptor_t desc; 1037 rbuf->bytes_consumed += bytes_consumed;
1077 desc.written = 0; 1038
1078 desc.count = count; 1039 if (rbuf->bytes_consumed >= rbuf->chan->subbuf_size) {
1079 desc.arg.data = target; 1040 relay_subbufs_consumed(rbuf->chan, rbuf->cpu, 1);
1080 desc.error = 0; 1041 rbuf->bytes_consumed %= rbuf->chan->subbuf_size;
1081 return relay_file_read_subbufs(filp, ppos, subbuf_send_actor, 1042 }
1082 actor, &desc); 1043}
1044
1045static void relay_pipe_buf_release(struct pipe_inode_info *pipe,
1046 struct pipe_buffer *buf)
1047{
1048 struct rchan_buf *rbuf;
1049
1050 rbuf = (struct rchan_buf *)page_private(buf->page);
1051 relay_consume_bytes(rbuf, buf->private);
1052}
1053
1054static struct pipe_buf_operations relay_pipe_buf_ops = {
1055 .can_merge = 0,
1056 .map = generic_pipe_buf_map,
1057 .unmap = generic_pipe_buf_unmap,
1058 .confirm = generic_pipe_buf_confirm,
1059 .release = relay_pipe_buf_release,
1060 .steal = generic_pipe_buf_steal,
1061 .get = generic_pipe_buf_get,
1062};
1063
1064/**
1065 * subbuf_splice_actor - splice up to one subbuf's worth of data
1066 */
1067static int subbuf_splice_actor(struct file *in,
1068 loff_t *ppos,
1069 struct pipe_inode_info *pipe,
1070 size_t len,
1071 unsigned int flags,
1072 int *nonpad_ret)
1073{
1074 unsigned int pidx, poff, total_len, subbuf_pages, ret;
1075 struct rchan_buf *rbuf = in->private_data;
1076 unsigned int subbuf_size = rbuf->chan->subbuf_size;
1077 size_t read_start = ((size_t)*ppos) % rbuf->chan->alloc_size;
1078 size_t read_subbuf = read_start / subbuf_size;
1079 size_t padding = rbuf->padding[read_subbuf];
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 };
1090
1091 if (rbuf->subbufs_produced == rbuf->subbufs_consumed)
1092 return 0;
1093
1094 /*
1095 * Adjust read len, if longer than what is available
1096 */
1097 if (len > (subbuf_size - read_start % subbuf_size))
1098 len = subbuf_size - read_start % subbuf_size;
1099
1100 subbuf_pages = rbuf->chan->alloc_size >> PAGE_SHIFT;
1101 pidx = (read_start / PAGE_SIZE) % subbuf_pages;
1102 poff = read_start & ~PAGE_MASK;
1103
1104 for (total_len = 0; spd.nr_pages < subbuf_pages; spd.nr_pages++) {
1105 unsigned int this_len, this_end, private;
1106 unsigned int cur_pos = read_start + total_len;
1107
1108 if (!len)
1109 break;
1110
1111 this_len = min_t(unsigned long, len, PAGE_SIZE - poff);
1112 private = this_len;
1113
1114 spd.pages[spd.nr_pages] = rbuf->page_array[pidx];
1115 spd.partial[spd.nr_pages].offset = poff;
1116
1117 this_end = cur_pos + this_len;
1118 if (this_end >= nonpad_end) {
1119 this_len = nonpad_end - cur_pos;
1120 private = this_len + padding;
1121 }
1122 spd.partial[spd.nr_pages].len = this_len;
1123 spd.partial[spd.nr_pages].private = private;
1124
1125 len -= this_len;
1126 total_len += this_len;
1127 poff = 0;
1128 pidx = (pidx + 1) % subbuf_pages;
1129
1130 if (this_end >= nonpad_end) {
1131 spd.nr_pages++;
1132 break;
1133 }
1134 }
1135
1136 if (!spd.nr_pages)
1137 return 0;
1138
1139 ret = *nonpad_ret = splice_to_pipe(pipe, &spd);
1140 if (ret < 0 || ret < total_len)
1141 return ret;
1142
1143 if (read_start + ret == nonpad_end)
1144 ret += padding;
1145
1146 return ret;
1147}
1148
1149static ssize_t relay_file_splice_read(struct file *in,
1150 loff_t *ppos,
1151 struct pipe_inode_info *pipe,
1152 size_t len,
1153 unsigned int flags)
1154{
1155 ssize_t spliced;
1156 int ret;
1157 int nonpad_ret = 0;
1158
1159 ret = 0;
1160 spliced = 0;
1161
1162 while (len) {
1163 ret = subbuf_splice_actor(in, ppos, pipe, len, flags, &nonpad_ret);
1164 if (ret < 0)
1165 break;
1166 else if (!ret) {
1167 if (spliced)
1168 break;
1169 if (flags & SPLICE_F_NONBLOCK) {
1170 ret = -EAGAIN;
1171 break;
1172 }
1173 }
1174
1175 *ppos += ret;
1176 if (ret > len)
1177 len = 0;
1178 else
1179 len -= ret;
1180 spliced += nonpad_ret;
1181 nonpad_ret = 0;
1182 }
1183
1184 if (spliced)
1185 return spliced;
1186
1187 return ret;
1083} 1188}
1084 1189
1085const struct file_operations relay_file_operations = { 1190const struct file_operations relay_file_operations = {
@@ -1089,7 +1194,7 @@ const struct file_operations relay_file_operations = {
1089 .read = relay_file_read, 1194 .read = relay_file_read,
1090 .llseek = no_llseek, 1195 .llseek = no_llseek,
1091 .release = relay_file_release, 1196 .release = relay_file_release,
1092 .sendfile = relay_file_sendfile, 1197 .splice_read = relay_file_splice_read,
1093}; 1198};
1094EXPORT_SYMBOL_GPL(relay_file_operations); 1199EXPORT_SYMBOL_GPL(relay_file_operations);
1095 1200