The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/xen/xenbus/xenbus_xs.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /******************************************************************************
    2  * xenbus_xs.c
    3  *
    4  * This is the kernel equivalent of the "xs" library.  We don't need everything
    5  * and we use xenbus_comms for communication.
    6  *
    7  * Copyright (C) 2005 Rusty Russell, IBM Corporation
    8  * 
    9  * This file may be distributed separately from the Linux kernel, or
   10  * incorporated into other software packages, subject to the following license:
   11  * 
   12  * Permission is hereby granted, free of charge, to any person obtaining a copy
   13  * of this source file (the "Software"), to deal in the Software without
   14  * restriction, including without limitation the rights to use, copy, modify,
   15  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
   16  * and to permit persons to whom the Software is furnished to do so, subject to
   17  * the following conditions:
   18  * 
   19  * The above copyright notice and this permission notice shall be included in
   20  * all copies or substantial portions of the Software.
   21  * 
   22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   25  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   27  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   28  * IN THE SOFTWARE.
   29  */
   30 
   31 
   32 #include <sys/cdefs.h>
   33 __FBSDID("$FreeBSD: releng/8.0/sys/xen/xenbus/xenbus_xs.c 192951 2009-05-28 04:03:16Z adrian $");
   34 
   35 #include <sys/param.h>
   36 #include <sys/uio.h>
   37 #include <sys/kernel.h>
   38 #include <sys/lock.h>
   39 #include <sys/mutex.h>
   40 #include <sys/sx.h>
   41 #include <sys/syslog.h>
   42 #include <sys/malloc.h>
   43 #include <sys/systm.h>
   44 #include <sys/proc.h>
   45 #include <sys/kthread.h>
   46 #include <sys/unistd.h>
   47 
   48 #include <machine/xen/xen-os.h>
   49 #include <xen/hypervisor.h>
   50 #include <machine/stdarg.h>
   51 
   52 #include <xen/xenbus/xenbusvar.h>
   53 #include <xen/xenbus/xenbus_comms.h>
   54 #include <xen/interface/hvm/params.h>
   55 
   56 #include <vm/vm.h>
   57 #include <vm/pmap.h>
   58 
   59 static int xs_process_msg(enum xsd_sockmsg_type *type);
   60 
   61 int xenwatch_running = 0;
   62 int xenbus_running = 0;
   63 int xen_store_evtchn;
   64 
   65 struct xs_stored_msg {
   66         TAILQ_ENTRY(xs_stored_msg) list;
   67 
   68         struct xsd_sockmsg hdr;
   69 
   70         union {
   71                 /* Queued replies. */
   72                 struct {
   73                         char *body;
   74                 } reply;
   75 
   76                 /* Queued watch events. */
   77                 struct {
   78                         struct xenbus_watch *handle;
   79                         char **vec;
   80                         unsigned int vec_size;
   81                 } watch;
   82         } u;
   83 };
   84 
   85 struct xs_handle {
   86         /* A list of replies. Currently only one will ever be outstanding. */
   87         TAILQ_HEAD(xs_handle_list, xs_stored_msg) reply_list;
   88         struct mtx reply_lock;
   89         int reply_waitq;
   90 
   91         /* One request at a time. */
   92         struct sx request_mutex;
   93 
   94         /* Protect transactions against save/restore. */
   95         struct sx suspend_mutex;
   96 };
   97 
   98 static struct xs_handle xs_state;
   99 
  100 /* List of registered watches, and a lock to protect it. */
  101 static LIST_HEAD(watch_list_head, xenbus_watch) watches;
  102 static struct mtx watches_lock;
  103 /* List of pending watch callback events, and a lock to protect it. */
  104 static TAILQ_HEAD(event_list_head, xs_stored_msg) watch_events;
  105 static struct mtx watch_events_lock;
  106 
  107 /*
  108  * Details of the xenwatch callback kernel thread. The thread waits on the
  109  * watch_events_waitq for work to do (queued on watch_events list). When it
  110  * wakes up it acquires the xenwatch_mutex before reading the list and
  111  * carrying out work.
  112  */
  113 static pid_t xenwatch_pid;
  114 struct sx xenwatch_mutex;
  115 static int watch_events_waitq;
  116 
  117 #define xsd_error_count (sizeof(xsd_errors) / sizeof(xsd_errors[0]))
  118 
  119 static int
  120 xs_get_error(const char *errorstring)
  121 {
  122         unsigned int i;
  123 
  124         for (i = 0; i < xsd_error_count; i++) {
  125                 if (!strcmp(errorstring, xsd_errors[i].errstring))
  126                         return (xsd_errors[i].errnum);
  127         }
  128         log(LOG_WARNING, "XENBUS xen store gave: unknown error %s",
  129             errorstring);
  130         return (EINVAL);
  131 }
  132 
  133 extern void kdb_backtrace(void);
  134 
  135 static int
  136 xs_read_reply(enum xsd_sockmsg_type *type, unsigned int *len, void **result)
  137 {
  138         struct xs_stored_msg *msg;
  139         char *body;
  140         int error;
  141 
  142         mtx_lock(&xs_state.reply_lock);
  143 
  144         while (TAILQ_EMPTY(&xs_state.reply_list)) {
  145                 while (TAILQ_EMPTY(&xs_state.reply_list)) {
  146                         error = mtx_sleep(&xs_state.reply_waitq,
  147                             &xs_state.reply_lock,
  148                             PCATCH, "xswait", hz/10);
  149                         if (error && error != EWOULDBLOCK) {
  150                                 mtx_unlock(&xs_state.reply_lock);
  151                                 return (error);
  152                         }
  153                 }
  154         }
  155 
  156         msg = TAILQ_FIRST(&xs_state.reply_list);
  157         TAILQ_REMOVE(&xs_state.reply_list, msg, list);
  158 
  159         mtx_unlock(&xs_state.reply_lock);
  160 
  161         *type = msg->hdr.type;
  162         if (len)
  163                 *len = msg->hdr.len;
  164         body = msg->u.reply.body;
  165 
  166         free(msg, M_DEVBUF);
  167         *result = body;
  168         return (0);
  169 }
  170 
  171 #if 0
  172 /* Emergency write. UNUSED*/
  173 void xenbus_debug_write(const char *str, unsigned int count)
  174 {
  175         struct xsd_sockmsg msg = { 0 };
  176 
  177         msg.type = XS_DEBUG;
  178         msg.len = sizeof("print") + count + 1;
  179 
  180         sx_xlock(&xs_state.request_mutex);
  181         xb_write(&msg, sizeof(msg));
  182         xb_write("print", sizeof("print"));
  183         xb_write(str, count);
  184         xb_write("", 1);
  185         sx_xunlock(&xs_state.request_mutex);
  186 }
  187 
  188 #endif
  189 
  190 int
  191 xenbus_dev_request_and_reply(struct xsd_sockmsg *msg, void **result)
  192 {
  193         struct xsd_sockmsg req_msg = *msg;
  194         int error;
  195 
  196         if (req_msg.type == XS_TRANSACTION_START)
  197                 sx_slock(&xs_state.suspend_mutex);
  198 
  199         sx_xlock(&xs_state.request_mutex);
  200 
  201         error = xb_write(msg, sizeof(*msg) + msg->len,
  202             &xs_state.request_mutex.lock_object);
  203         if (error) {
  204                 msg->type = XS_ERROR;
  205         } else {
  206                 error = xs_read_reply(&msg->type, &msg->len, result);
  207         }
  208 
  209         sx_xunlock(&xs_state.request_mutex);
  210 
  211         if ((msg->type == XS_TRANSACTION_END) ||
  212             ((req_msg.type == XS_TRANSACTION_START) &&
  213                 (msg->type == XS_ERROR)))
  214                 sx_sunlock(&xs_state.suspend_mutex);
  215 
  216         return (error);
  217 }
  218 
  219 /*
  220  * Send message to xs. The reply is returned in *result and should be
  221  * fred with free(*result, M_DEVBUF). Return zero on success or an
  222  * error code on failure.
  223  */
  224 static int
  225 xs_talkv(struct xenbus_transaction t, enum xsd_sockmsg_type type,
  226     const struct iovec *iovec, unsigned int num_vecs,
  227     unsigned int *len, void **result)
  228 {
  229         struct xsd_sockmsg msg;
  230         void *ret = NULL;
  231         unsigned int i;
  232         int error;
  233 
  234         msg.tx_id = t.id;
  235         msg.req_id = 0;
  236         msg.type = type;
  237         msg.len = 0;
  238         for (i = 0; i < num_vecs; i++)
  239                 msg.len += iovec[i].iov_len;
  240 
  241         sx_xlock(&xs_state.request_mutex);
  242 
  243         error = xb_write(&msg, sizeof(msg),
  244             &xs_state.request_mutex.lock_object);
  245         if (error) {
  246                 sx_xunlock(&xs_state.request_mutex);
  247                 printf("xs_talkv failed %d\n", error);
  248                 return (error);
  249         }
  250 
  251         for (i = 0; i < num_vecs; i++) {
  252                 error = xb_write(iovec[i].iov_base, iovec[i].iov_len,
  253                     &xs_state.request_mutex.lock_object);
  254                 if (error) {            
  255                         sx_xunlock(&xs_state.request_mutex);
  256                         printf("xs_talkv failed %d\n", error);
  257                         return (error);
  258                 }
  259         }
  260 
  261         error = xs_read_reply(&msg.type, len, &ret);
  262 
  263         sx_xunlock(&xs_state.request_mutex);
  264 
  265         if (error)
  266                 return (error);
  267 
  268         if (msg.type == XS_ERROR) {
  269                 error = xs_get_error(ret);
  270                 free(ret, M_DEVBUF);
  271                 return (error);
  272         }
  273 
  274 #if 0
  275         if ((xenwatch_running == 0) && (xenwatch_inline == 0)) {
  276                 xenwatch_inline = 1;
  277                 while (!TAILQ_EMPTY(&watch_events) 
  278                     && xenwatch_running == 0) {
  279                                                 
  280                         struct xs_stored_msg *wmsg = TAILQ_FIRST(&watch_events);
  281                         TAILQ_REMOVE(&watch_events, wmsg, list);
  282                                                 
  283                         wmsg->u.watch.handle->callback(
  284                                 wmsg->u.watch.handle,
  285                                 (const char **)wmsg->u.watch.vec,
  286                                 wmsg->u.watch.vec_size);
  287                         free(wmsg->u.watch.vec, M_DEVBUF);
  288                         free(wmsg, M_DEVBUF);
  289                 }
  290                 xenwatch_inline = 0;
  291         }
  292 #endif
  293         KASSERT(msg.type == type, ("bad xenstore message type"));
  294 
  295         if (result)
  296                 *result = ret;
  297         else
  298                 free(ret, M_DEVBUF);
  299 
  300         return (0);
  301 }
  302 
  303 /* Simplified version of xs_talkv: single message. */
  304 static int
  305 xs_single(struct xenbus_transaction t, enum xsd_sockmsg_type type,
  306     const char *string, unsigned int *len, void **result)
  307 {
  308         struct iovec iovec;
  309 
  310         iovec.iov_base = (void *)(uintptr_t) string;
  311         iovec.iov_len = strlen(string) + 1;
  312 
  313         return (xs_talkv(t, type, &iovec, 1, len, result));
  314 }
  315 
  316 static unsigned int
  317 count_strings(const char *strings, unsigned int len)
  318 {
  319         unsigned int num;
  320         const char *p;
  321 
  322         for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1)
  323                 num++;
  324 
  325         return num;
  326 }
  327 
  328 /* Return the path to dir with /name appended. Buffer must be kfree()'ed. */ 
  329 static char *
  330 join(const char *dir, const char *name)
  331 {
  332         char *buffer;
  333 
  334         buffer = malloc(strlen(dir) + strlen("/") + strlen(name) + 1,
  335             M_DEVBUF, M_WAITOK);
  336 
  337         strcpy(buffer, dir);
  338         if (strcmp(name, "")) {
  339                 strcat(buffer, "/");
  340                 strcat(buffer, name);
  341         }
  342 
  343         return (buffer);
  344 }
  345 
  346 static char **
  347 split(char *strings, unsigned int len, unsigned int *num)
  348 {
  349         char *p, **ret;
  350 
  351         /* Count the strings. */
  352         *num = count_strings(strings, len) + 1;
  353 
  354         /* Transfer to one big alloc for easy freeing. */
  355         ret = malloc(*num * sizeof(char *) + len, M_DEVBUF, M_WAITOK);
  356         memcpy(&ret[*num], strings, len);
  357         free(strings, M_DEVBUF);
  358 
  359         strings = (char *)&ret[*num];
  360         for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1)
  361                 ret[(*num)++] = p;
  362 
  363         ret[*num] = strings + len;
  364                 
  365         return ret;
  366 }
  367 
  368 /*
  369  * Return the contents of a directory in *result which should be freed
  370  * with free(*result, M_DEVBUF).
  371  */
  372 int
  373 xenbus_directory(struct xenbus_transaction t, const char *dir,
  374     const char *node, unsigned int *num, char ***result)
  375 {
  376         char *strings, *path;
  377         unsigned int len = 0;
  378         int error;
  379 
  380         path = join(dir, node);
  381         error = xs_single(t, XS_DIRECTORY, path, &len, (void **) &strings);
  382         free(path, M_DEVBUF);
  383         if (error)
  384                 return (error);
  385 
  386         *result = split(strings, len, num);
  387         return (0);
  388 }
  389 
  390 /*
  391  * Check if a path exists. Return 1 if it does.
  392  */
  393 int
  394 xenbus_exists(struct xenbus_transaction t, const char *dir, const char *node)
  395 {
  396         char **d;
  397         int error, dir_n;
  398 
  399         error = xenbus_directory(t, dir, node, &dir_n, &d);
  400         if (error)
  401                 return (0);
  402         free(d, M_DEVBUF);
  403         return (1);
  404 }
  405 
  406 /*
  407  * Get the value of a single file.  Returns the contents in *result
  408  * which should be freed with free(*result, M_DEVBUF) after use.
  409  * The length of the value in bytes is returned in *len.
  410  */
  411 int
  412 xenbus_read(struct xenbus_transaction t, const char *dir, const char *node,
  413     unsigned int *len, void **result)
  414 {
  415         char *path;
  416         void *ret;
  417         int error;
  418 
  419         path = join(dir, node);
  420         error = xs_single(t, XS_READ, path, len, &ret);
  421         free(path, M_DEVBUF);
  422         if (error)
  423                 return (error);
  424         *result = ret;
  425         return (0);
  426 }
  427 
  428 /*
  429  * Write the value of a single file.  Returns error on failure.
  430  */
  431 int
  432 xenbus_write(struct xenbus_transaction t, const char *dir, const char *node,
  433     const char *string)
  434 {
  435         char *path;
  436         struct iovec iovec[2];
  437         int error;
  438 
  439         path = join(dir, node);
  440 
  441         iovec[0].iov_base = (void *)(uintptr_t) path;
  442         iovec[0].iov_len = strlen(path) + 1;
  443         iovec[1].iov_base = (void *)(uintptr_t) string;
  444         iovec[1].iov_len = strlen(string);
  445 
  446         error = xs_talkv(t, XS_WRITE, iovec, 2, NULL, NULL);
  447         free(path, M_DEVBUF);
  448 
  449         return (error);
  450 }
  451 
  452 /*
  453  * Create a new directory.
  454  */
  455 int
  456 xenbus_mkdir(struct xenbus_transaction t, const char *dir, const char *node)
  457 {
  458         char *path;
  459         int ret;
  460 
  461         path = join(dir, node);
  462         ret = xs_single(t, XS_MKDIR, path, NULL, NULL);
  463         free(path, M_DEVBUF);
  464 
  465         return (ret);
  466 }
  467 
  468 /*
  469  * Destroy a file or directory (directories must be empty).
  470  */
  471 int
  472 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         ret = xs_single(t, XS_RM, path, NULL, NULL);
  479         free(path, M_DEVBUF);
  480 
  481         return (ret);
  482 }
  483 
  484 /*
  485  * Start a transaction: changes by others will not be seen during this
  486  * transaction, and changes will not be visible to others until end.
  487  */
  488 int
  489 xenbus_transaction_start(struct xenbus_transaction *t)
  490 {
  491         char *id_str;
  492         int error;
  493 
  494         sx_slock(&xs_state.suspend_mutex);
  495         error = xs_single(XBT_NIL, XS_TRANSACTION_START, "", NULL,
  496             (void **) &id_str);
  497         if (error) {
  498                 sx_sunlock(&xs_state.suspend_mutex);
  499                 return (error);
  500         }
  501 
  502         t->id = strtoul(id_str, NULL, 0);
  503         free(id_str, M_DEVBUF);
  504 
  505         return (0);
  506 }
  507 
  508 /*
  509  * End a transaction.  If abandon is true, transaction is discarded
  510  * instead of committed.
  511  */
  512 int xenbus_transaction_end(struct xenbus_transaction t, int abort)
  513 {
  514         char abortstr[2];
  515         int error;
  516 
  517         if (abort)
  518                 strcpy(abortstr, "F");
  519         else
  520                 strcpy(abortstr, "T");
  521 
  522         error = xs_single(t, XS_TRANSACTION_END, abortstr, NULL, NULL);
  523                 
  524         sx_sunlock(&xs_state.suspend_mutex);
  525 
  526         return (error);
  527 }
  528 
  529 /* Single read and scanf: returns zero or errno. */
  530 int
  531 xenbus_scanf(struct xenbus_transaction t,
  532     const char *dir, const char *node, int *scancountp, const char *fmt, ...)
  533 {
  534         va_list ap;
  535         int error, ns;
  536         char *val;
  537 
  538         error = xenbus_read(t, dir, node, NULL, (void **) &val);
  539         if (error)
  540                 return (error);
  541 
  542         va_start(ap, fmt);
  543         ns = vsscanf(val, fmt, ap);
  544         va_end(ap);
  545         free(val, M_DEVBUF);
  546         /* Distinctive errno. */
  547         if (ns == 0)
  548                 return (ERANGE);
  549         if (scancountp)
  550                 *scancountp = ns;
  551         return (0);
  552 }
  553 
  554 /* Single printf and write: returns zero or errno. */
  555 int
  556 xenbus_printf(struct xenbus_transaction t,
  557     const char *dir, const char *node, const char *fmt, ...)
  558 {
  559         va_list ap;
  560         int error, ret;
  561 #define PRINTF_BUFFER_SIZE 4096
  562         char *printf_buffer;
  563 
  564         printf_buffer = malloc(PRINTF_BUFFER_SIZE, M_DEVBUF, M_WAITOK);
  565 
  566         va_start(ap, fmt);
  567         ret = vsnprintf(printf_buffer, PRINTF_BUFFER_SIZE, fmt, ap);
  568         va_end(ap);
  569 
  570         KASSERT(ret <= PRINTF_BUFFER_SIZE-1, ("xenbus_printf: message too large"));
  571         error = xenbus_write(t, dir, node, printf_buffer);
  572 
  573         free(printf_buffer, M_DEVBUF);
  574 
  575         return (error);
  576 }
  577 
  578 /* Takes tuples of names, scanf-style args, and void **, NULL terminated. */
  579 int
  580 xenbus_gather(struct xenbus_transaction t, const char *dir, ...)
  581 {
  582         va_list ap;
  583         const char *name;
  584         int error, i;
  585 
  586         for (i = 0; i < 10000; i++)
  587                 HYPERVISOR_yield();
  588                 
  589         va_start(ap, dir);
  590         error = 0;
  591         while (error == 0 && (name = va_arg(ap, char *)) != NULL) {
  592                 const char *fmt = va_arg(ap, char *);
  593                 void *result = va_arg(ap, void *);
  594                 char *p;
  595 
  596                 error = xenbus_read(t, dir, name, NULL, (void **) &p);
  597                 if (error)
  598                         break;
  599 
  600                 if (fmt) {
  601                         if (sscanf(p, fmt, result) == 0)
  602                                 error = EINVAL;
  603                         free(p, M_DEVBUF);
  604                 } else
  605                         *(char **)result = p;
  606         }
  607         va_end(ap);
  608 
  609         return (error);
  610 }
  611 
  612 static int
  613 xs_watch(const char *path, const char *token)
  614 {
  615         struct iovec iov[2];
  616 
  617         iov[0].iov_base = (void *)(uintptr_t) path;
  618         iov[0].iov_len = strlen(path) + 1;
  619         iov[1].iov_base = (void *)(uintptr_t) token;
  620         iov[1].iov_len = strlen(token) + 1;
  621 
  622         return (xs_talkv(XBT_NIL, XS_WATCH, iov, 2, NULL, NULL));
  623 }
  624 
  625 static int
  626 xs_unwatch(const char *path, const char *token)
  627 {
  628         struct iovec iov[2];
  629 
  630         iov[0].iov_base = (void *)(uintptr_t) path;
  631         iov[0].iov_len = strlen(path) + 1;
  632         iov[1].iov_base = (void *)(uintptr_t) token;
  633         iov[1].iov_len = strlen(token) + 1;
  634 
  635         return (xs_talkv(XBT_NIL, XS_UNWATCH, iov, 2, NULL, NULL));
  636 }
  637 
  638 static struct xenbus_watch *
  639 find_watch(const char *token)
  640 {
  641         struct xenbus_watch *i, *cmp;
  642 
  643         cmp = (void *)strtoul(token, NULL, 16);
  644 
  645         LIST_FOREACH(i, &watches, list)
  646                 if (i == cmp)
  647                         return (i);
  648 
  649         return (NULL);
  650 }
  651 
  652 /* Register callback to watch this node. */
  653 int
  654 register_xenbus_watch(struct xenbus_watch *watch)
  655 {
  656         /* Pointer in ascii is the token. */
  657         char token[sizeof(watch) * 2 + 1];
  658         int error;
  659 
  660         sprintf(token, "%lX", (long)watch);
  661 
  662         sx_slock(&xs_state.suspend_mutex);
  663 
  664         mtx_lock(&watches_lock);
  665         KASSERT(find_watch(token) == NULL, ("watch already registered"));
  666         LIST_INSERT_HEAD(&watches, watch, list);
  667         mtx_unlock(&watches_lock);
  668 
  669         error = xs_watch(watch->node, token);
  670                 
  671         /* Ignore errors due to multiple registration. */
  672         if (error == EEXIST) {
  673                 mtx_lock(&watches_lock);
  674                 LIST_REMOVE(watch, list);
  675                 mtx_unlock(&watches_lock);
  676         }
  677 
  678         sx_sunlock(&xs_state.suspend_mutex);
  679 
  680         return (error);
  681 }
  682 
  683 void
  684 unregister_xenbus_watch(struct xenbus_watch *watch)
  685 {
  686         struct xs_stored_msg *msg, *tmp;
  687         char token[sizeof(watch) * 2 + 1];
  688         int error;
  689 
  690         sprintf(token, "%lX", (long)watch);
  691                 
  692         sx_slock(&xs_state.suspend_mutex);
  693 
  694         mtx_lock(&watches_lock);
  695         KASSERT(find_watch(token), ("watch not registered"));
  696         LIST_REMOVE(watch, list);
  697         mtx_unlock(&watches_lock);
  698 
  699         error = xs_unwatch(watch->node, token);
  700         if (error)
  701                 log(LOG_WARNING, "XENBUS Failed to release watch %s: %i\n",
  702                     watch->node, error);
  703 
  704         sx_sunlock(&xs_state.suspend_mutex);
  705 
  706         /* Cancel pending watch events. */
  707         mtx_lock(&watch_events_lock);
  708         TAILQ_FOREACH_SAFE(msg, &watch_events, list, tmp) {
  709                 if (msg->u.watch.handle != watch)
  710                         continue;
  711                 TAILQ_REMOVE(&watch_events, msg, list);
  712                 free(msg->u.watch.vec, M_DEVBUF);
  713                 free(msg, M_DEVBUF);
  714         }
  715         mtx_unlock(&watch_events_lock);
  716 
  717         /* Flush any currently-executing callback, unless we are it. :-) */
  718         if (curproc->p_pid != xenwatch_pid) {
  719                 sx_xlock(&xenwatch_mutex);
  720                 sx_xunlock(&xenwatch_mutex);
  721         }
  722 }
  723 
  724 void
  725 xs_suspend(void)
  726 {       
  727 
  728         sx_xlock(&xs_state.suspend_mutex);
  729         sx_xlock(&xs_state.request_mutex);
  730 }
  731 
  732 void
  733 xs_resume(void)
  734 {
  735         struct xenbus_watch *watch;
  736         char token[sizeof(watch) * 2 + 1];
  737 
  738         sx_xunlock(&xs_state.request_mutex);
  739 
  740         /* No need for watches_lock: the suspend_mutex is sufficient. */
  741         LIST_FOREACH(watch, &watches, list) {
  742                 sprintf(token, "%lX", (long)watch);
  743                 xs_watch(watch->node, token);
  744         }
  745 
  746         sx_xunlock(&xs_state.suspend_mutex);
  747 }
  748 
  749 static void
  750 xenwatch_thread(void *unused)
  751 {
  752         struct xs_stored_msg *msg;
  753 
  754         for (;;) {
  755 
  756                 mtx_lock(&watch_events_lock);
  757                 while (TAILQ_EMPTY(&watch_events))
  758                         mtx_sleep(&watch_events_waitq,
  759                             &watch_events_lock,
  760                             PWAIT | PCATCH, "waitev", hz/10);
  761 
  762                 mtx_unlock(&watch_events_lock);
  763                 sx_xlock(&xenwatch_mutex);
  764 
  765                 mtx_lock(&watch_events_lock);
  766                 msg = TAILQ_FIRST(&watch_events);
  767                 if (msg)
  768                         TAILQ_REMOVE(&watch_events, msg, list);
  769                 mtx_unlock(&watch_events_lock);
  770 
  771                 if (msg != NULL) {
  772                         /*
  773                          * XXX There are messages coming in with a NULL callback.
  774                          * XXX This deserves further investigation; the workaround
  775                          * XXX here simply prevents the kernel from panic'ing
  776                          * XXX on startup.
  777                          */
  778                         if (msg->u.watch.handle->callback != NULL)
  779                                 msg->u.watch.handle->callback(
  780                                         msg->u.watch.handle,
  781                                         (const char **)msg->u.watch.vec,
  782                                         msg->u.watch.vec_size);
  783                         free(msg->u.watch.vec, M_DEVBUF);
  784                         free(msg, M_DEVBUF);
  785                 }
  786 
  787                 sx_xunlock(&xenwatch_mutex);
  788         }
  789 }
  790 
  791 static int
  792 xs_process_msg(enum xsd_sockmsg_type *type)
  793 {
  794         struct xs_stored_msg *msg;
  795         char *body;
  796         int error;
  797                 
  798         msg = malloc(sizeof(*msg), M_DEVBUF, M_WAITOK);
  799         mtx_lock(&xs_state.reply_lock);
  800         error = xb_read(&msg->hdr, sizeof(msg->hdr),
  801             &xs_state.reply_lock.lock_object);
  802         mtx_unlock(&xs_state.reply_lock);
  803         if (error) {
  804                 free(msg, M_DEVBUF);
  805                 return (error);
  806         }
  807 
  808         body = malloc(msg->hdr.len + 1, M_DEVBUF, M_WAITOK);
  809         mtx_lock(&xs_state.reply_lock);
  810         error = xb_read(body, msg->hdr.len,
  811             &xs_state.reply_lock.lock_object); 
  812         mtx_unlock(&xs_state.reply_lock);
  813         if (error) {
  814                 free(body, M_DEVBUF);
  815                 free(msg, M_DEVBUF);
  816                 return (error);
  817         }
  818         body[msg->hdr.len] = '\0';
  819 
  820         *type = msg->hdr.type;
  821         if (msg->hdr.type == XS_WATCH_EVENT) {
  822                 msg->u.watch.vec = split(body, msg->hdr.len,
  823                     &msg->u.watch.vec_size);
  824                                 
  825                 mtx_lock(&watches_lock);
  826                 msg->u.watch.handle = find_watch(
  827                         msg->u.watch.vec[XS_WATCH_TOKEN]);
  828                 if (msg->u.watch.handle != NULL) {
  829                         mtx_lock(&watch_events_lock);
  830                         TAILQ_INSERT_TAIL(&watch_events, msg, list);
  831                         wakeup(&watch_events_waitq);
  832                         mtx_unlock(&watch_events_lock);
  833                 } else {
  834                         free(msg->u.watch.vec, M_DEVBUF);
  835                         free(msg, M_DEVBUF);
  836                 }
  837                 mtx_unlock(&watches_lock);
  838         } else {
  839                 msg->u.reply.body = body;
  840                 mtx_lock(&xs_state.reply_lock);
  841                 TAILQ_INSERT_TAIL(&xs_state.reply_list, msg, list);
  842                 wakeup(&xs_state.reply_waitq);
  843                 mtx_unlock(&xs_state.reply_lock);
  844         }
  845                 
  846         return 0;
  847 }
  848 
  849 static void
  850 xenbus_thread(void *unused)
  851 {
  852         int error;
  853         enum xsd_sockmsg_type type;
  854         xenbus_running = 1;
  855 
  856         for (;;) {
  857                 error = xs_process_msg(&type);
  858                 if (error) 
  859                         printf("XENBUS error %d while reading message\n",
  860                             error);
  861         }
  862 }
  863 
  864 #ifdef XENHVM
  865 static unsigned long xen_store_mfn;
  866 char *xen_store;
  867 
  868 static inline unsigned long
  869 hvm_get_parameter(int index)
  870 {
  871         struct xen_hvm_param xhv;
  872         int error;
  873         
  874         xhv.domid = DOMID_SELF;
  875         xhv.index = index;
  876         error = HYPERVISOR_hvm_op(HVMOP_get_param, &xhv);
  877         if (error) {
  878                 printf("hvm_get_parameter: failed to get %d, error %d\n",
  879                     index, error);
  880                 return (0);
  881         }
  882         return (xhv.value);
  883 }
  884 
  885 #endif
  886 
  887 int
  888 xs_init(void)
  889 {
  890         int error;
  891         struct proc *p;
  892 
  893 #ifdef XENHVM
  894         xen_store_evtchn = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN);
  895         xen_store_mfn = hvm_get_parameter(HVM_PARAM_STORE_PFN);
  896         xen_store = pmap_mapdev(xen_store_mfn * PAGE_SIZE, PAGE_SIZE);
  897 #else
  898         xen_store_evtchn = xen_start_info->store_evtchn;
  899 #endif
  900 
  901         TAILQ_INIT(&xs_state.reply_list);
  902         TAILQ_INIT(&watch_events);
  903         sx_init(&xenwatch_mutex, "xenwatch");
  904 
  905                 
  906         mtx_init(&xs_state.reply_lock, "state reply", NULL, MTX_DEF);
  907         sx_init(&xs_state.request_mutex, "xenstore request");
  908         sx_init(&xs_state.suspend_mutex, "xenstore suspend");
  909 
  910                 
  911 #if 0
  912         mtx_init(&xs_state.suspend_mutex, "xenstore suspend", NULL, MTX_DEF);
  913         sema_init(&xs_state.request_mutex, 1, "xenstore request");
  914         sema_init(&xenwatch_mutex, 1, "xenwatch");
  915 #endif
  916         mtx_init(&watches_lock, "watches", NULL, MTX_DEF);
  917         mtx_init(&watch_events_lock, "watch events", NULL, MTX_DEF);
  918    
  919         /* Initialize the shared memory rings to talk to xenstored */
  920         error = xb_init_comms();
  921         if (error)
  922                 return (error);
  923 
  924         xenwatch_running = 1;
  925         error = kproc_create(xenwatch_thread, NULL, &p,
  926             RFHIGHPID, 0, "xenwatch");
  927         if (error)
  928                 return (error);
  929         xenwatch_pid = p->p_pid;
  930 
  931         error = kproc_create(xenbus_thread, NULL, NULL, 
  932             RFHIGHPID, 0, "xenbus");
  933         
  934         return (error);
  935 }

Cache object: f514e60f99e92bffe0b8ee5f444f44b5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.