1 /* $NetBSD: xenbus_xs.c,v 1.18 2009/04/28 05:44:43 cegger Exp $ */ 2 /****************************************************************************** 3 * xenbus_xs.c 4 * 5 * This is the kernel equivalent of the "xs" library. We don't need everything 6 * and we use xenbus_comms for communication. 7 * 8 * Copyright (C) 2005 Rusty Russell, IBM Corporation 9 * 10 * This file may be distributed separately from the Linux kernel, or 11 * incorporated into other software packages, subject to the following license: 12 * 13 * Permission is hereby granted, free of charge, to any person obtaining a copy 14 * of this source file (the "Software"), to deal in the Software without 15 * restriction, including without limitation the rights to use, copy, modify, 16 * merge, publish, distribute, sublicense, and/or sell copies of the Software, 17 * and to permit persons to whom the Software is furnished to do so, subject to 18 * the following conditions: 19 * 20 * The above copyright notice and this permission notice shall be included in 21 * all copies or substantial portions of the Software. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 28 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 29 * IN THE SOFTWARE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: xenbus_xs.c,v 1.18 2009/04/28 05:44:43 cegger Exp $"); 34 35 #if 0 36 #define DPRINTK(fmt, args...) \ 37 printf("xenbus_xs (%s:%d) " fmt ".\n", __func__, __LINE__, ##args) 38 #else 39 #define DPRINTK(fmt, args...) ((void)0) 40 #endif 41 42 #include <sys/types.h> 43 #include <sys/null.h> 44 #include <sys/errno.h> 45 #include <sys/malloc.h> 46 #include <sys/systm.h> 47 #include <sys/param.h> 48 #include <sys/proc.h> 49 #include <sys/mutex.h> 50 #include <sys/kthread.h> 51 #include <sys/simplelock.h> 52 53 #include <machine/stdarg.h> 54 55 #include <xen/xen.h> /* for xendomain_is_dom0() */ 56 #include <xen/xenbus.h> 57 #include "xenbus_comms.h" 58 59 #define streq(a, b) (strcmp((a), (b)) == 0) 60 61 struct xs_stored_msg { 62 SIMPLEQ_ENTRY(xs_stored_msg) msg_next; 63 64 struct xsd_sockmsg hdr; 65 66 union { 67 /* Queued replies. */ 68 struct { 69 char *body; 70 } reply; 71 72 /* Queued watch events. */ 73 struct { 74 struct xenbus_watch *handle; 75 char **vec; 76 unsigned int vec_size; 77 } watch; 78 } u; 79 }; 80 81 struct xs_handle { 82 /* A list of replies. Currently only one will ever be outstanding. */ 83 SIMPLEQ_HEAD(, xs_stored_msg) reply_list; 84 struct simplelock reply_lock; 85 kmutex_t xs_lock; /* serialize access to xenstore */ 86 int suspend_spl; 87 88 }; 89 90 static struct xs_handle xs_state; 91 92 /* List of registered watches, and a lock to protect it. */ 93 static SLIST_HEAD(, xenbus_watch) watches = 94 SLIST_HEAD_INITIALIZER(watches); 95 static struct simplelock watches_lock = SIMPLELOCK_INITIALIZER; 96 97 /* List of pending watch callback events, and a lock to protect it. */ 98 static SIMPLEQ_HEAD(, xs_stored_msg) watch_events = 99 SIMPLEQ_HEAD_INITIALIZER(watch_events); 100 static struct simplelock watch_events_lock = SIMPLELOCK_INITIALIZER; 101 102 static int 103 get_error(const char *errorstring) 104 { 105 unsigned int i; 106 107 for (i = 0; !streq(errorstring, xsd_errors[i].errstring); i++) { 108 if (i == (sizeof(xsd_errors) / sizeof(xsd_errors[0]) - 1)) { 109 printf( 110 "XENBUS xen store gave: unknown error %s", 111 errorstring); 112 return EINVAL; 113 } 114 } 115 return xsd_errors[i].errnum; 116 } 117 118 static void * 119 read_reply(enum xsd_sockmsg_type *type, unsigned int *len) 120 { 121 struct xs_stored_msg *msg; 122 char *body; 123 int s; 124 125 simple_lock(&xs_state.reply_lock); 126 s = spltty(); 127 128 while (SIMPLEQ_EMPTY(&xs_state.reply_list)) { 129 ltsleep(&xs_state.reply_list, PRIBIO, "rplq", 0, 130 &xs_state.reply_lock); 131 } 132 133 msg = SIMPLEQ_FIRST(&xs_state.reply_list); 134 SIMPLEQ_REMOVE_HEAD(&xs_state.reply_list, msg_next); 135 136 splx(s); 137 simple_unlock(&xs_state.reply_lock); 138 139 *type = msg->hdr.type; 140 if (len) 141 *len = msg->hdr.len; 142 body = msg->u.reply.body; 143 DPRINTK("read_reply: type %d body %s", 144 msg->hdr.type, body); 145 146 free(msg, M_DEVBUF); 147 148 return body; 149 } 150 151 #if 0 152 /* Emergency write. */ 153 void 154 xenbus_debug_write(const char *str, unsigned int count) 155 { 156 struct xsd_sockmsg msg = { 0 }; 157 158 msg.type = XS_DEBUG; 159 msg.len = sizeof("print") + count + 1; 160 161 xb_write(&msg, sizeof(msg)); 162 xb_write("print", sizeof("print")); 163 xb_write(str, count); 164 xb_write("", 1); 165 } 166 #endif 167 168 int 169 xenbus_dev_request_and_reply(struct xsd_sockmsg *msg, void**reply) 170 { 171 int err = 0, s; 172 173 s = spltty(); 174 mutex_enter(&xs_state.xs_lock); 175 err = xb_write(msg, sizeof(*msg) + msg->len); 176 if (err) { 177 msg->type = XS_ERROR; 178 *reply = NULL; 179 } else { 180 *reply = read_reply(&msg->type, &msg->len); 181 } 182 mutex_exit(&xs_state.xs_lock); 183 splx(s); 184 185 return err; 186 } 187 188 /* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */ 189 static int 190 xs_talkv(struct xenbus_transaction *t, 191 enum xsd_sockmsg_type type, 192 const struct iovec *iovec, 193 unsigned int num_vecs, 194 unsigned int *len, 195 char **retbuf) 196 { 197 struct xsd_sockmsg msg; 198 unsigned int i; 199 int err, s; 200 void *ret; 201 202 msg.tx_id = (uint32_t)(unsigned long)t; 203 msg.req_id = 0; 204 msg.type = type; 205 msg.len = 0; 206 for (i = 0; i < num_vecs; i++) 207 msg.len += iovec[i].iov_len; 208 209 s = spltty(); 210 mutex_enter(&xs_state.xs_lock); 211 212 DPRINTK("write msg"); 213 err = xb_write(&msg, sizeof(msg)); 214 DPRINTK("write msg err %d", err); 215 if (err) { 216 mutex_exit(&xs_state.xs_lock); 217 splx(s); 218 return (err); 219 } 220 221 for (i = 0; i < num_vecs; i++) { 222 DPRINTK("write iovect"); 223 err = xb_write(iovec[i].iov_base, iovec[i].iov_len); 224 DPRINTK("write iovect err %d", err); 225 if (err) { 226 mutex_exit(&xs_state.xs_lock); 227 splx(s); 228 return (err); 229 } 230 } 231 232 DPRINTK("read"); 233 ret = read_reply(&msg.type, len); 234 DPRINTK("read done"); 235 236 mutex_exit(&xs_state.xs_lock); 237 splx(s); 238 239 if (msg.type == XS_ERROR) { 240 err = get_error(ret); 241 free(ret, M_DEVBUF); 242 return (err); 243 } 244 245 KASSERT(msg.type == type); 246 if (retbuf != NULL) 247 *retbuf = ret; 248 else 249 free(ret, M_DEVBUF); 250 return 0; 251 } 252 253 /* Simplified version of xs_talkv: single message. */ 254 static int 255 xs_single(struct xenbus_transaction *t, 256 enum xsd_sockmsg_type type, 257 const char *string, 258 unsigned int *len, 259 char **ret) 260 { 261 struct iovec iovec; 262 263 /* xs_talkv only reads iovec */ 264 iovec.iov_base = __UNCONST(string); 265 iovec.iov_len = strlen(string) + 1; 266 return xs_talkv(t, type, &iovec, 1, len, ret); 267 } 268 269 static unsigned int 270 count_strings(const char *strings, unsigned int len) 271 { 272 unsigned int num; 273 const char *p; 274 275 for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1) 276 num++; 277 278 return num; 279 } 280 281 /* Return the path to dir with /name appended. Buffer must be kfree()'ed. */ 282 static char * 283 join(const char *dir, const char *name) 284 { 285 char *buffer; 286 287 buffer = malloc(strlen(dir) + strlen("/") + strlen(name) + 1, 288 M_DEVBUF, M_NOWAIT); 289 if (buffer == NULL) 290 return NULL; 291 292 strcpy(buffer, dir); 293 if (!streq(name, "")) { 294 strcat(buffer, "/"); 295 strcat(buffer, name); 296 } 297 298 return buffer; 299 } 300 301 static char ** 302 split(char *strings, unsigned int len, unsigned int *num) 303 { 304 char *p, **ret; 305 306 /* Count the strings. */ 307 *num = count_strings(strings, len); 308 309 /* Transfer to one big alloc for easy freeing. */ 310 ret = malloc(*num * sizeof(char *) + len, M_DEVBUF, M_NOWAIT); 311 if (!ret) { 312 free(strings, M_DEVBUF); 313 return NULL; 314 } 315 memcpy(&ret[*num], strings, len); 316 free(strings, M_DEVBUF); 317 318 strings = (char *)&ret[*num]; 319 for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1) 320 ret[(*num)++] = p; 321 322 return ret; 323 } 324 325 int 326 xenbus_directory(struct xenbus_transaction *t, 327 const char *dir, const char *node, unsigned int *num, 328 char ***retbuf) 329 { 330 char *strings, *path; 331 unsigned int len; 332 int err; 333 334 path = join(dir, node); 335 if (path == NULL) 336 return ENOMEM; 337 338 err = xs_single(t, XS_DIRECTORY, path, &len, &strings); 339 DPRINTK("xs_single %d %d", err, len); 340 free(path, M_DEVBUF); 341 if (err) 342 return err; 343 344 DPRINTK("xs_single strings %s", strings); 345 *retbuf = split(strings, len, num); 346 if (*retbuf == NULL) 347 return ENOMEM; 348 return 0; 349 } 350 351 /* Check if a path exists. Return 1 if it does. */ 352 int 353 xenbus_exists(struct xenbus_transaction *t, 354 const char *dir, const char *node) 355 { 356 char **d; 357 int dir_n, err; 358 359 err = xenbus_directory(t, dir, node, &dir_n, &d); 360 if (err) 361 return 0; 362 free(d, M_DEVBUF); 363 return 1; 364 } 365 366 /* Get the value of a single file. 367 * Returns a kmalloced value: call free() on it after use. 368 * len indicates length in bytes. 369 */ 370 int 371 xenbus_read(struct xenbus_transaction *t, 372 const char *dir, const char *node, unsigned int *len, 373 char **ret) 374 { 375 char *path; 376 int err; 377 378 path = join(dir, node); 379 if (path == NULL) 380 return ENOMEM; 381 382 err = xs_single(t, XS_READ, path, len, ret); 383 free(path, M_DEVBUF); 384 return err; 385 } 386 387 /* Read a node and convert it to unsigned long. */ 388 int 389 xenbus_read_ul(struct xenbus_transaction *t, 390 const char *dir, const char *node, unsigned long *val, 391 int base) 392 { 393 char *string, *ep; 394 int err; 395 396 err = xenbus_read(t, dir, node, NULL, &string); 397 if (err) 398 return err; 399 *val = strtoul(string, &ep, base); 400 if (*ep != '\0') { 401 free(string, M_DEVBUF); 402 return EFTYPE; 403 } 404 free(string, M_DEVBUF); 405 return 0; 406 } 407 408 /* Read a node and convert it to unsigned long long. */ 409 int 410 xenbus_read_ull(struct xenbus_transaction *t, 411 const char *dir, const char *node, unsigned long long *val, 412 int base) 413 { 414 char *string, *ep; 415 int err; 416 417 err = xenbus_read(t, dir, node, NULL, &string); 418 if (err) 419 return err; 420 *val = strtoull(string, &ep, base); 421 if (*ep != '\0') { 422 free(string, M_DEVBUF); 423 return EFTYPE; 424 } 425 free(string, M_DEVBUF); 426 return 0; 427 } 428 429 /* Write the value of a single file. 430 * Returns -err on failure. 431 */ 432 int 433 xenbus_write(struct xenbus_transaction *t, 434 const char *dir, const char *node, const char *string) 435 { 436 const char *path; 437 struct iovec iovec[2]; 438 int ret; 439 440 path = join(dir, node); 441 if (path == NULL) 442 return ENOMEM; 443 444 /* xs_talkv only reads iovec */ 445 iovec[0].iov_base = __UNCONST(path); 446 iovec[0].iov_len = strlen(path) + 1; 447 iovec[1].iov_base = __UNCONST(string); 448 iovec[1].iov_len = strlen(string); 449 450 ret = xs_talkv(t, XS_WRITE, iovec, 2, NULL, NULL); 451 return ret; 452 } 453 454 /* Create a new directory. */ 455 int 456 xenbus_mkdir(struct xenbus_transaction *t, 457 const char *dir, const char *node) 458 { 459 char *path; 460 int ret; 461 462 path = join(dir, node); 463 if (path == NULL) 464 return ENOMEM; 465 466 ret = xs_single(t, XS_MKDIR, path, NULL, NULL); 467 free(path, M_DEVBUF); 468 return ret; 469 } 470 471 /* Destroy a file or directory (directories must be empty). */ 472 int xenbus_rm(struct xenbus_transaction *t, const char *dir, const char *node) 473 { 474 char *path; 475 int ret; 476 477 path = join(dir, node); 478 if (path == NULL) 479 return ENOMEM; 480 481 ret = xs_single(t, XS_RM, path, NULL, NULL); 482 free(path, M_DEVBUF); 483 return ret; 484 } 485 486 /* Start a transaction: changes by others will not be seen during this 487 * transaction, and changes will not be visible to others until end. 488 * MUST BE CALLED AT IPL_TTY ! 489 */ 490 struct xenbus_transaction * 491 xenbus_transaction_start(void) 492 { 493 char *id_str; 494 unsigned long id, err; 495 496 err = xs_single(NULL, XS_TRANSACTION_START, "", NULL, &id_str); 497 if (err) { 498 return NULL; 499 } 500 501 id = strtoul(id_str, NULL, 0); 502 free(id_str, M_DEVBUF); 503 504 return (struct xenbus_transaction *)id; 505 } 506 507 /* End a transaction. 508 * If abandon is true, transaction is discarded instead of committed. 509 * MUST BE CALLED AT IPL_TTY ! 510 */ 511 int xenbus_transaction_end(struct xenbus_transaction *t, int abort) 512 { 513 char abortstr[2]; 514 int err; 515 516 if (abort) 517 strcpy(abortstr, "F"); 518 else 519 strcpy(abortstr, "T"); 520 521 err = xs_single(t, XS_TRANSACTION_END, abortstr, NULL, NULL); 522 523 return err; 524 } 525 526 /* Single read and scanf: returns -errno or num scanned. */ 527 int 528 xenbus_scanf(struct xenbus_transaction *t, 529 const char *dir, const char *node, const char *fmt, ...) 530 { 531 va_list ap; 532 int ret; 533 char *val; 534 535 ret = xenbus_read(t, dir, node, NULL, &val); 536 if (ret) 537 return ret; 538 539 va_start(ap, fmt); 540 //ret = vsscanf(val, fmt, ap); 541 ret = ENXIO; 542 printf("xb_scanf format %s in %s\n", fmt, val); 543 va_end(ap); 544 free(val, M_DEVBUF); 545 return ret; 546 } 547 548 /* Single printf and write: returns -errno or 0. */ 549 int 550 xenbus_printf(struct xenbus_transaction *t, 551 const char *dir, const char *node, const char *fmt, ...) 552 { 553 va_list ap; 554 int ret; 555 #define PRINTF_BUFFER_SIZE 4096 556 char *printf_buffer; 557 558 printf_buffer = malloc(PRINTF_BUFFER_SIZE, M_DEVBUF, M_NOWAIT); 559 if (printf_buffer == NULL) 560 return ENOMEM; 561 562 va_start(ap, fmt); 563 ret = vsnprintf(printf_buffer, PRINTF_BUFFER_SIZE, fmt, ap); 564 va_end(ap); 565 566 KASSERT(ret < PRINTF_BUFFER_SIZE); 567 ret = xenbus_write(t, dir, node, printf_buffer); 568 569 free(printf_buffer, M_DEVBUF); 570 571 return ret; 572 } 573 574 /* Takes tuples of names, scanf-style args, and void **, NULL terminated. */ 575 int 576 xenbus_gather(struct xenbus_transaction *t, const char *dir, ...) 577 { 578 va_list ap; 579 const char *name; 580 int ret = 0; 581 582 va_start(ap, dir); 583 while (ret == 0 && (name = va_arg(ap, char *)) != NULL) { 584 const char *fmt = va_arg(ap, char *); 585 void *result = va_arg(ap, void *); 586 char *p; 587 588 ret = xenbus_read(t, dir, name, NULL, &p); 589 if (ret) 590 break; 591 if (fmt) { 592 // XXX if (sscanf(p, fmt, result) == 0) 593 ret = -EINVAL; 594 free(p, M_DEVBUF); 595 } else 596 *(char **)result = p; 597 } 598 va_end(ap); 599 return ret; 600 } 601 602 static int 603 xs_watch(const char *path, const char *token) 604 { 605 struct iovec iov[2]; 606 607 /* xs_talkv only reads iovec */ 608 iov[0].iov_base = __UNCONST(path); 609 iov[0].iov_len = strlen(path) + 1; 610 iov[1].iov_base = __UNCONST(token); 611 iov[1].iov_len = strlen(token) + 1; 612 613 return xs_talkv(NULL, XS_WATCH, iov, 2, NULL, NULL); 614 } 615 616 static int 617 xs_unwatch(const char *path, const char *token) 618 { 619 struct iovec iov[2]; 620 621 /* xs_talkv only reads iovec */ 622 iov[0].iov_base = __UNCONST(path); 623 iov[0].iov_len = strlen(path) + 1; 624 iov[1].iov_base = __UNCONST(token); 625 iov[1].iov_len = strlen(token) + 1; 626 627 return xs_talkv(NULL, XS_UNWATCH, iov, 2, NULL, NULL); 628 } 629 630 static struct xenbus_watch * 631 find_watch(const char *token) 632 { 633 struct xenbus_watch *i, *cmp; 634 635 cmp = (void *)strtoul(token, NULL, 16); 636 637 SLIST_FOREACH(i, &watches, watch_next) { 638 if (i == cmp) 639 return i; 640 } 641 642 return NULL; 643 } 644 645 /* Register callback to watch this node. */ 646 int 647 register_xenbus_watch(struct xenbus_watch *watch) 648 { 649 /* Pointer in ascii is the token. */ 650 char token[sizeof(watch) * 2 + 1]; 651 int err; 652 int s; 653 654 snprintf(token, sizeof(token), "%lX", (long)watch); 655 656 s = spltty(); 657 658 simple_lock(&watches_lock); 659 KASSERT(find_watch(token) == 0); 660 SLIST_INSERT_HEAD(&watches, watch, watch_next); 661 simple_unlock(&watches_lock); 662 663 err = xs_watch(watch->node, token); 664 665 /* Ignore errors due to multiple registration. */ 666 if ((err != 0) && (err != EEXIST)) { 667 simple_lock(&watches_lock); 668 SLIST_REMOVE(&watches, watch, xenbus_watch, watch_next); 669 simple_unlock(&watches_lock); 670 } 671 672 splx(s); 673 674 return err; 675 } 676 677 void 678 unregister_xenbus_watch(struct xenbus_watch *watch) 679 { 680 struct xs_stored_msg *msg, *next_msg; 681 char token[sizeof(watch) * 2 + 1]; 682 int err, s; 683 684 snprintf(token, sizeof(token), "%lX", (long)watch); 685 686 s = spltty(); 687 688 simple_lock(&watches_lock); 689 KASSERT(find_watch(token)); 690 SLIST_REMOVE(&watches, watch, xenbus_watch, watch_next); 691 simple_unlock(&watches_lock); 692 693 err = xs_unwatch(watch->node, token); 694 if (err) 695 printf( 696 "XENBUS Failed to release watch %s: %i\n", 697 watch->node, err); 698 699 splx(s); 700 701 /* Cancel pending watch events. */ 702 simple_lock(&watch_events_lock); 703 for (msg = SIMPLEQ_FIRST(&watch_events); msg != NULL; msg = next_msg) { 704 next_msg = SIMPLEQ_NEXT(msg, msg_next); 705 if (msg->u.watch.handle != watch) 706 continue; 707 SIMPLEQ_REMOVE(&watch_events, msg, xs_stored_msg, msg_next); 708 free(msg->u.watch.vec, M_DEVBUF); 709 free(msg, M_DEVBUF); 710 } 711 simple_unlock(&watch_events_lock); 712 713 } 714 715 void 716 xs_suspend(void) 717 { 718 xs_state.suspend_spl = spltty(); 719 } 720 721 void 722 xs_resume(void) 723 { 724 struct xenbus_watch *watch; 725 char token[sizeof(watch) * 2 + 1]; 726 /* No need for watches_lock: the suspend_mutex is sufficient. */ 727 SLIST_FOREACH(watch, &watches, watch_next) { 728 snprintf(token, sizeof(token), "%lX", (long)watch); 729 xs_watch(watch->node, token); 730 } 731 732 splx(xs_state.suspend_spl); 733 } 734 735 static void 736 xenwatch_thread(void *unused) 737 { 738 struct xs_stored_msg *msg; 739 int s; 740 741 for (;;) { 742 tsleep(&watch_events, PRIBIO, "evtsq", 0); 743 s = spltty(); /* to block IPL_CTRL */ 744 while (!SIMPLEQ_EMPTY(&watch_events)) { 745 msg = SIMPLEQ_FIRST(&watch_events); 746 747 simple_lock(&watch_events_lock); 748 SIMPLEQ_REMOVE_HEAD(&watch_events, msg_next); 749 simple_unlock(&watch_events_lock); 750 DPRINTK("xenwatch_thread: got event"); 751 752 msg->u.watch.handle->xbw_callback( 753 msg->u.watch.handle, 754 (const char **)msg->u.watch.vec, 755 msg->u.watch.vec_size); 756 free(msg->u.watch.vec, M_DEVBUF); 757 free(msg, M_DEVBUF); 758 } 759 760 splx(s); 761 } 762 } 763 764 static int 765 process_msg(void) 766 { 767 struct xs_stored_msg *msg; 768 char *body; 769 int err, s; 770 771 msg = malloc(sizeof(*msg), M_DEVBUF, M_NOWAIT); 772 if (msg == NULL) 773 return ENOMEM; 774 775 err = xb_read(&msg->hdr, sizeof(msg->hdr)); 776 DPRINTK("xb_read hdr %d", err); 777 if (err) { 778 free(msg, M_DEVBUF); 779 return err; 780 } 781 782 body = malloc(msg->hdr.len + 1, M_DEVBUF, M_NOWAIT); 783 if (body == NULL) { 784 free(msg, M_DEVBUF); 785 return ENOMEM; 786 } 787 788 err = xb_read(body, msg->hdr.len); 789 DPRINTK("xb_read body %d", err); 790 if (err) { 791 free(body, M_DEVBUF); 792 free(msg, M_DEVBUF); 793 return err; 794 } 795 body[msg->hdr.len] = '\0'; 796 797 if (msg->hdr.type == XS_WATCH_EVENT) { 798 DPRINTK("process_msg: XS_WATCH_EVENT"); 799 msg->u.watch.vec = split(body, msg->hdr.len, 800 &msg->u.watch.vec_size); 801 if (msg->u.watch.vec == NULL) { 802 free(msg, M_DEVBUF); 803 return ENOMEM; 804 } 805 806 simple_lock(&watches_lock); 807 s = spltty(); 808 msg->u.watch.handle = find_watch( 809 msg->u.watch.vec[XS_WATCH_TOKEN]); 810 if (msg->u.watch.handle != NULL) { 811 simple_lock(&watch_events_lock); 812 SIMPLEQ_INSERT_TAIL(&watch_events, msg, msg_next); 813 wakeup(&watch_events); 814 simple_unlock(&watch_events_lock); 815 } else { 816 free(msg->u.watch.vec, M_DEVBUF); 817 free(msg, M_DEVBUF); 818 } 819 splx(s); 820 simple_unlock(&watches_lock); 821 } else { 822 DPRINTK("process_msg: type %d body %s", msg->hdr.type, body); 823 824 msg->u.reply.body = body; 825 simple_lock(&xs_state.reply_lock); 826 s = spltty(); 827 SIMPLEQ_INSERT_TAIL(&xs_state.reply_list, msg, msg_next); 828 splx(s); 829 simple_unlock(&xs_state.reply_lock); 830 wakeup(&xs_state.reply_list); 831 } 832 833 return 0; 834 } 835 836 static void 837 xenbus_thread(void *unused) 838 { 839 int err; 840 841 for (;;) { 842 err = process_msg(); 843 if (err) 844 printk("XENBUS error %d while reading message\n", err); 845 } 846 } 847 848 int 849 xs_init(device_t dev) 850 { 851 int err; 852 853 SIMPLEQ_INIT(&xs_state.reply_list); 854 simple_lock_init(&xs_state.reply_lock); 855 mutex_init(&xs_state.xs_lock, MUTEX_DEFAULT, IPL_NONE); 856 857 err = kthread_create(PRI_NONE, 0, NULL, xenwatch_thread, 858 NULL, NULL, "xenwatch"); 859 if (err) { 860 aprint_error_dev(dev, "kthread_create(xenwatch): %d\n", err); 861 return err; 862 } 863 864 err = kthread_create(PRI_NONE, 0, NULL, xenbus_thread, 865 NULL, NULL, "xenbus"); 866 if (err) { 867 aprint_error_dev(dev, "kthread_create(xenbus): %d\n", err); 868 return err; 869 } 870 871 return 0; 872 } 873 874 /* 875 * Local variables: 876 * c-file-style: "linux" 877 * indent-tabs-mode: t 878 * c-indent-level: 8 879 * c-basic-offset: 8 880 * tab-width: 8 881 * End: 882 */ 883