master
c 574 lines 17.7 KB
Raw
1 /*
2 * Xen 9p backend
3 *
4 * Copyright Aporeto 2017
5 *
6 * Authors:
7 * Stefano Stabellini <stefano@aporeto.com>
8 *
9 */
10
11 /*
12 * Not so fast! You might want to read the 9p developer docs first:
13 * https://wiki.qemu.org/Documentation/9p
14 */
15
16 #include "qemu/osdep.h"
17
18 #include "hw/9pfs/9p.h"
19 #include "hw/xen/xen-legacy-backend.h"
20 #include "hw/9pfs/xen-9pfs.h"
21 #include "qapi/error.h"
22 #include "qemu/config-file.h"
23 #include "qemu/main-loop.h"
24 #include "qemu/option.h"
25 #include "qemu/iov.h"
26 #include "fsdev/qemu-fsdev.h"
27
28 #include "trace.h"
29
30 #define VERSIONS "1"
31 #define MAX_RINGS 8
32 #define MAX_RING_ORDER 9
33
34 typedef struct Xen9pfsRing {
35 struct Xen9pfsDev *priv;
36
37 int ref;
38 xenevtchn_handle *evtchndev;
39 int evtchn;
40 int local_port;
41 int ring_order;
42 struct xen_9pfs_data_intf *intf;
43 unsigned char *data;
44 struct xen_9pfs_data ring;
45
46 struct iovec *sg;
47 QEMUBH *bh;
48 Coroutine *co;
49
50 /* local copies, so that we can read/write PDU data directly from
51 * the ring */
52 RING_IDX out_cons, out_size, in_cons;
53 bool inprogress;
54 } Xen9pfsRing;
55
56 typedef struct Xen9pfsDev {
57 struct XenLegacyDevice xendev; /* must be first */
58 V9fsState state;
59 char *path;
60 char *security_model;
61 char *tag;
62 char *id;
63
64 int num_rings;
65 Xen9pfsRing *rings;
66 MemReentrancyGuard mem_reentrancy_guard;
67 } Xen9pfsDev;
68
69 static void xen_9pfs_disconnect(struct XenLegacyDevice *xendev);
70
71 static void xen_9pfs_disconnect_bh(void *opaque)
72 {
73 xen_9pfs_disconnect(opaque);
74 }
75
76 static void xen_9pfs_in_sg(Xen9pfsRing *ring,
77 struct iovec *in_sg,
78 int *num,
79 uint32_t idx,
80 uint32_t size)
81 {
82 RING_IDX cons, prod, masked_prod, masked_cons;
83
84 cons = ring->intf->in_cons;
85 prod = ring->intf->in_prod;
86 xen_rmb();
87 masked_prod = xen_9pfs_mask(prod, XEN_FLEX_RING_SIZE(ring->ring_order));
88 masked_cons = xen_9pfs_mask(cons, XEN_FLEX_RING_SIZE(ring->ring_order));
89
90 if (masked_prod < masked_cons) {
91 in_sg[0].iov_base = ring->ring.in + masked_prod;
92 in_sg[0].iov_len = masked_cons - masked_prod;
93 *num = 1;
94 } else {
95 in_sg[0].iov_base = ring->ring.in + masked_prod;
96 in_sg[0].iov_len = XEN_FLEX_RING_SIZE(ring->ring_order) - masked_prod;
97 in_sg[1].iov_base = ring->ring.in;
98 in_sg[1].iov_len = masked_cons;
99 *num = 2;
100 }
101 }
102
103 static void xen_9pfs_out_sg(Xen9pfsRing *ring,
104 struct iovec *out_sg,
105 int *num,
106 uint32_t idx)
107 {
108 RING_IDX cons, prod, masked_prod, masked_cons;
109
110 cons = ring->intf->out_cons;
111 prod = ring->intf->out_prod;
112 xen_rmb();
113 masked_prod = xen_9pfs_mask(prod, XEN_FLEX_RING_SIZE(ring->ring_order));
114 masked_cons = xen_9pfs_mask(cons, XEN_FLEX_RING_SIZE(ring->ring_order));
115
116 if (masked_cons < masked_prod) {
117 out_sg[0].iov_base = ring->ring.out + masked_cons;
118 out_sg[0].iov_len = ring->out_size;
119 *num = 1;
120 } else {
121 if (ring->out_size >
122 (XEN_FLEX_RING_SIZE(ring->ring_order) - masked_cons)) {
123 out_sg[0].iov_base = ring->ring.out + masked_cons;
124 out_sg[0].iov_len = XEN_FLEX_RING_SIZE(ring->ring_order) -
125 masked_cons;
126 out_sg[1].iov_base = ring->ring.out;
127 out_sg[1].iov_len = ring->out_size -
128 (XEN_FLEX_RING_SIZE(ring->ring_order) -
129 masked_cons);
130 *num = 2;
131 } else {
132 out_sg[0].iov_base = ring->ring.out + masked_cons;
133 out_sg[0].iov_len = ring->out_size;
134 *num = 1;
135 }
136 }
137 }
138
139 static ssize_t coroutine_fn xen_9pfs_pdu_vmarshal(V9fsPDU *pdu,
140 size_t offset,
141 const char *fmt,
142 va_list ap)
143 {
144 Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
145 struct iovec in_sg[2];
146 int num;
147 ssize_t ret;
148
149 xen_9pfs_in_sg(&xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings],
150 in_sg, &num, pdu->idx, ROUND_UP(offset + 128, 512));
151
152 ret = v9fs_iov_vmarshal(in_sg, num, offset, 0, fmt, ap);
153 if (ret < 0) {
154 xen_pv_printf(&xen_9pfs->xendev, 0,
155 "Failed to encode VirtFS reply type %d\n",
156 pdu->id + 1);
157 xen_be_set_state(&xen_9pfs->xendev, XenbusStateClosing);
158 aio_bh_schedule_oneshot(qemu_get_aio_context(),
159 xen_9pfs_disconnect_bh, &xen_9pfs->xendev);
160 }
161 return ret;
162 }
163
164 static ssize_t coroutine_fn xen_9pfs_pdu_vunmarshal(V9fsPDU *pdu,
165 size_t offset,
166 const char *fmt,
167 va_list ap)
168 {
169 Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
170 struct iovec out_sg[2];
171 int num;
172 ssize_t ret;
173
174 xen_9pfs_out_sg(&xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings],
175 out_sg, &num, pdu->idx);
176
177 ret = v9fs_iov_vunmarshal(out_sg, num, offset, 0, fmt, ap);
178 if (ret < 0) {
179 xen_pv_printf(&xen_9pfs->xendev, 0,
180 "Failed to decode VirtFS request type %d\n", pdu->id);
181 xen_be_set_state(&xen_9pfs->xendev, XenbusStateClosing);
182 aio_bh_schedule_oneshot(qemu_get_aio_context(),
183 xen_9pfs_disconnect_bh, &xen_9pfs->xendev);
184 }
185 return ret;
186 }
187
188 static void coroutine_fn xen_9pfs_init_out_iov_from_pdu(V9fsPDU *pdu,
189 struct iovec **piov,
190 unsigned int *pniov,
191 size_t size)
192 {
193 Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
194 Xen9pfsRing *ring = &xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings];
195 int num;
196
197 g_free(ring->sg);
198
199 ring->sg = g_new0(struct iovec, 2);
200 xen_9pfs_out_sg(ring, ring->sg, &num, pdu->idx);
201 *piov = ring->sg;
202 *pniov = num;
203 }
204
205 static void coroutine_fn xen_9pfs_init_in_iov_from_pdu(V9fsPDU *pdu,
206 struct iovec **piov,
207 unsigned int *pniov,
208 size_t size)
209 {
210 Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
211 Xen9pfsRing *ring = &xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings];
212 int num;
213 size_t buf_size;
214
215 g_free(ring->sg);
216
217 ring->sg = g_new0(struct iovec, 2);
218 ring->co = qemu_coroutine_self();
219 /* make sure other threads see ring->co changes before continuing */
220 smp_wmb();
221
222 again:
223 xen_9pfs_in_sg(ring, ring->sg, &num, pdu->idx, size);
224 buf_size = iov_size(ring->sg, num);
225 if (buf_size < size) {
226 qemu_coroutine_yield();
227 goto again;
228 }
229 ring->co = NULL;
230 /* make sure other threads see ring->co changes before continuing */
231 smp_wmb();
232
233 *piov = ring->sg;
234 *pniov = num;
235 }
236
237 static void coroutine_fn xen_9pfs_push_and_notify(V9fsPDU *pdu)
238 {
239 RING_IDX prod;
240 Xen9pfsDev *priv = container_of(pdu->s, Xen9pfsDev, state);
241 Xen9pfsRing *ring = &priv->rings[pdu->tag % priv->num_rings];
242
243 g_free(ring->sg);
244 ring->sg = NULL;
245
246 ring->intf->out_cons = ring->out_cons;
247 xen_wmb();
248
249 prod = ring->intf->in_prod;
250 xen_rmb();
251 ring->intf->in_prod = prod + pdu->size;
252 xen_wmb();
253
254 ring->inprogress = false;
255 qemu_xen_evtchn_notify(ring->evtchndev, ring->local_port);
256
257 qemu_bh_schedule(ring->bh);
258 }
259
260 static size_t xen_9p_msize_limit(V9fsState *s)
261 {
262 Xen9pfsDev *xen_9pfs = container_of(s, Xen9pfsDev, state);
263 size_t limit;
264 int i;
265
266 if (!xen_9pfs->num_rings) {
267 return 0;
268 }
269
270 limit = XEN_FLEX_RING_SIZE(xen_9pfs->rings[0].ring_order);
271 for (i = 1; i < xen_9pfs->num_rings; i++) {
272 limit = MIN(limit, XEN_FLEX_RING_SIZE(xen_9pfs->rings[i].ring_order));
273 }
274
275 return limit;
276 }
277
278 static size_t xen_9pfs_response_buffer_size(V9fsPDU *pdu)
279 {
280 Xen9pfsDev *priv = container_of(pdu->s, Xen9pfsDev, state);
281 Xen9pfsRing *ring = &priv->rings[pdu->tag % priv->num_rings];
282 struct iovec in_sg[2];
283 int num;
284
285 xen_9pfs_in_sg(ring, in_sg, &num, pdu->idx, 0);
286 return iov_size(in_sg, num);
287 }
288
289 static const V9fsTransport xen_9p_transport = {
290 .pdu_vmarshal = xen_9pfs_pdu_vmarshal,
291 .pdu_vunmarshal = xen_9pfs_pdu_vunmarshal,
292 .init_in_iov_from_pdu = xen_9pfs_init_in_iov_from_pdu,
293 .init_out_iov_from_pdu = xen_9pfs_init_out_iov_from_pdu,
294 .push_and_notify = xen_9pfs_push_and_notify,
295 .msize_limit = xen_9p_msize_limit,
296 .response_buffer_size = xen_9pfs_response_buffer_size,
297 };
298
299 static int xen_9pfs_init(struct XenLegacyDevice *xendev)
300 {
301 return 0;
302 }
303
304 static int xen_9pfs_receive(Xen9pfsRing *ring)
305 {
306 P9MsgHeader h;
307 RING_IDX cons, prod, masked_prod, masked_cons, queued;
308 V9fsPDU *pdu;
309
310 if (ring->inprogress) {
311 return 0;
312 }
313
314 cons = ring->intf->out_cons;
315 prod = ring->intf->out_prod;
316 xen_rmb();
317
318 queued = xen_9pfs_queued(prod, cons, XEN_FLEX_RING_SIZE(ring->ring_order));
319 if (queued < sizeof(h)) {
320 return 0;
321 }
322 ring->inprogress = true;
323
324 masked_prod = xen_9pfs_mask(prod, XEN_FLEX_RING_SIZE(ring->ring_order));
325 masked_cons = xen_9pfs_mask(cons, XEN_FLEX_RING_SIZE(ring->ring_order));
326
327 xen_9pfs_read_packet((uint8_t *) &h, ring->ring.out, sizeof(h),
328 masked_prod, &masked_cons,
329 XEN_FLEX_RING_SIZE(ring->ring_order));
330 if (queued < le32_to_cpu(h.size_le)) {
331 return 0;
332 }
333
334 /* cannot fail, because we only handle one request per ring at a time */
335 pdu = pdu_alloc(&ring->priv->state);
336 ring->out_size = le32_to_cpu(h.size_le);
337 ring->out_cons = cons + le32_to_cpu(h.size_le);
338
339 pdu_submit(pdu, &h);
340
341 return 0;
342 }
343
344 static void xen_9pfs_bh(void *opaque)
345 {
346 Xen9pfsRing *ring = opaque;
347 bool wait;
348
349 again:
350 wait = ring->co != NULL && qemu_coroutine_entered(ring->co);
351 /* paired with the smp_wmb barriers in xen_9pfs_init_in_iov_from_pdu */
352 smp_rmb();
353 if (wait) {
354 cpu_relax();
355 goto again;
356 }
357
358 if (ring->co != NULL) {
359 qemu_coroutine_enter_if_inactive(ring->co);
360 }
361 xen_9pfs_receive(ring);
362 }
363
364 static void xen_9pfs_evtchn_event(void *opaque)
365 {
366 Xen9pfsRing *ring = opaque;
367 evtchn_port_t port;
368
369 port = qemu_xen_evtchn_pending(ring->evtchndev);
370 qemu_xen_evtchn_unmask(ring->evtchndev, port);
371
372 qemu_bh_schedule(ring->bh);
373 }
374
375 static void xen_9pfs_disconnect(struct XenLegacyDevice *xendev)
376 {
377 Xen9pfsDev *xen_9pdev = container_of(xendev, Xen9pfsDev, xendev);
378 V9fsState *s = &xen_9pdev->state;
379 int i;
380
381 trace_xen_9pfs_disconnect(xendev->name);
382
383 if (s->transport) {
384 v9fs_reset(s); /* cancel all in-flight PDUs to prevent UAF */
385 v9fs_device_unrealize_common(s);
386 }
387
388 for (i = 0; i < xen_9pdev->num_rings; i++) {
389 if (xen_9pdev->rings[i].evtchndev != NULL) {
390 qemu_set_fd_handler(qemu_xen_evtchn_fd(xen_9pdev->rings[i].evtchndev),
391 NULL, NULL, NULL);
392 qemu_xen_evtchn_unbind(xen_9pdev->rings[i].evtchndev,
393 xen_9pdev->rings[i].local_port);
394 xen_9pdev->rings[i].evtchndev = NULL;
395 }
396 if (xen_9pdev->rings[i].data != NULL) {
397 xen_be_unmap_grant_refs(&xen_9pdev->xendev,
398 xen_9pdev->rings[i].data,
399 xen_9pdev->rings[i].intf->ref,
400 (1 << xen_9pdev->rings[i].ring_order));
401 xen_9pdev->rings[i].data = NULL;
402 }
403 if (xen_9pdev->rings[i].intf != NULL) {
404 xen_be_unmap_grant_ref(&xen_9pdev->xendev,
405 xen_9pdev->rings[i].intf,
406 xen_9pdev->rings[i].ref);
407 xen_9pdev->rings[i].intf = NULL;
408 }
409 if (xen_9pdev->rings[i].bh != NULL) {
410 qemu_bh_delete(xen_9pdev->rings[i].bh);
411 xen_9pdev->rings[i].bh = NULL;
412 }
413 }
414
415 g_free(xen_9pdev->id);
416 xen_9pdev->id = NULL;
417 g_free(xen_9pdev->tag);
418 xen_9pdev->tag = NULL;
419 g_free(xen_9pdev->path);
420 xen_9pdev->path = NULL;
421 g_free(xen_9pdev->security_model);
422 xen_9pdev->security_model = NULL;
423 g_free(xen_9pdev->rings);
424 xen_9pdev->rings = NULL;
425 }
426
427 static int xen_9pfs_free(struct XenLegacyDevice *xendev)
428 {
429 trace_xen_9pfs_free(xendev->name);
430
431 return 0;
432 }
433
434 static int xen_9pfs_connect(struct XenLegacyDevice *xendev)
435 {
436 Error *err = NULL;
437 int i;
438 Xen9pfsDev *xen_9pdev = container_of(xendev, Xen9pfsDev, xendev);
439 V9fsState *s = &xen_9pdev->state;
440 QemuOpts *fsdev;
441
442 trace_xen_9pfs_connect(xendev->name);
443
444 if (xenstore_read_fe_int(&xen_9pdev->xendev, "num-rings",
445 &xen_9pdev->num_rings) == -1 ||
446 xen_9pdev->num_rings > MAX_RINGS || xen_9pdev->num_rings < 1) {
447 return -1;
448 }
449
450 xen_9pdev->rings = g_new0(Xen9pfsRing, xen_9pdev->num_rings);
451 for (i = 0; i < xen_9pdev->num_rings; i++) {
452 char *str;
453 int ring_order;
454
455 xen_9pdev->rings[i].priv = xen_9pdev;
456 xen_9pdev->rings[i].evtchn = -1;
457 xen_9pdev->rings[i].local_port = -1;
458
459 str = g_strdup_printf("ring-ref%u", i);
460 if (xenstore_read_fe_int(&xen_9pdev->xendev, str,
461 &xen_9pdev->rings[i].ref) == -1) {
462 g_free(str);
463 goto out;
464 }
465 g_free(str);
466 str = g_strdup_printf("event-channel-%u", i);
467 if (xenstore_read_fe_int(&xen_9pdev->xendev, str,
468 &xen_9pdev->rings[i].evtchn) == -1) {
469 g_free(str);
470 goto out;
471 }
472 g_free(str);
473
474 xen_9pdev->rings[i].intf =
475 xen_be_map_grant_ref(&xen_9pdev->xendev,
476 xen_9pdev->rings[i].ref,
477 PROT_READ | PROT_WRITE);
478 if (!xen_9pdev->rings[i].intf) {
479 goto out;
480 }
481 ring_order = xen_9pdev->rings[i].intf->ring_order;
482 if (ring_order > MAX_RING_ORDER) {
483 goto out;
484 }
485 xen_9pdev->rings[i].ring_order = ring_order;
486 xen_9pdev->rings[i].data =
487 xen_be_map_grant_refs(&xen_9pdev->xendev,
488 xen_9pdev->rings[i].intf->ref,
489 (1 << ring_order),
490 PROT_READ | PROT_WRITE);
491 if (!xen_9pdev->rings[i].data) {
492 goto out;
493 }
494 xen_9pdev->rings[i].ring.in = xen_9pdev->rings[i].data;
495 xen_9pdev->rings[i].ring.out = xen_9pdev->rings[i].data +
496 XEN_FLEX_RING_SIZE(ring_order);
497
498 xen_9pdev->rings[i].bh = qemu_bh_new_guarded(xen_9pfs_bh,
499 &xen_9pdev->rings[i],
500 &xen_9pdev->mem_reentrancy_guard);
501 xen_9pdev->rings[i].out_cons = 0;
502 xen_9pdev->rings[i].out_size = 0;
503 xen_9pdev->rings[i].inprogress = false;
504
505
506 xen_9pdev->rings[i].evtchndev = qemu_xen_evtchn_open();
507 if (xen_9pdev->rings[i].evtchndev == NULL) {
508 goto out;
509 }
510 qemu_set_cloexec(qemu_xen_evtchn_fd(xen_9pdev->rings[i].evtchndev));
511 xen_9pdev->rings[i].local_port = qemu_xen_evtchn_bind_interdomain
512 (xen_9pdev->rings[i].evtchndev,
513 xendev->dom,
514 xen_9pdev->rings[i].evtchn);
515 if (xen_9pdev->rings[i].local_port == -1) {
516 xen_pv_printf(xendev, 0,
517 "xenevtchn_bind_interdomain failed port=%d\n",
518 xen_9pdev->rings[i].evtchn);
519 goto out;
520 }
521 xen_pv_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port);
522 qemu_set_fd_handler(qemu_xen_evtchn_fd(xen_9pdev->rings[i].evtchndev),
523 xen_9pfs_evtchn_event, NULL, &xen_9pdev->rings[i]);
524 }
525
526 xen_9pdev->security_model = xenstore_read_be_str(xendev, "security_model");
527 xen_9pdev->path = xenstore_read_be_str(xendev, "path");
528 xen_9pdev->id = s->fsconf.fsdev_id =
529 g_strdup_printf("xen9p%d", xendev->dev);
530 xen_9pdev->tag = s->fsconf.tag = xenstore_read_fe_str(xendev, "tag");
531 fsdev = qemu_opts_create(qemu_find_opts("fsdev"),
532 s->fsconf.tag,
533 1, NULL);
534 qemu_opt_set(fsdev, "fsdriver", "local", NULL);
535 qemu_opt_set(fsdev, "path", xen_9pdev->path, NULL);
536 qemu_opt_set(fsdev, "security_model", xen_9pdev->security_model, NULL);
537 qemu_opts_set_id(fsdev, s->fsconf.fsdev_id);
538 qemu_fsdev_add(fsdev, &err);
539 if (err) {
540 error_report_err(err);
541 }
542 v9fs_device_realize_common(s, &xen_9p_transport, NULL);
543
544 return 0;
545
546 out:
547 xen_9pfs_free(xendev);
548 return -1;
549 }
550
551 static void xen_9pfs_alloc(struct XenLegacyDevice *xendev)
552 {
553 trace_xen_9pfs_alloc(xendev->name);
554
555 xenstore_write_be_str(xendev, "versions", VERSIONS);
556 xenstore_write_be_int(xendev, "max-rings", MAX_RINGS);
557 xenstore_write_be_int(xendev, "max-ring-page-order", MAX_RING_ORDER);
558 }
559
560 static const struct XenDevOps xen_9pfs_ops = {
561 .size = sizeof(Xen9pfsDev),
562 .flags = DEVOPS_FLAG_NEED_GNTDEV,
563 .alloc = xen_9pfs_alloc,
564 .init = xen_9pfs_init,
565 .initialise = xen_9pfs_connect,
566 .disconnect = xen_9pfs_disconnect,
567 .free = xen_9pfs_free,
568 };
569
570 static void xen_9pfs_register_backend(void)
571 {
572 xen_be_register("9pfs", &xen_9pfs_ops);
573 }
574 xen_backend_init(xen_9pfs_register_backend);