aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefano Stabellini <sstabellini@kernel.org>2017-07-06 14:01:08 -0400
committerBoris Ostrovsky <boris.ostrovsky@oracle.com>2017-08-31 09:45:55 -0400
commit5ad9918ffc4157f239f2e7849b4987d3b20f917e (patch)
tree6c2a8dc4e33440b1375960a81b62fd715c3f1941
parentb3f9f773af1f925b35f73f5e946bd96728b96cca (diff)
xen/pvcalls: implement write
When the other end notifies us that there is data to be written (pvcalls_back_conn_event), increment the io and write counters, and schedule the ioworker. Implement the write function called by ioworker by reading the data from the data ring, writing it to the socket by calling inet_sendmsg. Set out_error on error. Signed-off-by: Stefano Stabellini <stefano@aporeto.com> Reviewed-by: Juergen Gross <jgross@suse.com> CC: boris.ostrovsky@oracle.com CC: jgross@suse.com Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
-rw-r--r--drivers/xen/pvcalls-back.c71
1 files changed, 71 insertions, 0 deletions
diff --git a/drivers/xen/pvcalls-back.c b/drivers/xen/pvcalls-back.c
index 2519e46bd470..3201a0c5dbcf 100644
--- a/drivers/xen/pvcalls-back.c
+++ b/drivers/xen/pvcalls-back.c
@@ -177,6 +177,64 @@ static void pvcalls_conn_back_read(void *opaque)
177 177
178static void pvcalls_conn_back_write(struct sock_mapping *map) 178static void pvcalls_conn_back_write(struct sock_mapping *map)
179{ 179{
180 struct pvcalls_data_intf *intf = map->ring;
181 struct pvcalls_data *data = &map->data;
182 struct msghdr msg;
183 struct kvec vec[2];
184 RING_IDX cons, prod, size, array_size;
185 int ret;
186
187 cons = intf->out_cons;
188 prod = intf->out_prod;
189 /* read the indexes before dealing with the data */
190 virt_mb();
191
192 array_size = XEN_FLEX_RING_SIZE(map->ring_order);
193 size = pvcalls_queued(prod, cons, array_size);
194 if (size == 0)
195 return;
196
197 memset(&msg, 0, sizeof(msg));
198 msg.msg_flags |= MSG_DONTWAIT;
199 msg.msg_iter.type = ITER_KVEC|READ;
200 msg.msg_iter.count = size;
201 if (pvcalls_mask(prod, array_size) > pvcalls_mask(cons, array_size)) {
202 vec[0].iov_base = data->out + pvcalls_mask(cons, array_size);
203 vec[0].iov_len = size;
204 msg.msg_iter.kvec = vec;
205 msg.msg_iter.nr_segs = 1;
206 } else {
207 vec[0].iov_base = data->out + pvcalls_mask(cons, array_size);
208 vec[0].iov_len = array_size - pvcalls_mask(cons, array_size);
209 vec[1].iov_base = data->out;
210 vec[1].iov_len = size - vec[0].iov_len;
211 msg.msg_iter.kvec = vec;
212 msg.msg_iter.nr_segs = 2;
213 }
214
215 atomic_set(&map->write, 0);
216 ret = inet_sendmsg(map->sock, &msg, size);
217 if (ret == -EAGAIN || (ret >= 0 && ret < size)) {
218 atomic_inc(&map->write);
219 atomic_inc(&map->io);
220 }
221 if (ret == -EAGAIN)
222 return;
223
224 /* write the data, then update the indexes */
225 virt_wmb();
226 if (ret < 0) {
227 intf->out_error = ret;
228 } else {
229 intf->out_error = 0;
230 intf->out_cons = cons + ret;
231 prod = intf->out_prod;
232 }
233 /* update the indexes, then notify the other end */
234 virt_wmb();
235 if (prod != cons + ret)
236 atomic_inc(&map->write);
237 notify_remote_via_irq(map->irq);
180} 238}
181 239
182static void pvcalls_back_ioworker(struct work_struct *work) 240static void pvcalls_back_ioworker(struct work_struct *work)
@@ -847,6 +905,19 @@ static irqreturn_t pvcalls_back_event(int irq, void *dev_id)
847 905
848static irqreturn_t pvcalls_back_conn_event(int irq, void *sock_map) 906static irqreturn_t pvcalls_back_conn_event(int irq, void *sock_map)
849{ 907{
908 struct sock_mapping *map = sock_map;
909 struct pvcalls_ioworker *iow;
910
911 if (map == NULL || map->sock == NULL || map->sock->sk == NULL ||
912 map->sock->sk->sk_user_data != map)
913 return IRQ_HANDLED;
914
915 iow = &map->ioworker;
916
917 atomic_inc(&map->write);
918 atomic_inc(&map->io);
919 queue_work(iow->wq, &iow->register_work);
920
850 return IRQ_HANDLED; 921 return IRQ_HANDLED;
851} 922}
852 923