2 * Driver for xenstore - database shared between domains, used by xenbus to
3 * communicate configuration info.
7 #include "../port/lib.h"
11 #include "../port/error.h"
16 typedef struct Aux Aux;
29 ".", {Qtopdir, 0, QTDIR}, 0, 0555,
30 "xenstore", {Qctl, 0}, 0, 0660,
31 "xenwatch", {Qwatch, 0}, 0, 0440,
35 struct xenstore_domain_interface *intf;
36 struct xsd_sockmsg hdr;
58 static char Ephase[] = "phase error";
59 static char Eproto[] = "protocol error";
60 static char NodeShutdown[] = "control/shutdown";
62 static void xenbusproc(void*);
67 struct xenstore_domain_interface *xs = xenstore.intf;
69 return (xs->req_prod-xs->req_cons) < XENSTORE_RING_SIZE;
75 struct xenstore_domain_interface *xs = xenstore.intf;
77 return xs->rsp_prod > xs->rsp_cons;
83 return xenstore.rhead == a;
89 LOG(dprint("xsintr\n");)
95 xwrite(Queue *q, char *buf, int len)
97 struct xenstore_domain_interface *xs;
99 XENSTORE_RING_IDX idx;
103 n = XENSTORE_RING_SIZE - (xs->req_prod - xs->req_cons);
105 xenchannotify(xenstore.evtchn);
106 sleep(&xenstore.wr, notfull, 0);
111 idx = MASK_XENSTORE_IDX(xs->req_prod);
112 m = XENSTORE_RING_SIZE - idx;
116 qread(q, xs->req+idx, m);
118 memmove(xs->req+idx, buf, m);
121 qread(q, xs->req, n-m);
123 memmove(xs->req, buf+m, n-m);
127 xenchannotify(xenstore.evtchn);
135 xread(Queue *q, char *buf, int len)
137 struct xenstore_domain_interface *xs = xenstore.intf;
139 XENSTORE_RING_IDX idx;
141 for (n = len; n > 0; n -= m) {
142 while (xs->rsp_prod == xs->rsp_cons) {
143 xenchannotify(xenstore.evtchn);
147 sleep(&xenstore.rr, notempty, 0);
149 idx = MASK_XENSTORE_IDX(xs->rsp_cons);
150 m = xs->rsp_prod - xs->rsp_cons;
153 if (m > XENSTORE_RING_SIZE - idx)
154 m = XENSTORE_RING_SIZE - idx;
156 qwrite(q, xs->rsp+idx, m);
158 memmove(buf, xs->rsp+idx, m);
164 xenchannotify(xenstore.evtchn);
172 struct xsd_sockmsg hdr;
177 if (aux->state == WATCHING)
180 /* get the request header and check validity */
181 if (qlen(q) < sizeof hdr)
183 qread(q, &hdr, sizeof hdr);
188 /* generate a unique request id */
189 aux->reqid = ++xenstore.nextreqid;
190 hdr.req_id = aux->reqid;
192 /* send the request */
193 xwrite(0, (char*)&hdr, sizeof hdr);
198 /* join list of requests awaiting response */
199 ilock(&xenstore.rlock);
200 if (xenstore.rhead == 0) {
202 xenstore.rhead = aux;
204 aux->next = xenstore.rhead->next;
205 xenstore.rhead->next = aux;
207 iunlock(&xenstore.rlock);
209 /* loop until matching response header has been received */
211 ilock(&xenstore.rlock);
212 for (lp = &xenstore.rhead; *lp && *lp != aux; lp = &(*lp)->next)
216 if (lp == &xenstore.rhead && *lp)
219 iunlock(&xenstore.rlock);
223 /* wait until this request reaches head of queue */
224 if (xenstore.rhead != aux)
225 sleep(&aux->qr, ishead, aux);
226 /* wait until a response header (maybe for another request) has been read */
227 if (!xenstore.hdrvalid) {
228 xread(0, (char*)&xenstore.hdr, sizeof xenstore.hdr);
229 xenstore.hdrvalid = 1;
231 if (xenstore.hdr.req_id == aux->reqid)
233 /* response was for a different request: move matching request to head of queue */
234 ilock(&xenstore.rlock);
235 for (l = xenstore.rhead; r = l->next; l = r)
236 if (xenstore.hdr.req_id == r->reqid) {
238 r->next = xenstore.rhead;
242 iunlock(&xenstore.rlock);
244 /* wake the matching request */
247 /* response without a request: should be a watch event */
248 xenstore.hdrvalid = 0;
249 xread(0, 0, xenstore.hdr.len);
254 /* queue the response header, and data if any, for the caller to read */
255 qwrite(q, &xenstore.hdr, sizeof xenstore.hdr);
256 xenstore.hdrvalid = 0;
257 /* read the data, if any */
258 if (xenstore.hdr.len > 0)
259 xread(q, 0, xenstore.hdr.len);
261 /* remove finished request and wake the next request on the queue */
262 ilock(&xenstore.rlock);
263 xenstore.rhead = aux->next;
264 iunlock(&xenstore.rlock);
266 if (xenstore.rhead != 0)
267 wakeup(&xenstore.rhead->qr);
273 LOG(dprint("xsreset\n");)
279 intrenable(xenstore.evtchn, xsintr, 0, BUSUNKNOWN, "Xen store");
280 kproc("xenbus", xenbusproc, 0);
286 return devattach('x', spec);
290 xswalk(Chan *c, Chan *nc, char **name, int nname)
292 return devwalk(c, nc, name, nname, xsdir, nelem(xsdir), devgen);
296 xsstat(Chan *c, uchar *dp, int n)
298 return devstat(c, dp, n, xsdir, nelem(xsdir), devgen);
302 auxalloc(int initstate)
307 aux = mallocz(sizeof(Aux), 1);
310 q = qopen(MAXIO, 0, 0, 0);
316 aux->state = initstate;
322 xsopen(Chan *c, int omode)
327 c = devopen(c, omode, xsdir, nelem(xsdir), devgen);
329 switch ((ulong)c->qid.path) {
334 aux = auxalloc(state);
350 if ((c->flag&COPEN) == 0)
353 switch ((ulong)c->qid.path) {
356 if ((aux = (Aux*)c->aux) != 0) {
366 xsread(Chan *c, void *a, long n, vlong off)
373 if (c->qid.type == QTDIR)
374 return devdirread(c, a, n, xsdir, nelem(xsdir), devgen);
383 switch (aux->state) {
388 aux->state = READING;
405 xswrite(Chan *c, void *a, long n, vlong off)
411 if (c->qid.type == QTDIR)
413 if ((ulong)c->qid.path == Qwatch)
423 if ((off == 0 || aux->state == READING) && qlen(q) > 0)
425 aux->state = WRITING;
426 nr = qwrite(aux->ioq, a, n);
432 Dev xenstoredevtab = {
454 xscmd(Aux *aux, char *buf, int cmd, char *s, char *val)
456 struct xsd_sockmsg *msg;
460 msg = (struct xsd_sockmsg*)buf;
461 arg = buf + sizeof(*msg);
463 msg->len = strlen(s)+1;
465 msg->len += strlen(val);
467 msg->len++; /* stupid special case */
471 strcpy(arg+strlen(s)+1, val);
472 n = sizeof(*msg)+msg->len;
477 xread(0, buf, sizeof(*msg));
478 xread(0, arg, msg->len);
481 if (qlen(aux->ioq) > 0)
483 qwrite(aux->ioq, buf, n);
485 qread(aux->ioq, buf, sizeof(*msg));
486 LOG(dprint("xs: type %d req_id %d len %d\n", msg->type, msg->req_id, msg->len);)
487 // XXX buffer overflow
488 qread(aux->ioq, arg, msg->len);
492 if (msg->type == XS_ERROR) {
501 if (xenstore.intf == 0) {
502 xenstore.intf = (struct xenstore_domain_interface*)mmumapframe(XENBUS, xenstart->store_mfn);
503 xenstore.evtchn = xenstart->store_evtchn;
504 xenstore.kernelaux = auxalloc(WRITING);
509 xenstore_write(char *s, char *val)
514 xscmd(xenstore.kernelaux, buf, XS_WRITE, s, val);
518 xenstore_read(char *s, char *val, int len)
524 p = xscmd(xenstore.kernelaux, buf, XS_READ, s, nil);
527 strecpy(val, val+len, p);
532 xenstore_setd(char *dir, char *node, int value)
538 sprint(dir+off, "%s", node);
539 sprint(buf, "%ud", value);
540 xenstore_write(dir, buf);
545 xenstore_gets(char *dir, char *node, char *buf, int buflen)
551 sprint(dir+off, "%s", node);
552 n = xenstore_read(dir, buf, buflen);
563 struct xsd_sockmsg msg;
567 c = namec("#x/xenstore", Aopen, ORDWR, 0);
569 c = namec("#x/xenwatch", Aopen, OREAD, 0);
570 xscmd(aux, buf, XS_WATCH, NodeShutdown, "$");
572 xsread(c, &msg, sizeof(msg), 0);
573 for (n = msg.len; n > 0; n -= m)
574 m = xsread(c, buf, msg.len, sizeof(msg));
576 if (strcmp(buf, NodeShutdown) != 0)
578 p = xscmd(aux, buf, XS_READ, NodeShutdown, nil);
581 if (strcmp(p, "poweroff") == 0)
583 else if (strcmp(p, "reboot") == 0)
586 print("xenbus: %s=%s\n", NodeShutdown, p);
587 xscmd(aux, buf, XS_WRITE, NodeShutdown, "");