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