1 2#include <mini-os/os.h> 3#include <mini-os/xenbus.h> 4#include <mini-os/wait.h> 5 6#include <bmk-core/memalloc.h> 7#include <bmk-core/string.h> 8#include <bmk-core/errno.h> 9 10#include <bmk-rumpuser/core_types.h> 11#include <bmk-rumpuser/rumpuser.h> 12 13#include "busdev_user.h" 14 15#define xbd_malloc(sz) (bmk_memalloc((sz), 0, BMK_MEMWHO_RUMPKERN)) 16 17static inline void xbd_free(void *p) { bmk_memfree(p, BMK_MEMWHO_RUMPKERN); } 18 19#define strcmp bmk_strcmp 20#define strlen bmk_strlen 21#define memchr bmk_memchr 22#define memcpy bmk_memcpy 23#define strtoul bmk_strtoul 24 25#define bzero(p,l) bmk_memset((p),0,(l)) 26 27#define KASSERT bmk_assert 28#define assert bmk_assert 29#define INT_MAX ((int)(~(unsigned int)0 >> 1u)) 30 31#define ENOMEM BMK_ENOMEM 32#define EINVAL BMK_EINVAL 33 34#define printf minios_printk 35 36#ifdef RUMP_DEV_XEN_DEBUG 37#define DPRINTF(a) (printf a) 38#else 39#define DPRINTF(a) /* nothing */ 40#endif 41 42static char *xbd_strdup(const char *s) { 43 size_t l = strlen(s); 44 char *r = xbd_malloc(l + 1); 45 if (!r) return r; 46 memcpy(r, s, l+1); 47 return r; 48} 49 50/*----- data structures -----*/ 51 52struct xenbus_dev_request { 53 struct xenbus_event xb; 54 uint32_t xb_id, user_id; 55 uint32_t req_type; 56 union { 57 struct xenbus_dev_transaction *trans; 58 struct xenbus_dev_watch *watch; 59 } u; 60}; 61 62struct xenbus_dev_transaction { 63 LIST_ENTRY(xenbus_dev_transaction) entry; 64 xenbus_transaction_t tx_id; 65 struct xenbus_dev_request destroy; 66}; 67 68struct xenbus_dev_watch { 69 struct xenbus_watch xb; 70 LIST_ENTRY(xenbus_dev_watch) entry; 71 struct xsd_sockmsg *wmsg; 72 char *path, *user_token; 73 _Bool visible_to_user; 74 struct xenbus_dev_request destroy; 75}; 76 77struct rumpxenbus_data_user { 78 struct rumpxenbus_data_common *c; 79 int outstanding_requests; 80 LIST_HEAD(, xenbus_dev_transaction) transactions; 81 LIST_HEAD(, xenbus_dev_watch) watches; 82 struct xenbus_event_queue replies; /* Entirely unread by user. */ 83}; 84 85/*----- helpers -----*/ 86 87static void 88free_watch(struct xenbus_dev_watch *watch) 89{ 90 xbd_free(watch->path); 91 xbd_free(watch->user_token); 92 xbd_free(watch); 93} 94 95static struct xenbus_dev_transaction* 96find_transaction(struct rumpxenbus_data_common *dc, xenbus_transaction_t id) 97{ 98 struct rumpxenbus_data_user *const du = dc->du; 99 struct xenbus_dev_transaction *trans; 100 101 LIST_FOREACH(trans, &du->transactions, entry) 102 if (trans->tx_id == dc->wbuf.msg.tx_id) 103 return trans; 104 /* not found */ 105 return 0; 106} 107 108static struct xenbus_dev_watch* 109find_visible_watch(struct rumpxenbus_data_common *dc, 110 const char *path, const char *token) 111{ 112 struct rumpxenbus_data_user *const du = dc->du; 113 struct xenbus_dev_watch *watch; 114 115 LIST_FOREACH(watch, &du->watches, entry) 116 if (watch->visible_to_user && 117 !strcmp(path, watch->path) && 118 !strcmp(token, watch->user_token)) 119 return watch; 120 /* not found */ 121 return 0; 122} 123 124/*----- request handling (writes to the device) -----*/ 125 126static void 127make_request(struct rumpxenbus_data_common *dc, struct xenbus_dev_request *req, 128 uint32_t tx_id, const struct write_req *wreqs, int num_wreqs) 129/* Caller should have filled in req->req_id, ->u, and (if needed) 130 * ->user_id. We deal with ->xb and ->xb_id. */ 131{ 132 struct rumpxenbus_data_user *const du = dc->du; 133 134 req->xb.watch = 0; 135 req->xb_id = xenbus_id_allocate(&du->replies, &req->xb); 136 137 KASSERT(du->outstanding_requests < INT_MAX); 138 du->outstanding_requests++; 139 140 xenbus_xb_write(req->req_type, req->xb_id, tx_id, 141 wreqs, num_wreqs); 142} 143 144static void 145watch_write_req_string(struct write_req **wreqp, const char *string) 146{ 147 struct write_req *wreq = (*wreqp)++; 148 int l = strlen(string); 149 wreq->len = l+1; 150 wreq->data = string; 151} 152 153static void 154make_watch_request(struct rumpxenbus_data_common *dc, 155 struct xenbus_dev_request *req, 156 uint32_t tx_id, struct xenbus_dev_watch *watch) 157{ 158 struct write_req wreqs[2], *wreq = wreqs; 159 watch_write_req_string(&wreq, watch->path); 160 watch_write_req_string(&wreq, watch->xb.token); 161 KASSERT((char*)wreq == (char*)wreqs + sizeof(wreqs)); 162 163 req->u.watch = watch; 164 make_request(dc, req, tx_id, wreqs, 2); 165} 166 167static void 168forward_request(struct rumpxenbus_data_common *dc, struct xenbus_dev_request *req) 169{ 170 struct write_req wreq = { 171 dc->wbuf.buffer + sizeof(dc->wbuf.msg), 172 dc->wbuf_used - sizeof(dc->wbuf.msg), 173 }; 174 175 make_request(dc, req, dc->wbuf.msg.tx_id, &wreq, 1); 176} 177 178static _Bool 179watch_message_parse_string(const char **p, const char *end, 180 const char **string_r) 181{ 182 const char *nul = memchr(*p, 0, end - *p); 183 if (!nul) 184 return 0; 185 186 *string_r = *p; 187 *p = nul+1; 188 189 return 1; 190} 191 192static _Bool 193watch_message_parse(const struct xsd_sockmsg *msg, 194 const char **path_r, const char **token_r) 195{ 196 const char *begin = (const char*)msg; 197 const char *p = begin + sizeof(*msg); 198 const char *end = p + msg->len; 199 KASSERT(p <= end); 200 201 return 202 watch_message_parse_string(&p, end, path_r) && 203 watch_message_parse_string(&p, end, token_r); 204} 205 206int 207rumpxenbus_process_request(struct rumpxenbus_data_common *dc) 208{ 209 struct rumpxenbus_data_user *const du = dc->du; 210 struct xenbus_dev_request *req; 211 struct xenbus_dev_transaction *trans; 212 struct xenbus_dev_watch *watch_free = 0, *watch; 213 const char *wpath, *wtoken; 214 int err; 215 216 DPRINTF(("/dev/xen/xenbus[%p,du=%p]: request, type=%d\n", 217 dc,du, dc->wbuf.msg.type)); 218 219 req = xbd_malloc(sizeof(*req)); 220 if (!req) { 221 err = ENOMEM; 222 goto end; 223 } 224 req->user_id = dc->wbuf.msg.req_id; 225 req->req_type = dc->wbuf.msg.type; 226 227 switch (dc->wbuf.msg.type) { 228 case XS_DIRECTORY: 229 case XS_READ: 230 case XS_GET_PERMS: 231 case XS_GET_DOMAIN_PATH: 232 case XS_IS_DOMAIN_INTRODUCED: 233 case XS_WRITE: 234 case XS_MKDIR: 235 case XS_RM: 236 case XS_SET_PERMS: 237 if (dc->wbuf.msg.tx_id) { 238 if (!find_transaction(dc, dc->wbuf.msg.tx_id)) 239 WTROUBLE("unknown transaction"); 240 } 241 forward_request(dc, req); 242 break; 243 244 case XS_TRANSACTION_START: 245 if (dc->wbuf.msg.tx_id) 246 WTROUBLE("nested transaction"); 247 req->u.trans = xbd_malloc(sizeof(*req->u.trans)); 248 if (!req->u.trans) { 249 err = ENOMEM; 250 goto end; 251 } 252 forward_request(dc, req); 253 break; 254 255 case XS_TRANSACTION_END: 256 if (!dc->wbuf.msg.tx_id) 257 WTROUBLE("ending zero transaction"); 258 req->u.trans = trans = find_transaction(dc, dc->wbuf.msg.tx_id); 259 if (!trans) 260 WTROUBLE("ending unknown transaction"); 261 LIST_REMOVE(trans, entry); /* prevent more reqs using it */ 262 forward_request(dc, req); 263 break; 264 265 case XS_WATCH: 266 if (dc->wbuf.msg.tx_id) 267 WTROUBLE("XS_WATCH with transaction"); 268 if (!watch_message_parse(&dc->wbuf.msg, &wpath, &wtoken)) 269 WTROUBLE("bad XS_WATCH message"); 270 271 watch = watch_free = xbd_malloc(sizeof(*watch)); 272 if (!watch) { 273 err = ENOMEM; 274 goto end; 275 } 276 277 watch->path = xbd_strdup(wpath); 278 watch->user_token = xbd_strdup(wtoken); 279 if (!watch->path || !watch->user_token) { 280 err = ENOMEM; 281 goto end; 282 } 283 284 watch->xb.events = &du->replies; 285 xenbus_watch_prepare(&watch->xb); 286 287 watch_free = 0; /* we are committed */ 288 watch->visible_to_user = 0; 289 LIST_INSERT_HEAD(&du->watches, watch, entry); 290 make_watch_request(dc, req, dc->wbuf.msg.tx_id, watch); 291 break; 292 293 case XS_UNWATCH: 294 if (dc->wbuf.msg.tx_id) 295 WTROUBLE("XS_UNWATCH with transaction"); 296 if (!watch_message_parse(&dc->wbuf.msg, &wpath, &wtoken)) 297 WTROUBLE("bad XS_WATCH message"); 298 299 watch = find_visible_watch(dc, wpath, wtoken); 300 if (!watch) 301 WTROUBLE("unwatch nonexistent watch"); 302 303 watch->visible_to_user = 0; 304 make_watch_request(dc, req, dc->wbuf.msg.tx_id, watch); 305 break; 306 307 default: 308 WTROUBLE("unknown request message type"); 309 } 310 311 err = 0; 312end: 313 if (watch_free) 314 free_watch(watch_free); 315 return err; 316} 317 318/*----- response and watch event handling (reads from the device) -----*/ 319 320static struct xsd_sockmsg* 321process_watch_event(struct rumpxenbus_data_common *dc, struct xenbus_event *event, 322 struct xenbus_dev_watch *watch, 323 void (**mfree_r)(void*)) 324{ 325 326 /* We need to make a new XS_WATCH_EVENT message because the 327 * one from xenstored (a) isn't visible to us here and (b) 328 * anyway has the wrong token in it. */ 329 330 DPRINTF(("/dev/xen/xenbus[%p]: watch event," 331 " wpath=%s user_token=%s epath=%s xb.token=%s\n", 332 dc, 333 watch->path, watch->user_token, 334 event->path, watch->xb.token)); 335 336 /* Define the parts of the message */ 337 338#define WATCH_MESSAGE_PART_STRING(PART,x) \ 339 PART(strlen((x)) + 1, memcpy(p, (x), sz)) 340 341#define WATCH_MESSAGE_PARTS(PART) \ 342 PART(sizeof(struct xsd_sockmsg), (void)0) \ 343 WATCH_MESSAGE_PART_STRING(PART,event->path) \ 344 WATCH_MESSAGE_PART_STRING(PART,watch->user_token) 345 346 /* Compute the size */ 347 348 size_t totalsz = 0; 349 size_t sz = 0; 350 351#define WATCH_MESSAGE_PART_ADD_SIZE(calcpartsz, fill) \ 352 totalsz += (calcpartsz); 353 354 WATCH_MESSAGE_PARTS(WATCH_MESSAGE_PART_ADD_SIZE); 355 356 DPRINTF(("/dev/xen/xenbus: watch event allocating %lu\n", 357 (unsigned long)totalsz)); 358 359 /* Allocate it and fill in the header */ 360 361 struct xsd_sockmsg *reply = xbd_malloc(totalsz); 362 if (!reply) { 363 printf("xenbus dev: out of memory for watch event" 364 " wpath=`%s' epath=`%s'\n", 365 watch->path, event->path); 366 dc->queued_enomem = 1; 367 goto end; 368 } 369 370 bzero(reply, sizeof(*reply)); 371 reply->type = XS_WATCH_EVENT; 372 reply->len = totalsz - sizeof(*reply); 373 374 char *p = (void*)reply; 375 376 /* Fill in the rest of the message */ 377 378#define WATCH_MESSAGE_PART_ADD(calcpartsz, fill) \ 379 sz = (calcpartsz); \ 380 fill; \ 381 p += sz; 382 383 WATCH_MESSAGE_PARTS(WATCH_MESSAGE_PART_ADD); 384 385 KASSERT(p == (const char*)reply + totalsz); 386 387 /* Now we are done */ 388 389end: 390 xenbus_free(event); 391 *mfree_r = xbd_free; 392 return reply; 393} 394 395/* Returned value is from malloc() */ 396static struct xsd_sockmsg* 397process_response(struct rumpxenbus_data_common *dc, struct xenbus_dev_request *req, 398 void (**mfree_r)(void*)) 399{ 400 struct rumpxenbus_data_user *const du = dc->du; 401 struct xenbus_dev_watch *watch; 402 struct xsd_sockmsg *msg = req->xb.reply; 403 404 msg->req_id = req->user_id; 405 406 _Bool error = msg->type == XS_ERROR; 407 KASSERT(error || msg->type == req->req_type); 408 409 DPRINTF(("/dev/xen/xenbus[%p,du=%p]:" 410 " response, req_type=%d msg->type=%d\n", 411 dc,du, req->req_type, msg->type)); 412 413 switch (req->req_type) { 414 415 case XS_TRANSACTION_START: 416 if (error) 417 break; 418 KASSERT(msg->len >= 2); 419 KASSERT(!((uint8_t*)(msg+1))[msg->len-1]); 420 req->u.trans->tx_id = 421 strtoul((char*)&msg + sizeof(*msg), 422 0, 0); 423 LIST_INSERT_HEAD(&du->transactions, req->u.trans, 424 entry); 425 break; 426 427 case XS_TRANSACTION_END: 428 xbd_free(req->u.trans); 429 break; 430 431 case XS_WATCH: 432 watch = req->u.watch; 433 if (error) 434 goto do_unwatch; 435 watch->visible_to_user = 1; 436 break; 437 438 case XS_UNWATCH: 439 KASSERT(!error); 440 watch = req->u.watch; 441 do_unwatch: 442 KASSERT(!watch->visible_to_user); 443 LIST_REMOVE(watch, entry); 444 xenbus_watch_release(&watch->xb); 445 free_watch(watch); 446 break; 447 448 } 449 450 xenbus_id_release(req->xb_id); 451 xbd_free(req); 452 KASSERT(du->outstanding_requests > 0); 453 du->outstanding_requests--; 454 455 *mfree_r = xenbus_free; 456 return msg; 457} 458 459static struct xsd_sockmsg* 460process_event(struct rumpxenbus_data_common *dc, struct xenbus_event *event, 461 void (**mfree_r)(void*)) 462{ 463 if (event->watch) { 464 struct xenbus_dev_watch *watch = 465 container_of(event->watch, struct xenbus_dev_watch, xb); 466 467 return process_watch_event(dc, event, watch, mfree_r); 468 469 } else { 470 struct xenbus_dev_request *req = 471 container_of(event, struct xenbus_dev_request, xb); 472 473 return process_response(dc, req, mfree_r); 474 } 475 476} 477 478struct xsd_sockmsg* 479rumpxenbus_next_event_msg(struct rumpxenbus_data_common *dc, 480 _Bool block, 481 void (**mfree_r)(void*)) 482/* If !!block, always blocks and always returns successfully. 483 * If !block, stores err_r_if_nothing into *err_r rather than blocking. 484 485 * If !!err_r, will block iff user process read should block: 486 * will either return successfully, or set *err_r and return 0. 487 * 488 * Must be called with dd->lock held; may temporarily release it 489 * by calling rumpxenbus_block_{before,after}. */ 490{ 491 struct rumpxenbus_data_user *du = dc->du; 492 int nlocks; 493 DEFINE_WAIT(w); 494 spin_lock(&xenbus_req_lock); 495 496 while (STAILQ_EMPTY(&du->replies.events)) { 497 if (!block) 498 goto fail; 499 500 DPRINTF(("/dev/xen/xenbus[%p,du=%p]: about to block\n",dc,du)); 501 502 minios_add_waiter(w, du->replies.waitq); 503 spin_unlock(&xenbus_req_lock); 504 rumpxenbus_block_before(dc); 505 rumpkern_unsched(&nlocks, 0); 506 507 minios_wait(w); 508 509 rumpkern_sched(nlocks, 0); 510 rumpxenbus_block_after(dc); 511 spin_lock(&xenbus_req_lock); 512 minios_remove_waiter(w, du->replies.waitq); 513 } 514 struct xenbus_event *event = STAILQ_FIRST(&du->replies.events); 515 STAILQ_REMOVE_HEAD(&du->replies.events, entry); 516 517 spin_unlock(&xenbus_req_lock); 518 519 DPRINTF(("/dev/xen/xenbus: next_event_msg found an event %p\n",event)); 520 return process_event(dc, event, mfree_r); 521 522fail: 523 DPRINTF(("/dev/xen/xenbus: not blocking, returning no event\n")); 524 spin_unlock(&xenbus_req_lock); 525 return 0; 526} 527 528/*----- more exciting reading -----*/ 529 530static void 531xenbus_dev_xb_wakeup(struct xenbus_event_queue *queue) 532{ 533 /* called with req_lock held */ 534 struct rumpxenbus_data_user *du = 535 container_of(queue, struct rumpxenbus_data_user, replies); 536 DPRINTF(("/dev/xen/xenbus[queue=%p,du=%p]: wakeup...\n",queue,du)); 537 minios_wake_up(&du->replies.waitq); 538 rumpxenbus_dev_xb_wakeup(du->c); 539} 540 541void 542rumpxenbus_dev_restart_wakeup(struct rumpxenbus_data_common *dc) 543{ 544 struct rumpxenbus_data_user *du = dc->du; 545 spin_lock(&xenbus_req_lock); 546 minios_wake_up(&du->replies.waitq); 547 spin_unlock(&xenbus_req_lock); 548} 549 550void 551rumpxenbus_dev_user_shutdown(struct rumpxenbus_data_common *dc) 552{ 553 struct rumpxenbus_data_user *du = dc->du; 554 for (;;) { 555 DPRINTF(("/dev/xen/xenbus[%p,du=%p]: close loop\n",dc,du)); 556 /* We need to go round this again and again because 557 * there might be requests in flight. Eg if the 558 * user has an XS_WATCH in flight we have to wait for it 559 * to be done and then unwatch it again. */ 560 561 struct xenbus_dev_watch *watch, *watch_tmp; 562 LIST_FOREACH_SAFE(watch, &du->watches, entry, watch_tmp) { 563 DPRINTF(("/dev/xen/xenbus: close watch %p %d\n", 564 watch, watch->visible_to_user)); 565 if (watch->visible_to_user) { 566 /* mirrors process_request XS_UNWATCH */ 567 watch->destroy.req_type = XS_UNWATCH; 568 watch->visible_to_user = 0; 569 make_watch_request(dc, &watch->destroy, 0, 570 watch); 571 } 572 } 573 574 struct xenbus_dev_transaction *trans, *trans_tmp; 575 const struct write_req trans_end_data = { "F", 2 }; 576 LIST_FOREACH_SAFE(trans, &du->transactions, entry, trans_tmp) { 577 DPRINTF(("/dev/xen/xenbus: close transaction" 578 " %p %lx\n", 579 trans, (unsigned long)trans->tx_id)); 580 /* mirrors process_request XS_TRANSACTION_END */ 581 trans->destroy.req_type = XS_TRANSACTION_END; 582 trans->destroy.u.trans = trans; 583 LIST_REMOVE(trans, entry); 584 make_request(dc, &trans->destroy, trans->tx_id, 585 &trans_end_data, 1); 586 } 587 588 DPRINTF(("/dev/xen/xenbus: close outstanding=%d\n", 589 du->outstanding_requests)); 590 KASSERT(du->outstanding_requests >= 0); 591 if (!du->outstanding_requests) 592 break; 593 594 void (*dfree)(void*); 595 596 struct xsd_sockmsg *discard = 597 rumpxenbus_next_event_msg(dc, 1, &dfree); 598 599 KASSERT(discard); 600 dfree(discard); 601 } 602 603 KASSERT(!du->outstanding_requests); 604 KASSERT(LIST_EMPTY(&du->transactions)); 605 KASSERT(LIST_EMPTY(&du->watches)); 606 607 xbd_free(du); 608 dc->du = NULL; 609} 610 611int 612rumpxenbus_dev_user_open(struct rumpxenbus_data_common *dc) 613{ 614 assert(!dc->du); 615 616 struct rumpxenbus_data_user *du = dc->du = xbd_malloc(sizeof(*dc->du)); 617 if (!du) 618 return ENOMEM; 619 620 DPRINTF(("/dev/xen/xenbus[%p,dd=%p]: open: user...\n",dc,du)); 621 622 du->c = dc; 623 du->outstanding_requests = 0; 624 LIST_INIT(&du->transactions); 625 LIST_INIT(&du->watches); 626 xenbus_event_queue_init(&du->replies); 627 du->replies.wakeup = xenbus_dev_xb_wakeup; 628 629 dc->wbuf_used = 0; 630 dc->queued_enomem = 0; 631 632 return 0; 633} 634