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 : }
|