ia64/xen-unstable

view extras/mini-os/xenbus/xenbus.c @ 18380:2708ad934551

mini-os: make xenbus_read_integer and xenbus_printf take const strings

Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Aug 27 09:46:22 2008 +0100 (2008-08-27)
parents 433d1b26fd51
children 86db039882ea
line source
1 /*
2 ****************************************************************************
3 * (C) 2006 - Cambridge University
4 ****************************************************************************
5 *
6 * File: xenbus.c
7 * Author: Steven Smith (sos22@cam.ac.uk)
8 * Changes: Grzegorz Milos (gm281@cam.ac.uk)
9 * Changes: John D. Ramsdell
10 *
11 * Date: Jun 2006, chages Aug 2005
12 *
13 * Environment: Xen Minimal OS
14 * Description: Minimal implementation of xenbus
15 *
16 ****************************************************************************
17 **/
18 #include <os.h>
19 #include <mm.h>
20 #include <traps.h>
21 #include <lib.h>
22 #include <xenbus.h>
23 #include <events.h>
24 #include <errno.h>
25 #include <sched.h>
26 #include <wait.h>
27 #include <xen/io/xs_wire.h>
28 #include <spinlock.h>
29 #include <xmalloc.h>
31 #define min(x,y) ({ \
32 typeof(x) tmpx = (x); \
33 typeof(y) tmpy = (y); \
34 tmpx < tmpy ? tmpx : tmpy; \
35 })
37 #ifdef XENBUS_DEBUG
38 #define DEBUG(_f, _a...) \
39 printk("MINI_OS(file=xenbus.c, line=%d) " _f , __LINE__, ## _a)
40 #else
41 #define DEBUG(_f, _a...) ((void)0)
42 #endif
44 static struct xenstore_domain_interface *xenstore_buf;
45 static DECLARE_WAIT_QUEUE_HEAD(xb_waitq);
46 DECLARE_WAIT_QUEUE_HEAD(xenbus_watch_queue);
48 xenbus_event_queue xenbus_events;
49 static struct watch {
50 char *token;
51 xenbus_event_queue *events;
52 struct watch *next;
53 } *watches;
54 struct xenbus_req_info
55 {
56 int in_use:1;
57 struct wait_queue_head waitq;
58 void *reply;
59 };
61 #define NR_REQS 32
62 static struct xenbus_req_info req_info[NR_REQS];
64 static void memcpy_from_ring(const void *Ring,
65 void *Dest,
66 int off,
67 int len)
68 {
69 int c1, c2;
70 const char *ring = Ring;
71 char *dest = Dest;
72 c1 = min(len, XENSTORE_RING_SIZE - off);
73 c2 = len - c1;
74 memcpy(dest, ring + off, c1);
75 memcpy(dest + c1, ring, c2);
76 }
78 char **xenbus_wait_for_watch_return(xenbus_event_queue *queue)
79 {
80 struct xenbus_event *event;
81 DEFINE_WAIT(w);
82 if (!queue)
83 queue = &xenbus_events;
84 while (!(event = *queue)) {
85 add_waiter(w, xenbus_watch_queue);
86 schedule();
87 }
88 remove_waiter(w);
89 *queue = event->next;
90 return &event->path;
91 }
93 void xenbus_wait_for_watch(xenbus_event_queue *queue)
94 {
95 char **ret;
96 if (!queue)
97 queue = &xenbus_events;
98 ret = xenbus_wait_for_watch_return(queue);
99 free(ret);
100 }
102 char* xenbus_wait_for_value(const char* path, const char* value, xenbus_event_queue *queue)
103 {
104 if (!queue)
105 queue = &xenbus_events;
106 for(;;)
107 {
108 char *res, *msg;
109 int r;
111 msg = xenbus_read(XBT_NIL, path, &res);
112 if(msg) return msg;
114 r = strcmp(value,res);
115 free(res);
117 if(r==0) break;
118 else xenbus_wait_for_watch(queue);
119 }
120 return NULL;
121 }
124 static void xenbus_thread_func(void *ign)
125 {
126 struct xsd_sockmsg msg;
127 unsigned prod = xenstore_buf->rsp_prod;
129 for (;;)
130 {
131 wait_event(xb_waitq, prod != xenstore_buf->rsp_prod);
132 while (1)
133 {
134 prod = xenstore_buf->rsp_prod;
135 DEBUG("Rsp_cons %d, rsp_prod %d.\n", xenstore_buf->rsp_cons,
136 xenstore_buf->rsp_prod);
137 if (xenstore_buf->rsp_prod - xenstore_buf->rsp_cons < sizeof(msg))
138 break;
139 rmb();
140 memcpy_from_ring(xenstore_buf->rsp,
141 &msg,
142 MASK_XENSTORE_IDX(xenstore_buf->rsp_cons),
143 sizeof(msg));
144 DEBUG("Msg len %d, %d avail, id %d.\n",
145 msg.len + sizeof(msg),
146 xenstore_buf->rsp_prod - xenstore_buf->rsp_cons,
147 msg.req_id);
148 if (xenstore_buf->rsp_prod - xenstore_buf->rsp_cons <
149 sizeof(msg) + msg.len)
150 break;
152 DEBUG("Message is good.\n");
154 if(msg.type == XS_WATCH_EVENT)
155 {
156 struct xenbus_event *event = malloc(sizeof(*event) + msg.len);
157 xenbus_event_queue *events = NULL;
158 char *data = (char*)event + sizeof(*event);
159 struct watch *watch;
161 memcpy_from_ring(xenstore_buf->rsp,
162 data,
163 MASK_XENSTORE_IDX(xenstore_buf->rsp_cons + sizeof(msg)),
164 msg.len);
166 event->path = data;
167 event->token = event->path + strlen(event->path) + 1;
169 xenstore_buf->rsp_cons += msg.len + sizeof(msg);
171 for (watch = watches; watch; watch = watch->next)
172 if (!strcmp(watch->token, event->token)) {
173 events = watch->events;
174 break;
175 }
177 if (events) {
178 event->next = *events;
179 *events = event;
180 wake_up(&xenbus_watch_queue);
181 } else {
182 printk("unexpected watch token %s\n", event->token);
183 free(event);
184 }
185 }
187 else
188 {
189 req_info[msg.req_id].reply = malloc(sizeof(msg) + msg.len);
190 memcpy_from_ring(xenstore_buf->rsp,
191 req_info[msg.req_id].reply,
192 MASK_XENSTORE_IDX(xenstore_buf->rsp_cons),
193 msg.len + sizeof(msg));
194 xenstore_buf->rsp_cons += msg.len + sizeof(msg);
195 wake_up(&req_info[msg.req_id].waitq);
196 }
197 }
198 }
199 }
201 static void xenbus_evtchn_handler(evtchn_port_t port, struct pt_regs *regs,
202 void *ign)
203 {
204 wake_up(&xb_waitq);
205 }
207 static int nr_live_reqs;
208 static spinlock_t req_lock = SPIN_LOCK_UNLOCKED;
209 static DECLARE_WAIT_QUEUE_HEAD(req_wq);
211 /* Release a xenbus identifier */
212 static void release_xenbus_id(int id)
213 {
214 BUG_ON(!req_info[id].in_use);
215 spin_lock(&req_lock);
216 req_info[id].in_use = 0;
217 nr_live_reqs--;
218 req_info[id].in_use = 0;
219 if (nr_live_reqs == NR_REQS - 1)
220 wake_up(&req_wq);
221 spin_unlock(&req_lock);
222 }
224 /* Allocate an identifier for a xenbus request. Blocks if none are
225 available. */
226 static int allocate_xenbus_id(void)
227 {
228 static int probe;
229 int o_probe;
231 while (1)
232 {
233 spin_lock(&req_lock);
234 if (nr_live_reqs < NR_REQS)
235 break;
236 spin_unlock(&req_lock);
237 wait_event(req_wq, (nr_live_reqs < NR_REQS));
238 }
240 o_probe = probe;
241 for (;;)
242 {
243 if (!req_info[o_probe].in_use)
244 break;
245 o_probe = (o_probe + 1) % NR_REQS;
246 BUG_ON(o_probe == probe);
247 }
248 nr_live_reqs++;
249 req_info[o_probe].in_use = 1;
250 probe = (o_probe + 1) % NR_REQS;
251 spin_unlock(&req_lock);
252 init_waitqueue_head(&req_info[o_probe].waitq);
254 return o_probe;
255 }
257 /* Initialise xenbus. */
258 void init_xenbus(void)
259 {
260 int err;
261 printk("Initialising xenbus\n");
262 DEBUG("init_xenbus called.\n");
263 xenstore_buf = mfn_to_virt(start_info.store_mfn);
264 create_thread("xenstore", xenbus_thread_func, NULL);
265 DEBUG("buf at %p.\n", xenstore_buf);
266 err = bind_evtchn(start_info.store_evtchn,
267 xenbus_evtchn_handler,
268 NULL);
269 unmask_evtchn(start_info.store_evtchn);
270 DEBUG("xenbus on irq %d\n", err);
271 }
273 void fini_xenbus(void)
274 {
275 }
277 /* Send data to xenbus. This can block. All of the requests are seen
278 by xenbus as if sent atomically. The header is added
279 automatically, using type %type, req_id %req_id, and trans_id
280 %trans_id. */
281 static void xb_write(int type, int req_id, xenbus_transaction_t trans_id,
282 const struct write_req *req, int nr_reqs)
283 {
284 XENSTORE_RING_IDX prod;
285 int r;
286 int len = 0;
287 const struct write_req *cur_req;
288 int req_off;
289 int total_off;
290 int this_chunk;
291 struct xsd_sockmsg m = {.type = type, .req_id = req_id,
292 .tx_id = trans_id };
293 struct write_req header_req = { &m, sizeof(m) };
295 for (r = 0; r < nr_reqs; r++)
296 len += req[r].len;
297 m.len = len;
298 len += sizeof(m);
300 cur_req = &header_req;
302 BUG_ON(len > XENSTORE_RING_SIZE);
303 /* Wait for the ring to drain to the point where we can send the
304 message. */
305 prod = xenstore_buf->req_prod;
306 if (prod + len - xenstore_buf->req_cons > XENSTORE_RING_SIZE)
307 {
308 /* Wait for there to be space on the ring */
309 DEBUG("prod %d, len %d, cons %d, size %d; waiting.\n",
310 prod, len, xenstore_buf->req_cons, XENSTORE_RING_SIZE);
311 wait_event(xb_waitq,
312 xenstore_buf->req_prod + len - xenstore_buf->req_cons <=
313 XENSTORE_RING_SIZE);
314 DEBUG("Back from wait.\n");
315 prod = xenstore_buf->req_prod;
316 }
318 /* We're now guaranteed to be able to send the message without
319 overflowing the ring. Do so. */
320 total_off = 0;
321 req_off = 0;
322 while (total_off < len)
323 {
324 this_chunk = min(cur_req->len - req_off,
325 XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod));
326 memcpy((char *)xenstore_buf->req + MASK_XENSTORE_IDX(prod),
327 (char *)cur_req->data + req_off, this_chunk);
328 prod += this_chunk;
329 req_off += this_chunk;
330 total_off += this_chunk;
331 if (req_off == cur_req->len)
332 {
333 req_off = 0;
334 if (cur_req == &header_req)
335 cur_req = req;
336 else
337 cur_req++;
338 }
339 }
341 DEBUG("Complete main loop of xb_write.\n");
342 BUG_ON(req_off != 0);
343 BUG_ON(total_off != len);
344 BUG_ON(prod > xenstore_buf->req_cons + XENSTORE_RING_SIZE);
346 /* Remote must see entire message before updating indexes */
347 wmb();
349 xenstore_buf->req_prod += len;
351 /* Send evtchn to notify remote */
352 notify_remote_via_evtchn(start_info.store_evtchn);
353 }
355 /* Send a mesasge to xenbus, in the same fashion as xb_write, and
356 block waiting for a reply. The reply is malloced and should be
357 freed by the caller. */
358 struct xsd_sockmsg *
359 xenbus_msg_reply(int type,
360 xenbus_transaction_t trans,
361 struct write_req *io,
362 int nr_reqs)
363 {
364 int id;
365 DEFINE_WAIT(w);
366 struct xsd_sockmsg *rep;
368 id = allocate_xenbus_id();
369 add_waiter(w, req_info[id].waitq);
371 xb_write(type, id, trans, io, nr_reqs);
373 schedule();
374 remove_waiter(w);
375 wake(current);
377 rep = req_info[id].reply;
378 BUG_ON(rep->req_id != id);
379 release_xenbus_id(id);
380 return rep;
381 }
383 static char *errmsg(struct xsd_sockmsg *rep)
384 {
385 char *res;
386 if (!rep) {
387 char msg[] = "No reply";
388 size_t len = strlen(msg) + 1;
389 return memcpy(malloc(len), msg, len);
390 }
391 if (rep->type != XS_ERROR)
392 return NULL;
393 res = malloc(rep->len + 1);
394 memcpy(res, rep + 1, rep->len);
395 res[rep->len] = 0;
396 free(rep);
397 return res;
398 }
400 /* Send a debug message to xenbus. Can block. */
401 static void xenbus_debug_msg(const char *msg)
402 {
403 int len = strlen(msg);
404 struct write_req req[] = {
405 { "print", sizeof("print") },
406 { msg, len },
407 { "", 1 }};
408 struct xsd_sockmsg *reply;
410 reply = xenbus_msg_reply(XS_DEBUG, 0, req, ARRAY_SIZE(req));
411 DEBUG("Got a reply, type %d, id %d, len %d.\n",
412 reply->type, reply->req_id, reply->len);
413 }
415 /* List the contents of a directory. Returns a malloc()ed array of
416 pointers to malloc()ed strings. The array is NULL terminated. May
417 block. */
418 char *xenbus_ls(xenbus_transaction_t xbt, const char *pre, char ***contents)
419 {
420 struct xsd_sockmsg *reply, *repmsg;
421 struct write_req req[] = { { pre, strlen(pre)+1 } };
422 int nr_elems, x, i;
423 char **res, *msg;
425 repmsg = xenbus_msg_reply(XS_DIRECTORY, xbt, req, ARRAY_SIZE(req));
426 msg = errmsg(repmsg);
427 if (msg) {
428 *contents = NULL;
429 return msg;
430 }
431 reply = repmsg + 1;
432 for (x = nr_elems = 0; x < repmsg->len; x++)
433 nr_elems += (((char *)reply)[x] == 0);
434 res = malloc(sizeof(res[0]) * (nr_elems + 1));
435 for (x = i = 0; i < nr_elems; i++) {
436 int l = strlen((char *)reply + x);
437 res[i] = malloc(l + 1);
438 memcpy(res[i], (char *)reply + x, l + 1);
439 x += l + 1;
440 }
441 res[i] = NULL;
442 free(repmsg);
443 *contents = res;
444 return NULL;
445 }
447 char *xenbus_read(xenbus_transaction_t xbt, const char *path, char **value)
448 {
449 struct write_req req[] = { {path, strlen(path) + 1} };
450 struct xsd_sockmsg *rep;
451 char *res, *msg;
452 rep = xenbus_msg_reply(XS_READ, xbt, req, ARRAY_SIZE(req));
453 msg = errmsg(rep);
454 if (msg) {
455 *value = NULL;
456 return msg;
457 }
458 res = malloc(rep->len + 1);
459 memcpy(res, rep + 1, rep->len);
460 res[rep->len] = 0;
461 free(rep);
462 *value = res;
463 return NULL;
464 }
466 char *xenbus_write(xenbus_transaction_t xbt, const char *path, const char *value)
467 {
468 struct write_req req[] = {
469 {path, strlen(path) + 1},
470 {value, strlen(value)},
471 };
472 struct xsd_sockmsg *rep;
473 char *msg;
474 rep = xenbus_msg_reply(XS_WRITE, xbt, req, ARRAY_SIZE(req));
475 msg = errmsg(rep);
476 if (msg) return msg;
477 free(rep);
478 return NULL;
479 }
481 char* xenbus_watch_path_token( xenbus_transaction_t xbt, const char *path, const char *token, xenbus_event_queue *events)
482 {
483 struct xsd_sockmsg *rep;
485 struct write_req req[] = {
486 {path, strlen(path) + 1},
487 {token, strlen(token) + 1},
488 };
490 struct watch *watch = malloc(sizeof(*watch));
492 char *msg;
494 if (!events)
495 events = &xenbus_events;
497 watch->token = strdup(token);
498 watch->events = events;
499 watch->next = watches;
500 watches = watch;
502 rep = xenbus_msg_reply(XS_WATCH, xbt, req, ARRAY_SIZE(req));
504 msg = errmsg(rep);
505 if (msg) return msg;
506 free(rep);
508 return NULL;
509 }
511 char* xenbus_unwatch_path_token( xenbus_transaction_t xbt, const char *path, const char *token)
512 {
513 struct xsd_sockmsg *rep;
515 struct write_req req[] = {
516 {path, strlen(path) + 1},
517 {token, strlen(token) + 1},
518 };
520 struct watch *watch, **prev;
522 char *msg;
524 rep = xenbus_msg_reply(XS_UNWATCH, xbt, req, ARRAY_SIZE(req));
526 msg = errmsg(rep);
527 if (msg) return msg;
528 free(rep);
530 for (prev = &watches, watch = *prev; watch; prev = &watch->next, watch = *prev)
531 if (!strcmp(watch->token, token)) {
532 free(watch->token);
533 *prev = watch->next;
534 free(watch);
535 break;
536 }
538 return NULL;
539 }
541 char *xenbus_rm(xenbus_transaction_t xbt, const char *path)
542 {
543 struct write_req req[] = { {path, strlen(path) + 1} };
544 struct xsd_sockmsg *rep;
545 char *msg;
546 rep = xenbus_msg_reply(XS_RM, xbt, req, ARRAY_SIZE(req));
547 msg = errmsg(rep);
548 if (msg)
549 return msg;
550 free(rep);
551 return NULL;
552 }
554 char *xenbus_get_perms(xenbus_transaction_t xbt, const char *path, char **value)
555 {
556 struct write_req req[] = { {path, strlen(path) + 1} };
557 struct xsd_sockmsg *rep;
558 char *res, *msg;
559 rep = xenbus_msg_reply(XS_GET_PERMS, xbt, req, ARRAY_SIZE(req));
560 msg = errmsg(rep);
561 if (msg) {
562 *value = NULL;
563 return msg;
564 }
565 res = malloc(rep->len + 1);
566 memcpy(res, rep + 1, rep->len);
567 res[rep->len] = 0;
568 free(rep);
569 *value = res;
570 return NULL;
571 }
573 #define PERM_MAX_SIZE 32
574 char *xenbus_set_perms(xenbus_transaction_t xbt, const char *path, domid_t dom, char perm)
575 {
576 char value[PERM_MAX_SIZE];
577 struct write_req req[] = {
578 {path, strlen(path) + 1},
579 {value, 0},
580 };
581 struct xsd_sockmsg *rep;
582 char *msg;
583 snprintf(value, PERM_MAX_SIZE, "%c%hu", perm, dom);
584 req[1].len = strlen(value) + 1;
585 rep = xenbus_msg_reply(XS_SET_PERMS, xbt, req, ARRAY_SIZE(req));
586 msg = errmsg(rep);
587 if (msg)
588 return msg;
589 free(rep);
590 return NULL;
591 }
593 char *xenbus_transaction_start(xenbus_transaction_t *xbt)
594 {
595 /* xenstored becomes angry if you send a length 0 message, so just
596 shove a nul terminator on the end */
597 struct write_req req = { "", 1};
598 struct xsd_sockmsg *rep;
599 char *err;
601 rep = xenbus_msg_reply(XS_TRANSACTION_START, 0, &req, 1);
602 err = errmsg(rep);
603 if (err)
604 return err;
605 sscanf((char *)(rep + 1), "%u", xbt);
606 free(rep);
607 return NULL;
608 }
610 char *
611 xenbus_transaction_end(xenbus_transaction_t t, int abort, int *retry)
612 {
613 struct xsd_sockmsg *rep;
614 struct write_req req;
615 char *err;
617 *retry = 0;
619 req.data = abort ? "F" : "T";
620 req.len = 2;
621 rep = xenbus_msg_reply(XS_TRANSACTION_END, t, &req, 1);
622 err = errmsg(rep);
623 if (err) {
624 if (!strcmp(err, "EAGAIN")) {
625 *retry = 1;
626 free(err);
627 return NULL;
628 } else {
629 return err;
630 }
631 }
632 free(rep);
633 return NULL;
634 }
636 int xenbus_read_integer(const char *path)
637 {
638 char *res, *buf;
639 int t;
641 res = xenbus_read(XBT_NIL, path, &buf);
642 if (res) {
643 printk("Failed to read %s.\n", path);
644 free(res);
645 return -1;
646 }
647 sscanf(buf, "%d", &t);
648 free(buf);
649 return t;
650 }
652 char* xenbus_printf(xenbus_transaction_t xbt,
653 const char* node, const char* path,
654 const char* fmt, ...)
655 {
656 #define BUFFER_SIZE 256
657 char fullpath[BUFFER_SIZE];
658 char val[BUFFER_SIZE];
659 va_list args;
661 BUG_ON(strlen(node) + strlen(path) + 1 >= BUFFER_SIZE);
662 sprintf(fullpath,"%s/%s", node, path);
663 va_start(args, fmt);
664 vsprintf(val, fmt, args);
665 va_end(args);
666 return xenbus_write(xbt,fullpath,val);
667 }
669 static void do_ls_test(const char *pre)
670 {
671 char **dirs, *msg;
672 int x;
674 DEBUG("ls %s...\n", pre);
675 msg = xenbus_ls(XBT_NIL, pre, &dirs);
676 if (msg) {
677 DEBUG("Error in xenbus ls: %s\n", msg);
678 free(msg);
679 return;
680 }
681 for (x = 0; dirs[x]; x++)
682 {
683 DEBUG("ls %s[%d] -> %s\n", pre, x, dirs[x]);
684 free(dirs[x]);
685 }
686 free(dirs);
687 }
689 static void do_read_test(const char *path)
690 {
691 char *res, *msg;
692 DEBUG("Read %s...\n", path);
693 msg = xenbus_read(XBT_NIL, path, &res);
694 if (msg) {
695 DEBUG("Error in xenbus read: %s\n", msg);
696 free(msg);
697 return;
698 }
699 DEBUG("Read %s -> %s.\n", path, res);
700 free(res);
701 }
703 static void do_write_test(const char *path, const char *val)
704 {
705 char *msg;
706 DEBUG("Write %s to %s...\n", val, path);
707 msg = xenbus_write(XBT_NIL, path, val);
708 if (msg) {
709 DEBUG("Result %s\n", msg);
710 free(msg);
711 } else {
712 DEBUG("Success.\n");
713 }
714 }
716 static void do_rm_test(const char *path)
717 {
718 char *msg;
719 DEBUG("rm %s...\n", path);
720 msg = xenbus_rm(XBT_NIL, path);
721 if (msg) {
722 DEBUG("Result %s\n", msg);
723 free(msg);
724 } else {
725 DEBUG("Success.\n");
726 }
727 }
729 /* Simple testing thing */
730 void test_xenbus(void)
731 {
732 DEBUG("Doing xenbus test.\n");
733 xenbus_debug_msg("Testing xenbus...\n");
735 DEBUG("Doing ls test.\n");
736 do_ls_test("device");
737 do_ls_test("device/vif");
738 do_ls_test("device/vif/0");
740 DEBUG("Doing read test.\n");
741 do_read_test("device/vif/0/mac");
742 do_read_test("device/vif/0/backend");
744 DEBUG("Doing write test.\n");
745 do_write_test("device/vif/0/flibble", "flobble");
746 do_read_test("device/vif/0/flibble");
747 do_write_test("device/vif/0/flibble", "widget");
748 do_read_test("device/vif/0/flibble");
750 DEBUG("Doing rm test.\n");
751 do_rm_test("device/vif/0/flibble");
752 do_read_test("device/vif/0/flibble");
753 DEBUG("(Should have said ENOENT)\n");
754 }
756 /*
757 * Local variables:
758 * mode: C
759 * c-basic-offset: 4
760 * End:
761 */