LCOV - code coverage report
Current view: top level - dev/pv - xenstore.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 546 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 27 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: xenstore.c,v 1.44 2017/08/10 18:14:56 mikeb Exp $     */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2015 Mike Belopuhov
       5             :  *
       6             :  * Permission to use, copy, modify, and distribute this software for any
       7             :  * purpose with or without fee is hereby granted, provided that the above
       8             :  * copyright notice and this permission notice appear in all copies.
       9             :  *
      10             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      11             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      12             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      13             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      14             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      15             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      16             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      17             :  */
      18             : 
      19             : #include <sys/param.h>
      20             : #include <sys/systm.h>
      21             : #include <sys/atomic.h>
      22             : #include <sys/kernel.h>
      23             : #include <sys/malloc.h>
      24             : #include <sys/device.h>
      25             : #include <sys/mutex.h>
      26             : #include <sys/rwlock.h>
      27             : #include <sys/ioctl.h>
      28             : #include <sys/task.h>
      29             : 
      30             : #include <machine/bus.h>
      31             : 
      32             : #include <uvm/uvm_extern.h>
      33             : 
      34             : #include <dev/pv/pvvar.h>
      35             : #include <dev/pv/xenreg.h>
      36             : #include <dev/pv/xenvar.h>
      37             : 
      38             : /* #define XS_DEBUG */
      39             : 
      40             : #ifdef XS_DEBUG
      41             : #define DPRINTF(x...)           printf(x)
      42             : #else
      43             : #define DPRINTF(x...)
      44             : #endif
      45             : 
      46             : /*
      47             :  * The XenStore interface is a simple storage system that is a means of
      48             :  * communicating state and configuration data between the Xen Domain 0
      49             :  * and the various guest domains.  All configuration data other than
      50             :  * a small amount of essential information required during the early
      51             :  * boot process of launching a Xen aware guest, is managed using the
      52             :  * XenStore.
      53             :  *
      54             :  * The XenStore is ASCII string based, and has a structure and semantics
      55             :  * similar to a filesystem.  There are files and directories that are
      56             :  * able to contain files or other directories.  The depth of the hierachy
      57             :  * is only limited by the XenStore's maximum path length.
      58             :  *
      59             :  * The communication channel between the XenStore service and other
      60             :  * domains is via two, guest specific, ring buffers in a shared memory
      61             :  * area.  One ring buffer is used for communicating in each direction.
      62             :  * The grant table references for this shared memory are given to the
      63             :  * guest via HVM hypercalls.
      64             :  *
      65             :  * The XenStore communication relies on an event channel and thus
      66             :  * interrupts. Several Xen services depend on the XenStore, most
      67             :  * notably the XenBus used to discover and manage Xen devices.
      68             :  */
      69             : 
      70             : const struct {
      71             :         const char              *xse_errstr;
      72             :         int                      xse_errnum;
      73             : } xs_errors[] = {
      74             :         { "EINVAL",   EINVAL },
      75             :         { "EACCES",   EACCES },
      76             :         { "EEXIST",   EEXIST },
      77             :         { "EISDIR",   EISDIR },
      78             :         { "ENOENT",   ENOENT },
      79             :         { "ENOMEM",   ENOMEM },
      80             :         { "ENOSPC",   ENOSPC },
      81             :         { "EIO",      EIO },
      82             :         { "ENOTEMPTY",        ENOTEMPTY },
      83             :         { "ENOSYS",   ENOSYS },
      84             :         { "EROFS",    EROFS },
      85             :         { "EBUSY",    EBUSY },
      86             :         { "EAGAIN",   EAGAIN },
      87             :         { "EISCONN",  EISCONN },
      88             :         { NULL,         -1 },
      89             : };
      90             : 
      91             : struct xs_msghdr {
      92             :         /* Message type */
      93             :         uint32_t                 xmh_type;
      94             :         /* Request identifier, echoed in daemon's response.  */
      95             :         uint32_t                 xmh_rid;
      96             :         /* Transaction id (0 if not related to a transaction). */
      97             :         uint32_t                 xmh_tid;
      98             :         /* Length of data following this. */
      99             :         uint32_t                 xmh_len;
     100             :         /* Generally followed by nul-terminated string(s). */
     101             : } __packed;
     102             : 
     103             : /*
     104             :  * A minimum output buffer size needed to store an error string.
     105             :  */
     106             : #define XS_ERR_PAYLOAD          16
     107             : 
     108             : /*
     109             :  * Although the Xen source code implies that the limit is 4k,
     110             :  * in practice it turns out that we can only send 2k bytes of
     111             :  * payload before receiving a ENOSPC.  We set it to an even
     112             :  * smaller value however, because there's no real need to use
     113             :  * large buffers for anything.
     114             :  */
     115             : #define XS_MAX_PAYLOAD          1024
     116             : 
     117             : struct xs_msg {
     118             :         struct xs_msghdr         xsm_hdr;
     119             :         uint32_t                 xsm_read;
     120             :         uint32_t                 xsm_dlen;
     121             :         uint8_t                 *xsm_data;
     122             :         TAILQ_ENTRY(xs_msg)      xsm_link;
     123             : };
     124             : TAILQ_HEAD(xs_msgq, xs_msg);
     125             : 
     126             : #define XS_RING_SIZE            1024
     127             : 
     128             : struct xs_ring {
     129             :         uint8_t                 xsr_req[XS_RING_SIZE];
     130             :         uint8_t                 xsr_rsp[XS_RING_SIZE];
     131             :         uint32_t                xsr_req_cons;
     132             :         uint32_t                xsr_req_prod;
     133             :         uint32_t                xsr_rsp_cons;
     134             :         uint32_t                xsr_rsp_prod;
     135             : } __packed;
     136             : 
     137             : #define XST_DELAY               1       /* in seconds */
     138             : 
     139             : #define XSW_TOKLEN              (sizeof(void *) * 2 + 1)
     140             : 
     141             : struct xs_watch {
     142             :         TAILQ_ENTRY(xs_watch)    xsw_entry;
     143             :         uint8_t                  xsw_token[XSW_TOKLEN];
     144             :         struct task             *xsw_task;
     145             : };
     146             : 
     147             : /*
     148             :  * Container for all XenStore related state.
     149             :  */
     150             : struct xs_softc {
     151             :         struct xen_softc        *xs_sc;
     152             : 
     153             :         evtchn_port_t            xs_port;
     154             :         xen_intr_handle_t        xs_ih;
     155             : 
     156             :         struct xs_ring          *xs_ring;
     157             : 
     158             :         struct xs_msg            xs_msgs[10];
     159             :         struct xs_msg           *xs_rmsg;
     160             : 
     161             :         struct xs_msgq           xs_free;
     162             :         struct xs_msgq           xs_reqs;
     163             :         struct xs_msgq           xs_rsps;
     164             : 
     165             :         volatile uint            xs_rid;
     166             : 
     167             :         const char              *xs_wchan;
     168             :         const char              *xs_rchan;
     169             : 
     170             :         struct mutex             xs_reqlck;     /* request queue mutex */
     171             :         struct mutex             xs_rsplck;     /* response queue mutex */
     172             :         struct mutex             xs_frqlck;     /* free queue mutex */
     173             : 
     174             :         TAILQ_HEAD(, xs_watch)   xs_watches;
     175             :         struct mutex             xs_watchlck;
     176             :         struct xs_msg            xs_emsg;
     177             :         struct taskq            *xs_watchtq;
     178             : 
     179             :         struct rwlock            xs_rnglck;
     180             : };
     181             : 
     182             : struct xs_msg *
     183             :         xs_get_msg(struct xs_softc *, int);
     184             : void    xs_put_msg(struct xs_softc *, struct xs_msg *);
     185             : int     xs_ring_get(struct xs_softc *, void *, size_t);
     186             : int     xs_ring_put(struct xs_softc *, void *, size_t);
     187             : void    xs_intr(void *);
     188             : void    xs_poll(struct xs_softc *, int);
     189             : int     xs_output(struct xs_transaction *, uint8_t *, int);
     190             : int     xs_start(struct xs_transaction *, struct xs_msg *, struct iovec *, int);
     191             : struct xs_msg *
     192             :         xs_reply(struct xs_transaction *, uint);
     193             : int     xs_parse(struct xs_transaction *, struct xs_msg *, struct iovec **,
     194             :             int *);
     195             : int     xs_event(struct xs_softc *, struct xs_msg *);
     196             : 
     197             : int
     198           0 : xs_attach(struct xen_softc *sc)
     199             : {
     200           0 :         struct xen_hvm_param xhv;
     201             :         struct xs_softc *xs;
     202             :         paddr_t pa;
     203             :         int i;
     204             : 
     205           0 :         if ((xs = malloc(sizeof(*xs), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) {
     206           0 :                 printf(": failed to allocate xenstore softc\n");
     207           0 :                 return (-1);
     208             :         }
     209           0 :         sc->sc_xs = xs;
     210           0 :         xs->xs_sc = sc;
     211             : 
     212             :         /* Fetch event channel port */
     213           0 :         memset(&xhv, 0, sizeof(xhv));
     214           0 :         xhv.domid = DOMID_SELF;
     215           0 :         xhv.index = HVM_PARAM_STORE_EVTCHN;
     216           0 :         if (xen_hypercall(sc, XC_HVM, 2, HVMOP_get_param, &xhv)) {
     217           0 :                 printf(": failed to obtain a xenstore event channel\n");
     218           0 :                 goto fail_1;
     219             :         }
     220           0 :         xs->xs_port = xhv.value;
     221             : 
     222           0 :         printf(", event channel %u\n", xs->xs_port);
     223             : 
     224             :         /* Fetch a frame number (PA) of a shared xenstore page */
     225           0 :         memset(&xhv, 0, sizeof(xhv));
     226           0 :         xhv.domid = DOMID_SELF;
     227           0 :         xhv.index = HVM_PARAM_STORE_PFN;
     228           0 :         if (xen_hypercall(sc, XC_HVM, 2, HVMOP_get_param, &xhv))
     229             :                 goto fail_1;
     230           0 :         pa = ptoa(xhv.value);
     231             :         /* Allocate a page of virtual memory */
     232           0 :         xs->xs_ring = km_alloc(PAGE_SIZE, &kv_any, &kp_none, &kd_nowait);
     233           0 :         if (xs->xs_ring == NULL)
     234             :                 goto fail_1;
     235             :         /* Map in the xenstore page into our KVA */
     236           0 :         pa |= PMAP_NOCACHE;
     237           0 :         pmap_kenter_pa((vaddr_t)xs->xs_ring, pa, PROT_READ | PROT_WRITE);
     238             :         pmap_update(pmap_kernel());
     239             : 
     240           0 :         if (xen_intr_establish(xs->xs_port, &xs->xs_ih, 0, xs_intr, xs,
     241           0 :             sc->sc_dev.dv_xname))
     242             :                 goto fail_2;
     243             : 
     244           0 :         xs->xs_wchan = "xswrite";
     245           0 :         xs->xs_rchan = "xsread";
     246             : 
     247           0 :         TAILQ_INIT(&xs->xs_free);
     248           0 :         TAILQ_INIT(&xs->xs_reqs);
     249           0 :         TAILQ_INIT(&xs->xs_rsps);
     250           0 :         for (i = 0; i < nitems(xs->xs_msgs); i++)
     251           0 :                 TAILQ_INSERT_TAIL(&xs->xs_free, &xs->xs_msgs[i], xsm_link);
     252             : 
     253           0 :         mtx_init(&xs->xs_reqlck, IPL_NET);
     254           0 :         mtx_init(&xs->xs_rsplck, IPL_NET);
     255           0 :         mtx_init(&xs->xs_frqlck, IPL_NET);
     256             : 
     257           0 :         rw_init(&xs->xs_rnglck, "xsrnglck");
     258             : 
     259           0 :         xs->xs_watchtq = taskq_create("xenwatch", 1, IPL_NET, 0);
     260             : 
     261           0 :         mtx_init(&xs->xs_watchlck, IPL_NET);
     262           0 :         TAILQ_INIT(&xs->xs_watches);
     263             : 
     264           0 :         xs->xs_emsg.xsm_data = malloc(XS_MAX_PAYLOAD, M_DEVBUF,
     265             :             M_ZERO | M_NOWAIT);
     266           0 :         if (xs->xs_emsg.xsm_data == NULL)
     267             :                 goto fail_2;
     268           0 :         xs->xs_emsg.xsm_dlen = XS_MAX_PAYLOAD;
     269             : 
     270           0 :         return (0);
     271             : 
     272             :  fail_2:
     273           0 :         pmap_kremove((vaddr_t)xs->xs_ring, PAGE_SIZE);
     274             :         pmap_update(pmap_kernel());
     275           0 :         km_free(xs->xs_ring, PAGE_SIZE, &kv_any, &kp_none);
     276           0 :         xs->xs_ring = NULL;
     277             :  fail_1:
     278           0 :         free(xs, sizeof(*xs), M_DEVBUF);
     279           0 :         sc->sc_xs = NULL;
     280           0 :         return (-1);
     281           0 : }
     282             : 
     283             : struct xs_msg *
     284           0 : xs_get_msg(struct xs_softc *xs, int waitok)
     285             : {
     286             :         static const char *chan = "xsalloc";
     287             :         struct xs_msg *xsm;
     288             : 
     289           0 :         mtx_enter(&xs->xs_frqlck);
     290           0 :         for (;;) {
     291           0 :                 xsm = TAILQ_FIRST(&xs->xs_free);
     292           0 :                 if (xsm != NULL) {
     293           0 :                         TAILQ_REMOVE(&xs->xs_free, xsm, xsm_link);
     294             :                         break;
     295             :                 }
     296           0 :                 if (!waitok) {
     297           0 :                         mtx_leave(&xs->xs_frqlck);
     298           0 :                         delay(XST_DELAY * 1000 >> 2);
     299           0 :                         mtx_enter(&xs->xs_frqlck);
     300           0 :                 } else
     301           0 :                         msleep(chan, &xs->xs_frqlck, PRIBIO, chan,
     302           0 :                             XST_DELAY * hz >> 2);
     303             :         }
     304           0 :         mtx_leave(&xs->xs_frqlck);
     305           0 :         return (xsm);
     306             : }
     307             : 
     308             : void
     309           0 : xs_put_msg(struct xs_softc *xs, struct xs_msg *xsm)
     310             : {
     311           0 :         memset(xsm, 0, sizeof(*xsm));
     312           0 :         mtx_enter(&xs->xs_frqlck);
     313           0 :         TAILQ_INSERT_TAIL(&xs->xs_free, xsm, xsm_link);
     314           0 :         mtx_leave(&xs->xs_frqlck);
     315           0 : }
     316             : 
     317             : int
     318           0 : xs_geterror(struct xs_msg *xsm)
     319             : {
     320             :         int i;
     321             : 
     322           0 :         for (i = 0; i < nitems(xs_errors); i++)
     323           0 :                 if (strcmp(xs_errors[i].xse_errstr, xsm->xsm_data) == 0)
     324           0 :                         return (xs_errors[i].xse_errnum);
     325           0 :         return (EOPNOTSUPP);
     326           0 : }
     327             : 
     328             : static inline uint32_t
     329           0 : xs_ring_avail(struct xs_ring *xsr, int req)
     330             : {
     331           0 :         uint32_t cons = req ? xsr->xsr_req_cons : xsr->xsr_rsp_cons;
     332           0 :         uint32_t prod = req ? xsr->xsr_req_prod : xsr->xsr_rsp_prod;
     333             : 
     334           0 :         KASSERT(prod - cons <= XS_RING_SIZE);
     335           0 :         return (req ? XS_RING_SIZE - (prod - cons) : prod - cons);
     336             : }
     337             : 
     338             : void
     339           0 : xs_poll(struct xs_softc *xs, int nosleep)
     340             : {
     341             :         int s;
     342             : 
     343           0 :         if (nosleep) {
     344           0 :                 delay(XST_DELAY * 1000 >> 2);
     345           0 :                 s = splnet();
     346           0 :                 xs_intr(xs);
     347           0 :                 splx(s);
     348           0 :         } else
     349           0 :                 tsleep(xs->xs_wchan, PRIBIO, xs->xs_wchan, XST_DELAY * hz >> 2);
     350           0 : }
     351             : 
     352             : int
     353           0 : xs_output(struct xs_transaction *xst, uint8_t *bp, int len)
     354             : {
     355           0 :         struct xs_softc *xs = xst->xst_cookie;
     356             :         int chunk;
     357             : 
     358           0 :         while (len > 0) {
     359           0 :                 chunk = xs_ring_put(xs, bp, MIN(len, XS_RING_SIZE));
     360           0 :                 if (chunk < 0)
     361           0 :                         return (-1);
     362           0 :                 if (chunk > 0) {
     363           0 :                         len -= chunk;
     364           0 :                         bp += chunk;
     365           0 :                         if (xs_ring_avail(xs->xs_ring, 1) > 0)
     366           0 :                                 continue;
     367             :                 }
     368             :                 /* Squeaky wheel gets the kick */
     369           0 :                 xen_intr_signal(xs->xs_ih);
     370             :                 /*
     371             :                  * chunk == 0: we need to wait for hv to consume
     372             :                  * what has already been written;
     373             :                  *
     374             :                  * Alternatively we have managed to fill the ring
     375             :                  * and must wait for HV to collect the data.
     376             :                  */
     377           0 :                 while (xs->xs_ring->xsr_req_prod != xs->xs_ring->xsr_req_cons)
     378           0 :                         xs_poll(xs, 1);
     379             :         }
     380           0 :         return (0);
     381           0 : }
     382             : 
     383             : int
     384           0 : xs_start(struct xs_transaction *xst, struct xs_msg *xsm, struct iovec *iov,
     385             :     int iov_cnt)
     386             : {
     387           0 :         struct xs_softc *xs = xst->xst_cookie;
     388             :         int i;
     389             : 
     390           0 :         rw_enter_write(&xs->xs_rnglck);
     391             : 
     392             :         /* Header */
     393           0 :         if (xs_output(xst, (uint8_t *)&xsm->xsm_hdr,
     394           0 :             sizeof(xsm->xsm_hdr)) == -1) {
     395           0 :                 printf("%s: failed to write the header\n", __func__);
     396           0 :                 rw_exit_write(&xs->xs_rnglck);
     397           0 :                 return (-1);
     398             :         }
     399             : 
     400             :         /* Data loop */
     401           0 :         for (i = 0; i < iov_cnt; i++) {
     402           0 :                 if (xs_output(xst, iov[i].iov_base, iov[i].iov_len) == -1) {
     403           0 :                         printf("%s: failed on iovec #%d len %lu\n", __func__,
     404           0 :                             i, iov[i].iov_len);
     405           0 :                         rw_exit_write(&xs->xs_rnglck);
     406           0 :                         return (-1);
     407             :                 }
     408             :         }
     409             : 
     410           0 :         mtx_enter(&xs->xs_reqlck);
     411           0 :         TAILQ_INSERT_TAIL(&xs->xs_reqs, xsm, xsm_link);
     412           0 :         mtx_leave(&xs->xs_reqlck);
     413             : 
     414           0 :         xen_intr_signal(xs->xs_ih);
     415             : 
     416           0 :         rw_exit_write(&xs->xs_rnglck);
     417             : 
     418           0 :         return (0);
     419           0 : }
     420             : 
     421             : struct xs_msg *
     422           0 : xs_reply(struct xs_transaction *xst, uint rid)
     423             : {
     424           0 :         struct xs_softc *xs = xst->xst_cookie;
     425             :         struct xs_msg *xsm;
     426             :         int s;
     427             : 
     428           0 :         mtx_enter(&xs->xs_rsplck);
     429           0 :         for (;;) {
     430           0 :                 TAILQ_FOREACH(xsm, &xs->xs_rsps, xsm_link) {
     431           0 :                         if (xsm->xsm_hdr.xmh_tid == xst->xst_id &&
     432           0 :                             xsm->xsm_hdr.xmh_rid == rid)
     433             :                                 break;
     434             :                 }
     435           0 :                 if (xsm != NULL) {
     436           0 :                         TAILQ_REMOVE(&xs->xs_rsps, xsm, xsm_link);
     437             :                         break;
     438             :                 }
     439           0 :                 if (cold) {
     440           0 :                         mtx_leave(&xs->xs_rsplck);
     441           0 :                         delay(XST_DELAY * 1000 >> 2);
     442           0 :                         s = splnet();
     443           0 :                         xs_intr(xs);
     444           0 :                         splx(s);
     445           0 :                         mtx_enter(&xs->xs_rsplck);
     446           0 :                 } else
     447           0 :                         msleep(xs->xs_rchan, &xs->xs_rsplck, PRIBIO,
     448           0 :                             xs->xs_rchan, XST_DELAY * hz >> 2);
     449             :         }
     450           0 :         mtx_leave(&xs->xs_rsplck);
     451           0 :         return (xsm);
     452             : }
     453             : 
     454             : int
     455           0 : xs_ring_put(struct xs_softc *xs, void *src, size_t size)
     456             : {
     457           0 :         struct xs_ring *xsr = xs->xs_ring;
     458           0 :         uint32_t prod = xsr->xsr_req_prod & (XS_RING_SIZE - 1);
     459           0 :         uint32_t avail = xs_ring_avail(xsr, 1);
     460             :         size_t left;
     461             : 
     462           0 :         if (size > XS_RING_SIZE)
     463           0 :                 return (-1);
     464           0 :         if (avail == 0)
     465           0 :                 return (0);
     466             : 
     467             :         /* Bound the size by the number of available slots */
     468           0 :         size = MIN(size, avail);
     469             :         /* How many contiguous bytes can we memcpy... */
     470           0 :         left = XS_RING_SIZE - prod;
     471             :         /* ...bounded by by how much we need to write? */
     472           0 :         left = MIN(left, size);
     473             : 
     474           0 :         memcpy(&xsr->xsr_req[prod], src, left);
     475           0 :         memcpy(&xsr->xsr_req[0], (caddr_t)src + left, size - left);
     476           0 :         virtio_membar_sync();
     477           0 :         xsr->xsr_req_prod += size;
     478           0 :         return (size);
     479           0 : }
     480             : 
     481             : int
     482           0 : xs_ring_get(struct xs_softc *xs, void *dst, size_t size)
     483             : {
     484           0 :         struct xs_ring *xsr = xs->xs_ring;
     485           0 :         uint32_t cons = xsr->xsr_rsp_cons & (XS_RING_SIZE - 1);
     486           0 :         uint32_t avail = xs_ring_avail(xsr, 0);
     487             :         size_t left;
     488             : 
     489           0 :         if (size > XS_RING_SIZE)
     490           0 :                 return (-1);
     491           0 :         if (avail == 0)
     492           0 :                 return (0);
     493             : 
     494             :         /* Bound the size by the number of available slots */
     495           0 :         size = MIN(size, avail);
     496             :         /* How many contiguous bytes can we memcpy... */
     497           0 :         left = XS_RING_SIZE - cons;
     498             :         /* ...bounded by by how much we need to read? */
     499           0 :         left = MIN(left, size);
     500             : 
     501           0 :         memcpy(dst, &xsr->xsr_rsp[cons], left);
     502           0 :         memcpy((caddr_t)dst + left, &xsr->xsr_rsp[0], size - left);
     503           0 :         virtio_membar_sync();
     504           0 :         xsr->xsr_rsp_cons += size;
     505           0 :         return (size);
     506           0 : }
     507             : 
     508             : void
     509           0 : xs_intr(void *arg)
     510             : {
     511           0 :         struct xs_softc *xs = arg;
     512           0 :         struct xs_ring *xsr = xs->xs_ring;
     513           0 :         struct xen_softc *sc = xs->xs_sc;
     514           0 :         struct xs_msg *xsm = xs->xs_rmsg;
     515           0 :         struct xs_msghdr xmh;
     516             :         uint32_t avail;
     517             :         int len;
     518             : 
     519           0 :         virtio_membar_sync();
     520             : 
     521           0 :         if (xsr->xsr_rsp_cons == xsr->xsr_rsp_prod)
     522           0 :                 return;
     523             : 
     524           0 :         avail = xs_ring_avail(xsr, 0);
     525             : 
     526             :         /* Response processing */
     527             : 
     528             :  again:
     529           0 :         if (xs->xs_rmsg == NULL) {
     530           0 :                 if (avail < sizeof(xmh)) {
     531             :                         DPRINTF("%s: incomplete header: %u\n",
     532             :                             sc->sc_dev.dv_xname, avail);
     533             :                         goto out;
     534             :                 }
     535           0 :                 avail -= sizeof(xmh);
     536             : 
     537           0 :                 if ((len = xs_ring_get(xs, &xmh, sizeof(xmh))) != sizeof(xmh)) {
     538           0 :                         printf("%s: message too short: %d\n",
     539           0 :                             sc->sc_dev.dv_xname, len);
     540           0 :                         goto out;
     541             :                 }
     542             : 
     543           0 :                 if (xmh.xmh_type == XS_EVENT) {
     544           0 :                         xsm = &xs->xs_emsg;
     545           0 :                         xsm->xsm_read = 0;
     546           0 :                 } else {
     547           0 :                         mtx_enter(&xs->xs_reqlck);
     548           0 :                         TAILQ_FOREACH(xsm, &xs->xs_reqs, xsm_link) {
     549           0 :                                 if (xsm->xsm_hdr.xmh_rid == xmh.xmh_rid) {
     550           0 :                                         TAILQ_REMOVE(&xs->xs_reqs, xsm,
     551             :                                             xsm_link);
     552           0 :                                         break;
     553             :                                 }
     554             :                         }
     555           0 :                         mtx_leave(&xs->xs_reqlck);
     556           0 :                         if (xsm == NULL) {
     557           0 :                                 printf("%s: unexpected message id %u\n",
     558           0 :                                     sc->sc_dev.dv_xname, xmh.xmh_rid);
     559           0 :                                 goto out;
     560             :                         }
     561             :                 }
     562           0 :                 memcpy(&xsm->xsm_hdr, &xmh, sizeof(xmh));
     563           0 :                 xs->xs_rmsg = xsm;
     564           0 :         }
     565             : 
     566           0 :         if (xsm->xsm_hdr.xmh_len > xsm->xsm_dlen)
     567           0 :                 panic("message too large: %d vs %d for type %d, rid %u",
     568           0 :                     xsm->xsm_hdr.xmh_len, xsm->xsm_dlen, xsm->xsm_hdr.xmh_type,
     569           0 :                     xsm->xsm_hdr.xmh_rid);
     570             : 
     571           0 :         len = MIN(xsm->xsm_hdr.xmh_len - xsm->xsm_read, avail);
     572           0 :         if (len) {
     573             :                 /* Get data if reply is not empty */
     574           0 :                 if ((len = xs_ring_get(xs,
     575           0 :                     &xsm->xsm_data[xsm->xsm_read], len)) <= 0) {
     576           0 :                         printf("%s: read failure %d\n", sc->sc_dev.dv_xname,
     577             :                             len);
     578           0 :                         goto out;
     579             :                 }
     580           0 :                 xsm->xsm_read += len;
     581           0 :         }
     582             : 
     583             :         /* Notify reader that we've managed to read the whole message */
     584           0 :         if (xsm->xsm_read == xsm->xsm_hdr.xmh_len) {
     585           0 :                 xs->xs_rmsg = NULL;
     586           0 :                 if (xsm->xsm_hdr.xmh_type == XS_EVENT) {
     587           0 :                         xs_event(xs, xsm);
     588           0 :                 } else {
     589           0 :                         mtx_enter(&xs->xs_rsplck);
     590           0 :                         TAILQ_INSERT_TAIL(&xs->xs_rsps, xsm, xsm_link);
     591           0 :                         mtx_leave(&xs->xs_rsplck);
     592           0 :                         wakeup(xs->xs_rchan);
     593             :                 }
     594             :         }
     595             : 
     596           0 :         if ((avail = xs_ring_avail(xsr, 0)) > 0)
     597           0 :                 goto again;
     598             : 
     599             :  out:
     600             :         /* Wakeup sleeping writes (if any) */
     601           0 :         wakeup(xs->xs_wchan);
     602           0 :         xen_intr_signal(xs->xs_ih);
     603           0 : }
     604             : 
     605             : static inline int
     606           0 : xs_get_buf(struct xs_transaction *xst, struct xs_msg *xsm, int len)
     607             : {
     608             :         unsigned char *buf;
     609             : 
     610           0 :         buf = malloc(len, M_DEVBUF, M_ZERO | (cold ? M_NOWAIT : M_WAITOK));
     611           0 :         if (buf == NULL)
     612           0 :                 return (-1);
     613           0 :         xsm->xsm_dlen = len;
     614           0 :         xsm->xsm_data = buf;
     615           0 :         return (0);
     616           0 : }
     617             : 
     618             : static inline void
     619           0 : xs_put_buf(struct xs_transaction *xst, struct xs_msg *xsm)
     620             : {
     621           0 :         free(xsm->xsm_data, M_DEVBUF, xsm->xsm_dlen);
     622           0 :         xsm->xsm_data = NULL;
     623           0 : }
     624             : 
     625             : void
     626           0 : xs_resfree(struct xs_transaction *xst, struct iovec *iov, int iov_cnt)
     627             : {
     628             :         int i;
     629             : 
     630           0 :         for (i = 0; i < iov_cnt; i++)
     631           0 :                 free(iov[i].iov_base, M_DEVBUF, iov[i].iov_len);
     632           0 :         free(iov, M_DEVBUF, sizeof(struct iovec) * iov_cnt);
     633           0 : }
     634             : 
     635             : int
     636           0 : xs_parse(struct xs_transaction *xst, struct xs_msg *xsm, struct iovec **iov,
     637             :     int *iov_cnt)
     638             : {
     639             :         char *bp, *cp;
     640             :         uint32_t dlen;
     641             :         int i, flags;
     642             : 
     643             :         /* If the response size is zero, we return an empty string */
     644           0 :         dlen = MAX(xsm->xsm_hdr.xmh_len, 1);
     645           0 :         flags = M_ZERO | (cold ? M_NOWAIT : M_WAITOK);
     646             : 
     647           0 :         *iov_cnt = 0;
     648             :         /* Make sure that the data is NUL terminated */
     649           0 :         if (xsm->xsm_data[dlen - 1] != '\0') {
     650             :                 /*
     651             :                  * The XS_READ operation always returns length without
     652             :                  * the trailing NUL so we have to adjust the length.
     653             :                  */
     654           0 :                 dlen = MIN(dlen + 1, xsm->xsm_dlen);
     655           0 :                 xsm->xsm_data[dlen - 1] = '\0';
     656           0 :         }
     657           0 :         for (i = 0; i < dlen; i++)
     658           0 :                 if (xsm->xsm_data[i] == '\0')
     659           0 :                         (*iov_cnt)++;
     660           0 :         *iov = mallocarray(*iov_cnt, sizeof(struct iovec), M_DEVBUF, flags);
     661           0 :         if (*iov == NULL)
     662             :                 goto cleanup;
     663           0 :         bp = xsm->xsm_data;
     664           0 :         for (i = 0; i < *iov_cnt; i++) {
     665             :                 cp = bp;
     666           0 :                 while (cp - (caddr_t)xsm->xsm_data < dlen && *cp != '\0')
     667           0 :                         cp++;
     668           0 :                 (*iov)[i].iov_len = cp - bp + 1;
     669           0 :                 (*iov)[i].iov_base = malloc((*iov)[i].iov_len, M_DEVBUF, flags);
     670           0 :                 if (!(*iov)[i].iov_base) {
     671           0 :                         xs_resfree(xst, *iov, *iov_cnt);
     672           0 :                         goto cleanup;
     673             :                 }
     674           0 :                 memcpy((*iov)[i].iov_base, bp, (*iov)[i].iov_len);
     675           0 :                 bp = ++cp;
     676             :         }
     677           0 :         return (0);
     678             : 
     679             :  cleanup:
     680           0 :         *iov = NULL;
     681           0 :         *iov_cnt = 0;
     682           0 :         return (ENOMEM);
     683           0 : }
     684             : 
     685             : int
     686           0 : xs_event(struct xs_softc *xs, struct xs_msg *xsm)
     687             : {
     688             :         struct xs_watch *xsw;
     689             :         char *token = NULL;
     690             :         int i;
     691             : 
     692           0 :         for (i = 0; i < xsm->xsm_read; i++) {
     693           0 :                 if (xsm->xsm_data[i] == '\0') {
     694           0 :                         token = &xsm->xsm_data[i+1];
     695           0 :                         break;
     696             :                 }
     697             :         }
     698           0 :         if (token == NULL) {
     699           0 :                 printf("%s: event on \"%s\" without token\n",
     700           0 :                     xs->xs_sc->sc_dev.dv_xname, xsm->xsm_data);
     701           0 :                 return (-1);
     702             :         }
     703             : 
     704           0 :         mtx_enter(&xs->xs_watchlck);
     705           0 :         TAILQ_FOREACH(xsw, &xs->xs_watches, xsw_entry) {
     706           0 :                 if (strcmp(xsw->xsw_token, token))
     707             :                         continue;
     708           0 :                 mtx_leave(&xs->xs_watchlck);
     709           0 :                 task_add(xs->xs_watchtq, xsw->xsw_task);
     710           0 :                 return (0);
     711             :         }
     712           0 :         mtx_leave(&xs->xs_watchlck);
     713             : 
     714           0 :         printf("%s: no watchers for node \"%s\"\n",
     715           0 :             xs->xs_sc->sc_dev.dv_xname, xsm->xsm_data);
     716           0 :         return (-1);
     717           0 : }
     718             : 
     719             : int
     720           0 : xs_cmd(struct xs_transaction *xst, int cmd, const char *path,
     721             :     struct iovec **iov, int *iov_cnt)
     722             : {
     723           0 :         struct xs_softc *xs = xst->xst_cookie;
     724             :         struct xs_msg *xsm;
     725           0 :         struct iovec ov[10];    /* output vector */
     726             :         int datalen = XS_ERR_PAYLOAD;
     727             :         int ov_cnt = 0;
     728             :         enum { READ, WRITE } mode = READ;
     729             :         int i, error = 0;
     730             : 
     731           0 :         if (cmd >= XS_MAX)
     732           0 :                 return (EINVAL);
     733             : 
     734           0 :         switch (cmd) {
     735             :         case XS_TOPEN:
     736           0 :                 ov[0].iov_base = "";
     737           0 :                 ov[0].iov_len = 1;
     738             :                 ov_cnt++;
     739           0 :                 break;
     740             :         case XS_TCLOSE:
     741             :         case XS_RM:
     742             :         case XS_WATCH:
     743             :         case XS_WRITE:
     744           0 :                 mode = WRITE;
     745             :                 /* FALLTHROUGH */
     746             :         default:
     747           0 :                 if (mode == READ)
     748           0 :                         datalen = XS_MAX_PAYLOAD;
     749             :                 break;
     750             :         }
     751             : 
     752           0 :         if (path) {
     753           0 :                 ov[ov_cnt].iov_base = (void *)path;
     754           0 :                 ov[ov_cnt++].iov_len = strlen(path) + 1; /* +NUL */
     755           0 :         }
     756             : 
     757           0 :         if (mode == WRITE && iov && iov_cnt && *iov_cnt > 0) {
     758           0 :                 for (i = 0; i < *iov_cnt && ov_cnt < nitems(ov);
     759           0 :                      i++, ov_cnt++) {
     760           0 :                         ov[ov_cnt].iov_base = (*iov)[i].iov_base;
     761           0 :                         ov[ov_cnt].iov_len = (*iov)[i].iov_len;
     762             :                 }
     763             :         }
     764             : 
     765           0 :         xsm = xs_get_msg(xs, !cold);
     766             : 
     767           0 :         if (xs_get_buf(xst, xsm, datalen)) {
     768           0 :                 xs_put_msg(xs, xsm);
     769           0 :                 return (ENOMEM);
     770             :         }
     771             : 
     772           0 :         xsm->xsm_hdr.xmh_tid = xst->xst_id;
     773           0 :         xsm->xsm_hdr.xmh_type = cmd;
     774           0 :         xsm->xsm_hdr.xmh_rid = atomic_inc_int_nv(&xs->xs_rid);
     775             : 
     776           0 :         for (i = 0; i < ov_cnt; i++)
     777           0 :                 xsm->xsm_hdr.xmh_len += ov[i].iov_len;
     778             : 
     779           0 :         if (xsm->xsm_hdr.xmh_len > XS_MAX_PAYLOAD) {
     780           0 :                 printf("%s: message type %d with payload above the limit\n",
     781           0 :                     xs->xs_sc->sc_dev.dv_xname, cmd);
     782           0 :                 xs_put_buf(xst, xsm);
     783           0 :                 xs_put_msg(xs, xsm);
     784           0 :                 return (EIO);
     785             :         }
     786             : 
     787           0 :         if (xs_start(xst, xsm, ov, ov_cnt)) {
     788           0 :                 printf("%s: message type %d transmission failed\n",
     789           0 :                     xs->xs_sc->sc_dev.dv_xname, cmd);
     790           0 :                 xs_put_buf(xst, xsm);
     791           0 :                 xs_put_msg(xs, xsm);
     792           0 :                 return (EIO);
     793             :         }
     794             : 
     795           0 :         xsm = xs_reply(xst, xsm->xsm_hdr.xmh_rid);
     796             : 
     797           0 :         if (xsm->xsm_hdr.xmh_type == XS_ERROR) {
     798           0 :                 error = xs_geterror(xsm);
     799             :                 DPRINTF("%s: xenstore request %d \"%s\" error %s\n",
     800             :                     xs->xs_sc->sc_dev.dv_xname, cmd, path, xsm->xsm_data);
     801           0 :         } else if (mode == READ) {
     802           0 :                 KASSERT(iov && iov_cnt);
     803           0 :                 error = xs_parse(xst, xsm, iov, iov_cnt);
     804           0 :         }
     805             : #ifdef XS_DEBUG
     806             :         else
     807             :                 if (strcmp(xsm->xsm_data, "OK"))
     808             :                         printf("%s: xenstore request %d failed: %s\n",
     809             :                             xs->xs_sc->sc_dev.dv_xname, cmd, xsm->xsm_data);
     810             : #endif
     811             : 
     812           0 :         xs_put_buf(xst, xsm);
     813           0 :         xs_put_msg(xs, xsm);
     814             : 
     815           0 :         return (error);
     816           0 : }
     817             : 
     818             : int
     819           0 : xs_watch(void *xsc, const char *path, const char *property, struct task *task,
     820             :     void (*cb)(void *), void *arg)
     821             : {
     822           0 :         struct xen_softc *sc = xsc;
     823           0 :         struct xs_softc *xs = sc->sc_xs;
     824           0 :         struct xs_transaction xst;
     825             :         struct xs_watch *xsw;
     826           0 :         struct iovec iov, *iovp = &iov;
     827           0 :         char key[256];
     828           0 :         int error, iov_cnt, ret;
     829             : 
     830           0 :         memset(&xst, 0, sizeof(xst));
     831           0 :         xst.xst_id = 0;
     832           0 :         xst.xst_cookie = sc->sc_xs;
     833             : 
     834           0 :         xsw = malloc(sizeof(*xsw), M_DEVBUF, M_NOWAIT | M_ZERO);
     835           0 :         if (xsw == NULL)
     836           0 :                 return (-1);
     837             : 
     838           0 :         task_set(task, cb, arg);
     839           0 :         xsw->xsw_task = task;
     840             : 
     841           0 :         snprintf(xsw->xsw_token, sizeof(xsw->xsw_token), "%0lx",
     842           0 :             (unsigned long)xsw);
     843             : 
     844           0 :         if (path)
     845           0 :                 ret = snprintf(key, sizeof(key), "%s/%s", path, property);
     846             :         else
     847           0 :                 ret = snprintf(key, sizeof(key), "%s", property);
     848           0 :         if (ret == -1 || ret >= sizeof(key)) {
     849           0 :                 free(xsw, M_DEVBUF, sizeof(*xsw));
     850           0 :                 return (EINVAL);
     851             :         }
     852             : 
     853           0 :         iov.iov_base = xsw->xsw_token;
     854           0 :         iov.iov_len = sizeof(xsw->xsw_token);
     855           0 :         iov_cnt = 1;
     856             : 
     857             :         /*
     858             :          * xs_watches must be prepared pre-emptively because a xenstore
     859             :          * event is raised immediately after a watch is established.
     860             :          */
     861           0 :         mtx_enter(&xs->xs_watchlck);
     862           0 :         TAILQ_INSERT_TAIL(&xs->xs_watches, xsw, xsw_entry);
     863           0 :         mtx_leave(&xs->xs_watchlck);
     864             : 
     865           0 :         if ((error = xs_cmd(&xst, XS_WATCH, key, &iovp, &iov_cnt)) != 0) {
     866           0 :                 mtx_enter(&xs->xs_watchlck);
     867           0 :                 TAILQ_REMOVE(&xs->xs_watches, xsw, xsw_entry);
     868           0 :                 mtx_leave(&xs->xs_watchlck);
     869           0 :                 free(xsw, M_DEVBUF, sizeof(*xsw));
     870           0 :                 return (error);
     871             :         }
     872             : 
     873           0 :         return (0);
     874           0 : }
     875             : 
     876             : static unsigned long long
     877           0 : atoull(const char *cp, int *error)
     878             : {
     879             :         unsigned long long res, cutoff;
     880             :         int ch;
     881             :         int cutlim;
     882             : 
     883             :         res = 0;
     884             :         cutoff = ULLONG_MAX / (unsigned long long)10;
     885             :         cutlim = ULLONG_MAX % (unsigned long long)10;
     886             : 
     887           0 :         do {
     888           0 :                 if (*cp < '0' || *cp > '9') {
     889           0 :                         *error = EINVAL;
     890           0 :                         return (res);
     891             :                 }
     892           0 :                 ch = *cp - '0';
     893           0 :                 if (res > cutoff || (res == cutoff && ch > cutlim)) {
     894           0 :                         *error = ERANGE;
     895           0 :                         return (res);
     896             :                 }
     897           0 :                 res *= 10;
     898           0 :                 res += ch;
     899           0 :         } while (*(++cp) != '\0');
     900             : 
     901           0 :         *error = 0;
     902           0 :         return (res);
     903           0 : }
     904             : 
     905             : int
     906           0 : xs_getnum(void *xsc, const char *path, const char *property,
     907             :     unsigned long long *val)
     908             : {
     909             :         char *buf;
     910           0 :         int error = 0;
     911             : 
     912           0 :         buf = malloc(XS_MAX_PAYLOAD, M_DEVBUF, M_ZERO |
     913           0 :             (cold ? M_NOWAIT : M_WAITOK));
     914           0 :         if (buf == NULL)
     915           0 :                 return (ENOMEM);
     916             : 
     917           0 :         error = xs_getprop(xsc, path, property, buf, XS_MAX_PAYLOAD);
     918           0 :         if (error)
     919             :                 goto out;
     920             : 
     921           0 :         *val = atoull(buf, &error);
     922             :         if (error)
     923           0 :                 goto out;
     924             : 
     925             :  out:
     926           0 :         free(buf, M_DEVBUF, XS_MAX_PAYLOAD);
     927           0 :         return (error);
     928           0 : }
     929             : 
     930             : int
     931           0 : xs_setnum(void *xsc, const char *path, const char *property,
     932             :     unsigned long long val)
     933             : {
     934           0 :         char buf[32];
     935             :         int ret;
     936             : 
     937           0 :         ret = snprintf(buf, sizeof(buf), "%llu", val);
     938           0 :         if (ret == -1 || ret >= sizeof(buf))
     939           0 :                 return (ERANGE);
     940             : 
     941           0 :         return (xs_setprop(xsc, path, property, buf, strlen(buf)));
     942           0 : }
     943             : 
     944             : int
     945           0 : xs_getprop(void *xsc, const char *path, const char *property, char *value,
     946             :     int size)
     947             : {
     948           0 :         struct xen_softc *sc = xsc;
     949           0 :         struct xs_transaction xst;
     950           0 :         struct iovec *iovp = NULL;
     951           0 :         char key[256];
     952           0 :         int error, ret, iov_cnt = 0;
     953             : 
     954           0 :         if (!property)
     955           0 :                 return (EINVAL);
     956             : 
     957           0 :         memset(&xst, 0, sizeof(xst));
     958           0 :         xst.xst_id = 0;
     959           0 :         xst.xst_cookie = sc->sc_xs;
     960             : 
     961           0 :         if (path)
     962           0 :                 ret = snprintf(key, sizeof(key), "%s/%s", path, property);
     963             :         else
     964           0 :                 ret = snprintf(key, sizeof(key), "%s", property);
     965           0 :         if (ret == -1 || ret >= sizeof(key))
     966           0 :                 return (EINVAL);
     967             : 
     968           0 :         if ((error = xs_cmd(&xst, XS_READ, key, &iovp, &iov_cnt)) != 0)
     969           0 :                 return (error);
     970             : 
     971           0 :         if (iov_cnt > 0)
     972           0 :                 strlcpy(value, (char *)iovp->iov_base, size);
     973             : 
     974           0 :         xs_resfree(&xst, iovp, iov_cnt);
     975             : 
     976           0 :         return (0);
     977           0 : }
     978             : 
     979             : int
     980           0 : xs_setprop(void *xsc, const char *path, const char *property, char *value,
     981             :     int size)
     982             : {
     983           0 :         struct xen_softc *sc = xsc;
     984           0 :         struct xs_transaction xst;
     985           0 :         struct iovec iov, *iovp = &iov;
     986           0 :         char key[256];
     987           0 :         int error, ret, iov_cnt = 0;
     988             : 
     989           0 :         if (!property)
     990           0 :                 return (EINVAL);
     991             : 
     992           0 :         memset(&xst, 0, sizeof(xst));
     993           0 :         xst.xst_id = 0;
     994           0 :         xst.xst_cookie = sc->sc_xs;
     995             : 
     996           0 :         if (path)
     997           0 :                 ret = snprintf(key, sizeof(key), "%s/%s", path, property);
     998             :         else
     999           0 :                 ret = snprintf(key, sizeof(key), "%s", property);
    1000           0 :         if (ret == -1 || ret >= sizeof(key))
    1001           0 :                 return (EINVAL);
    1002             : 
    1003           0 :         iov.iov_base = value;
    1004           0 :         iov.iov_len = size;
    1005           0 :         iov_cnt = 1;
    1006             : 
    1007           0 :         error = xs_cmd(&xst, XS_WRITE, key, &iovp, &iov_cnt);
    1008             : 
    1009           0 :         return (error);
    1010           0 : }
    1011             : 
    1012             : int
    1013           0 : xs_cmpprop(void *xsc, const char *path, const char *property, const char *value,
    1014             :     int *result)
    1015             : {
    1016           0 :         struct xen_softc *sc = xsc;
    1017           0 :         struct xs_transaction xst;
    1018           0 :         struct iovec *iovp = NULL;
    1019           0 :         char key[256];
    1020           0 :         int error, ret, iov_cnt = 0;
    1021             : 
    1022           0 :         if (!property)
    1023           0 :                 return (EINVAL);
    1024             : 
    1025           0 :         memset(&xst, 0, sizeof(xst));
    1026           0 :         xst.xst_id = 0;
    1027           0 :         xst.xst_cookie = sc->sc_xs;
    1028             : 
    1029           0 :         if (path)
    1030           0 :                 ret = snprintf(key, sizeof(key), "%s/%s", path, property);
    1031             :         else
    1032           0 :                 ret = snprintf(key, sizeof(key), "%s", property);
    1033           0 :         if (ret == -1 || ret >= sizeof(key))
    1034           0 :                 return (EINVAL);
    1035             : 
    1036           0 :         if ((error = xs_cmd(&xst, XS_READ, key, &iovp, &iov_cnt)) != 0)
    1037           0 :                 return (error);
    1038             : 
    1039           0 :         *result = strcmp(value, (char *)iovp->iov_base);
    1040             : 
    1041           0 :         xs_resfree(&xst, iovp, iov_cnt);
    1042             : 
    1043           0 :         return (0);
    1044           0 : }
    1045             : 
    1046             : int
    1047           0 : xs_await_transition(void *xsc, const char *path, const char *property,
    1048             :     const char *value, int timo)
    1049             : {
    1050           0 :         struct xen_softc *sc = xsc;
    1051           0 :         int error, res;
    1052             : 
    1053           0 :         do {
    1054           0 :                 error = xs_cmpprop(xsc, path, property, value, &res);
    1055           0 :                 if (error)
    1056           0 :                         return (error);
    1057           0 :                 if (timo && --timo == 0)
    1058           0 :                         return (ETIMEDOUT);
    1059           0 :                 xs_poll(sc->sc_xs, cold);
    1060           0 :         } while (res != 0);
    1061             : 
    1062           0 :         return (0);
    1063           0 : }
    1064             : 
    1065             : int
    1066           0 : xs_kvop(void *xsc, int op, char *key, char *value, size_t valuelen)
    1067             : {
    1068           0 :         struct xen_softc *sc = xsc;
    1069           0 :         struct xs_transaction xst;
    1070           0 :         struct iovec iov, *iovp = &iov;
    1071           0 :         int error = 0, iov_cnt = 0, cmd, i;
    1072             : 
    1073           0 :         switch (op) {
    1074             :         case PVBUS_KVWRITE:
    1075             :                 cmd = XS_WRITE;
    1076           0 :                 iov.iov_base = value;
    1077           0 :                 iov.iov_len = strlen(value);
    1078           0 :                 iov_cnt = 1;
    1079           0 :                 break;
    1080             :         case PVBUS_KVREAD:
    1081             :                 cmd = XS_READ;
    1082           0 :                 break;
    1083             :         case PVBUS_KVLS:
    1084             :                 cmd = XS_LIST;
    1085           0 :                 break;
    1086             :         default:
    1087           0 :                 return (EOPNOTSUPP);
    1088             :         }
    1089             : 
    1090           0 :         memset(&xst, 0, sizeof(xst));
    1091           0 :         xst.xst_id = 0;
    1092           0 :         xst.xst_cookie = sc->sc_xs;
    1093             : 
    1094           0 :         if ((error = xs_cmd(&xst, cmd, key, &iovp, &iov_cnt)) != 0)
    1095           0 :                 return (error);
    1096             : 
    1097           0 :         memset(value, 0, valuelen);
    1098             : 
    1099           0 :         switch (cmd) {
    1100             :         case XS_READ:
    1101           0 :                 if (iov_cnt == 1 && iovp[0].iov_len == 1) {
    1102           0 :                         xs_resfree(&xst, iovp, iov_cnt);
    1103             : 
    1104             :                         /*
    1105             :                          * We cannot distinguish if the returned value is
    1106             :                          * a directory or a file in the xenstore.  The only
    1107             :                          * indication is that the read value of a directory
    1108             :                          * returns an empty string (single nul byte),
    1109             :                          * so try to get the directory list in this case.
    1110             :                          */
    1111           0 :                         return (xs_kvop(xsc, PVBUS_KVLS, key, value, valuelen));
    1112             :                 }
    1113             :                 /* FALLTHROUGH */
    1114             :         case XS_LIST:
    1115           0 :                 for (i = 0; i < iov_cnt; i++) {
    1116           0 :                         if (i && strlcat(value, "\n", valuelen) >= valuelen)
    1117             :                                 break;
    1118           0 :                         if (strlcat(value, iovp[i].iov_base,
    1119           0 :                             valuelen) >= valuelen)
    1120             :                                 break;
    1121             :                 }
    1122           0 :                 xs_resfree(&xst, iovp, iov_cnt);
    1123           0 :                 break;
    1124             :         default:
    1125             :                 break;
    1126             :         }
    1127             : 
    1128           0 :         return (0);
    1129           0 : }

Generated by: LCOV version 1.13