debuggers.hg

view extras/mini-os/xenbus/xenbus.c @ 20689:23bc248302df

mini-os: Fix memory leaks in blkfront, netfront, pcifront, etc.

The return value of Xenbus routines xenbus_transaction_start(),
xenbus_printf(), xenbus_transaction_end(), etc. is a pointer of error
message. This pointer should be passed to free() to release the
allocated memory when it is no longer needed.

Signed-off-by: Yu Zhiguo <yuzg@cn.fujitsu.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Dec 14 09:51:07 2009 +0000 (2009-12-14)
parents dd951d96304a
children 6c833a9ee3c4
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 <mini-os/os.h>
19 #include <mini-os/mm.h>
20 #include <mini-os/traps.h>
21 #include <mini-os/lib.h>
22 #include <mini-os/xenbus.h>
23 #include <mini-os/events.h>
24 #include <mini-os/errno.h>
25 #include <mini-os/sched.h>
26 #include <mini-os/wait.h>
27 #include <xen/io/xs_wire.h>
28 #include <mini-os/spinlock.h>
29 #include <mini-os/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 if (ret)
100 free(ret);
101 else
102 printk("unexpected path returned by watch\n");
103 }
105 char* xenbus_wait_for_value(const char* path, const char* value, xenbus_event_queue *queue)
106 {
107 if (!queue)
108 queue = &xenbus_events;
109 for(;;)
110 {
111 char *res, *msg;
112 int r;
114 msg = xenbus_read(XBT_NIL, path, &res);
115 if(msg) return msg;
117 r = strcmp(value,res);
118 free(res);
120 if(r==0) break;
121 else xenbus_wait_for_watch(queue);
122 }
123 return NULL;
124 }
126 char *xenbus_switch_state(xenbus_transaction_t xbt, const char* path, XenbusState state)
127 {
128 char *current_state;
129 char *msg = NULL;
130 char *msg2 = NULL;
131 char value[2];
132 XenbusState rs;
133 int xbt_flag = 0;
134 int retry = 0;
136 do {
137 if (xbt == XBT_NIL) {
138 msg = xenbus_transaction_start(&xbt);
139 if (msg) goto exit;
140 xbt_flag = 1;
141 }
143 msg = xenbus_read(xbt, path, &current_state);
144 if (msg) goto exit;
146 rs = (XenbusState) (current_state[0] - '0');
147 free(current_state);
148 if (rs == state) {
149 msg = NULL;
150 goto exit;
151 }
153 snprintf(value, 2, "%d", state);
154 msg = xenbus_write(xbt, path, value);
156 exit:
157 if (xbt_flag)
158 msg2 = xenbus_transaction_end(xbt, 0, &retry);
159 if (msg == NULL && msg2 != NULL)
160 msg = msg2;
161 } while (retry);
163 return msg;
164 }
166 char *xenbus_wait_for_state_change(const char* path, XenbusState *state, xenbus_event_queue *queue)
167 {
168 if (!queue)
169 queue = &xenbus_events;
170 for(;;)
171 {
172 char *res, *msg;
173 XenbusState rs;
175 msg = xenbus_read(XBT_NIL, path, &res);
176 if(msg) return msg;
178 rs = (XenbusState) (res[0] - 48);
179 free(res);
181 if (rs == *state)
182 xenbus_wait_for_watch(queue);
183 else {
184 *state = rs;
185 break;
186 }
187 }
188 return NULL;
189 }
192 static void xenbus_thread_func(void *ign)
193 {
194 struct xsd_sockmsg msg;
195 unsigned prod = xenstore_buf->rsp_prod;
197 for (;;)
198 {
199 wait_event(xb_waitq, prod != xenstore_buf->rsp_prod);
200 while (1)
201 {
202 prod = xenstore_buf->rsp_prod;
203 DEBUG("Rsp_cons %d, rsp_prod %d.\n", xenstore_buf->rsp_cons,
204 xenstore_buf->rsp_prod);
205 if (xenstore_buf->rsp_prod - xenstore_buf->rsp_cons < sizeof(msg))
206 break;
207 rmb();
208 memcpy_from_ring(xenstore_buf->rsp,
209 &msg,
210 MASK_XENSTORE_IDX(xenstore_buf->rsp_cons),
211 sizeof(msg));
212 DEBUG("Msg len %d, %d avail, id %d.\n",
213 msg.len + sizeof(msg),
214 xenstore_buf->rsp_prod - xenstore_buf->rsp_cons,
215 msg.req_id);
216 if (xenstore_buf->rsp_prod - xenstore_buf->rsp_cons <
217 sizeof(msg) + msg.len)
218 break;
220 DEBUG("Message is good.\n");
222 if(msg.type == XS_WATCH_EVENT)
223 {
224 struct xenbus_event *event = malloc(sizeof(*event) + msg.len);
225 xenbus_event_queue *events = NULL;
226 char *data = (char*)event + sizeof(*event);
227 struct watch *watch;
229 memcpy_from_ring(xenstore_buf->rsp,
230 data,
231 MASK_XENSTORE_IDX(xenstore_buf->rsp_cons + sizeof(msg)),
232 msg.len);
234 event->path = data;
235 event->token = event->path + strlen(event->path) + 1;
237 xenstore_buf->rsp_cons += msg.len + sizeof(msg);
239 for (watch = watches; watch; watch = watch->next)
240 if (!strcmp(watch->token, event->token)) {
241 events = watch->events;
242 break;
243 }
245 if (events) {
246 event->next = *events;
247 *events = event;
248 wake_up(&xenbus_watch_queue);
249 } else {
250 printk("unexpected watch token %s\n", event->token);
251 free(event);
252 }
253 }
255 else
256 {
257 req_info[msg.req_id].reply = malloc(sizeof(msg) + msg.len);
258 memcpy_from_ring(xenstore_buf->rsp,
259 req_info[msg.req_id].reply,
260 MASK_XENSTORE_IDX(xenstore_buf->rsp_cons),
261 msg.len + sizeof(msg));
262 xenstore_buf->rsp_cons += msg.len + sizeof(msg);
263 wake_up(&req_info[msg.req_id].waitq);
264 }
265 }
266 }
267 }
269 static void xenbus_evtchn_handler(evtchn_port_t port, struct pt_regs *regs,
270 void *ign)
271 {
272 wake_up(&xb_waitq);
273 }
275 static int nr_live_reqs;
276 static spinlock_t req_lock = SPIN_LOCK_UNLOCKED;
277 static DECLARE_WAIT_QUEUE_HEAD(req_wq);
279 /* Release a xenbus identifier */
280 static void release_xenbus_id(int id)
281 {
282 BUG_ON(!req_info[id].in_use);
283 spin_lock(&req_lock);
284 req_info[id].in_use = 0;
285 nr_live_reqs--;
286 req_info[id].in_use = 0;
287 if (nr_live_reqs == NR_REQS - 1)
288 wake_up(&req_wq);
289 spin_unlock(&req_lock);
290 }
292 /* Allocate an identifier for a xenbus request. Blocks if none are
293 available. */
294 static int allocate_xenbus_id(void)
295 {
296 static int probe;
297 int o_probe;
299 while (1)
300 {
301 spin_lock(&req_lock);
302 if (nr_live_reqs < NR_REQS)
303 break;
304 spin_unlock(&req_lock);
305 wait_event(req_wq, (nr_live_reqs < NR_REQS));
306 }
308 o_probe = probe;
309 for (;;)
310 {
311 if (!req_info[o_probe].in_use)
312 break;
313 o_probe = (o_probe + 1) % NR_REQS;
314 BUG_ON(o_probe == probe);
315 }
316 nr_live_reqs++;
317 req_info[o_probe].in_use = 1;
318 probe = (o_probe + 1) % NR_REQS;
319 spin_unlock(&req_lock);
320 init_waitqueue_head(&req_info[o_probe].waitq);
322 return o_probe;
323 }
325 /* Initialise xenbus. */
326 void init_xenbus(void)
327 {
328 int err;
329 printk("Initialising xenbus\n");
330 DEBUG("init_xenbus called.\n");
331 xenstore_buf = mfn_to_virt(start_info.store_mfn);
332 create_thread("xenstore", xenbus_thread_func, NULL);
333 DEBUG("buf at %p.\n", xenstore_buf);
334 err = bind_evtchn(start_info.store_evtchn,
335 xenbus_evtchn_handler,
336 NULL);
337 unmask_evtchn(start_info.store_evtchn);
338 DEBUG("xenbus on irq %d\n", err);
339 }
341 void fini_xenbus(void)
342 {
343 }
345 /* Send data to xenbus. This can block. All of the requests are seen
346 by xenbus as if sent atomically. The header is added
347 automatically, using type %type, req_id %req_id, and trans_id
348 %trans_id. */
349 static void xb_write(int type, int req_id, xenbus_transaction_t trans_id,
350 const struct write_req *req, int nr_reqs)
351 {
352 XENSTORE_RING_IDX prod;
353 int r;
354 int len = 0;
355 const struct write_req *cur_req;
356 int req_off;
357 int total_off;
358 int this_chunk;
359 struct xsd_sockmsg m = {.type = type, .req_id = req_id,
360 .tx_id = trans_id };
361 struct write_req header_req = { &m, sizeof(m) };
363 for (r = 0; r < nr_reqs; r++)
364 len += req[r].len;
365 m.len = len;
366 len += sizeof(m);
368 cur_req = &header_req;
370 BUG_ON(len > XENSTORE_RING_SIZE);
371 /* Wait for the ring to drain to the point where we can send the
372 message. */
373 prod = xenstore_buf->req_prod;
374 if (prod + len - xenstore_buf->req_cons > XENSTORE_RING_SIZE)
375 {
376 /* Wait for there to be space on the ring */
377 DEBUG("prod %d, len %d, cons %d, size %d; waiting.\n",
378 prod, len, xenstore_buf->req_cons, XENSTORE_RING_SIZE);
379 wait_event(xb_waitq,
380 xenstore_buf->req_prod + len - xenstore_buf->req_cons <=
381 XENSTORE_RING_SIZE);
382 DEBUG("Back from wait.\n");
383 prod = xenstore_buf->req_prod;
384 }
386 /* We're now guaranteed to be able to send the message without
387 overflowing the ring. Do so. */
388 total_off = 0;
389 req_off = 0;
390 while (total_off < len)
391 {
392 this_chunk = min(cur_req->len - req_off,
393 XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod));
394 memcpy((char *)xenstore_buf->req + MASK_XENSTORE_IDX(prod),
395 (char *)cur_req->data + req_off, this_chunk);
396 prod += this_chunk;
397 req_off += this_chunk;
398 total_off += this_chunk;
399 if (req_off == cur_req->len)
400 {
401 req_off = 0;
402 if (cur_req == &header_req)
403 cur_req = req;
404 else
405 cur_req++;
406 }
407 }
409 DEBUG("Complete main loop of xb_write.\n");
410 BUG_ON(req_off != 0);
411 BUG_ON(total_off != len);
412 BUG_ON(prod > xenstore_buf->req_cons + XENSTORE_RING_SIZE);
414 /* Remote must see entire message before updating indexes */
415 wmb();
417 xenstore_buf->req_prod += len;
419 /* Send evtchn to notify remote */
420 notify_remote_via_evtchn(start_info.store_evtchn);
421 }
423 /* Send a mesasge to xenbus, in the same fashion as xb_write, and
424 block waiting for a reply. The reply is malloced and should be
425 freed by the caller. */
426 struct xsd_sockmsg *
427 xenbus_msg_reply(int type,
428 xenbus_transaction_t trans,
429 struct write_req *io,
430 int nr_reqs)
431 {
432 int id;
433 DEFINE_WAIT(w);
434 struct xsd_sockmsg *rep;
436 id = allocate_xenbus_id();
437 add_waiter(w, req_info[id].waitq);
439 xb_write(type, id, trans, io, nr_reqs);
441 schedule();
442 remove_waiter(w);
443 wake(current);
445 rep = req_info[id].reply;
446 BUG_ON(rep->req_id != id);
447 release_xenbus_id(id);
448 return rep;
449 }
451 static char *errmsg(struct xsd_sockmsg *rep)
452 {
453 char *res;
454 if (!rep) {
455 char msg[] = "No reply";
456 size_t len = strlen(msg) + 1;
457 return memcpy(malloc(len), msg, len);
458 }
459 if (rep->type != XS_ERROR)
460 return NULL;
461 res = malloc(rep->len + 1);
462 memcpy(res, rep + 1, rep->len);
463 res[rep->len] = 0;
464 free(rep);
465 return res;
466 }
468 /* Send a debug message to xenbus. Can block. */
469 static void xenbus_debug_msg(const char *msg)
470 {
471 int len = strlen(msg);
472 struct write_req req[] = {
473 { "print", sizeof("print") },
474 { msg, len },
475 { "", 1 }};
476 struct xsd_sockmsg *reply;
478 reply = xenbus_msg_reply(XS_DEBUG, 0, req, ARRAY_SIZE(req));
479 DEBUG("Got a reply, type %d, id %d, len %d.\n",
480 reply->type, reply->req_id, reply->len);
481 }
483 /* List the contents of a directory. Returns a malloc()ed array of
484 pointers to malloc()ed strings. The array is NULL terminated. May
485 block. */
486 char *xenbus_ls(xenbus_transaction_t xbt, const char *pre, char ***contents)
487 {
488 struct xsd_sockmsg *reply, *repmsg;
489 struct write_req req[] = { { pre, strlen(pre)+1 } };
490 int nr_elems, x, i;
491 char **res, *msg;
493 repmsg = xenbus_msg_reply(XS_DIRECTORY, xbt, req, ARRAY_SIZE(req));
494 msg = errmsg(repmsg);
495 if (msg) {
496 *contents = NULL;
497 return msg;
498 }
499 reply = repmsg + 1;
500 for (x = nr_elems = 0; x < repmsg->len; x++)
501 nr_elems += (((char *)reply)[x] == 0);
502 res = malloc(sizeof(res[0]) * (nr_elems + 1));
503 for (x = i = 0; i < nr_elems; i++) {
504 int l = strlen((char *)reply + x);
505 res[i] = malloc(l + 1);
506 memcpy(res[i], (char *)reply + x, l + 1);
507 x += l + 1;
508 }
509 res[i] = NULL;
510 free(repmsg);
511 *contents = res;
512 return NULL;
513 }
515 char *xenbus_read(xenbus_transaction_t xbt, const char *path, char **value)
516 {
517 struct write_req req[] = { {path, strlen(path) + 1} };
518 struct xsd_sockmsg *rep;
519 char *res, *msg;
520 rep = xenbus_msg_reply(XS_READ, xbt, req, ARRAY_SIZE(req));
521 msg = errmsg(rep);
522 if (msg) {
523 *value = NULL;
524 return msg;
525 }
526 res = malloc(rep->len + 1);
527 memcpy(res, rep + 1, rep->len);
528 res[rep->len] = 0;
529 free(rep);
530 *value = res;
531 return NULL;
532 }
534 char *xenbus_write(xenbus_transaction_t xbt, const char *path, const char *value)
535 {
536 struct write_req req[] = {
537 {path, strlen(path) + 1},
538 {value, strlen(value)},
539 };
540 struct xsd_sockmsg *rep;
541 char *msg;
542 rep = xenbus_msg_reply(XS_WRITE, xbt, req, ARRAY_SIZE(req));
543 msg = errmsg(rep);
544 if (msg) return msg;
545 free(rep);
546 return NULL;
547 }
549 char* xenbus_watch_path_token( xenbus_transaction_t xbt, const char *path, const char *token, xenbus_event_queue *events)
550 {
551 struct xsd_sockmsg *rep;
553 struct write_req req[] = {
554 {path, strlen(path) + 1},
555 {token, strlen(token) + 1},
556 };
558 struct watch *watch = malloc(sizeof(*watch));
560 char *msg;
562 if (!events)
563 events = &xenbus_events;
565 watch->token = strdup(token);
566 watch->events = events;
567 watch->next = watches;
568 watches = watch;
570 rep = xenbus_msg_reply(XS_WATCH, xbt, req, ARRAY_SIZE(req));
572 msg = errmsg(rep);
573 if (msg) return msg;
574 free(rep);
576 return NULL;
577 }
579 char* xenbus_unwatch_path_token( xenbus_transaction_t xbt, const char *path, const char *token)
580 {
581 struct xsd_sockmsg *rep;
583 struct write_req req[] = {
584 {path, strlen(path) + 1},
585 {token, strlen(token) + 1},
586 };
588 struct watch *watch, **prev;
590 char *msg;
592 rep = xenbus_msg_reply(XS_UNWATCH, xbt, req, ARRAY_SIZE(req));
594 msg = errmsg(rep);
595 if (msg) return msg;
596 free(rep);
598 for (prev = &watches, watch = *prev; watch; prev = &watch->next, watch = *prev)
599 if (!strcmp(watch->token, token)) {
600 free(watch->token);
601 *prev = watch->next;
602 free(watch);
603 break;
604 }
606 return NULL;
607 }
609 char *xenbus_rm(xenbus_transaction_t xbt, const char *path)
610 {
611 struct write_req req[] = { {path, strlen(path) + 1} };
612 struct xsd_sockmsg *rep;
613 char *msg;
614 rep = xenbus_msg_reply(XS_RM, xbt, req, ARRAY_SIZE(req));
615 msg = errmsg(rep);
616 if (msg)
617 return msg;
618 free(rep);
619 return NULL;
620 }
622 char *xenbus_get_perms(xenbus_transaction_t xbt, const char *path, char **value)
623 {
624 struct write_req req[] = { {path, strlen(path) + 1} };
625 struct xsd_sockmsg *rep;
626 char *res, *msg;
627 rep = xenbus_msg_reply(XS_GET_PERMS, xbt, req, ARRAY_SIZE(req));
628 msg = errmsg(rep);
629 if (msg) {
630 *value = NULL;
631 return msg;
632 }
633 res = malloc(rep->len + 1);
634 memcpy(res, rep + 1, rep->len);
635 res[rep->len] = 0;
636 free(rep);
637 *value = res;
638 return NULL;
639 }
641 #define PERM_MAX_SIZE 32
642 char *xenbus_set_perms(xenbus_transaction_t xbt, const char *path, domid_t dom, char perm)
643 {
644 char value[PERM_MAX_SIZE];
645 struct write_req req[] = {
646 {path, strlen(path) + 1},
647 {value, 0},
648 };
649 struct xsd_sockmsg *rep;
650 char *msg;
651 snprintf(value, PERM_MAX_SIZE, "%c%hu", perm, dom);
652 req[1].len = strlen(value) + 1;
653 rep = xenbus_msg_reply(XS_SET_PERMS, xbt, req, ARRAY_SIZE(req));
654 msg = errmsg(rep);
655 if (msg)
656 return msg;
657 free(rep);
658 return NULL;
659 }
661 char *xenbus_transaction_start(xenbus_transaction_t *xbt)
662 {
663 /* xenstored becomes angry if you send a length 0 message, so just
664 shove a nul terminator on the end */
665 struct write_req req = { "", 1};
666 struct xsd_sockmsg *rep;
667 char *err;
669 rep = xenbus_msg_reply(XS_TRANSACTION_START, 0, &req, 1);
670 err = errmsg(rep);
671 if (err)
672 return err;
673 sscanf((char *)(rep + 1), "%u", xbt);
674 free(rep);
675 return NULL;
676 }
678 char *
679 xenbus_transaction_end(xenbus_transaction_t t, int abort, int *retry)
680 {
681 struct xsd_sockmsg *rep;
682 struct write_req req;
683 char *err;
685 *retry = 0;
687 req.data = abort ? "F" : "T";
688 req.len = 2;
689 rep = xenbus_msg_reply(XS_TRANSACTION_END, t, &req, 1);
690 err = errmsg(rep);
691 if (err) {
692 if (!strcmp(err, "EAGAIN")) {
693 *retry = 1;
694 free(err);
695 return NULL;
696 } else {
697 return err;
698 }
699 }
700 free(rep);
701 return NULL;
702 }
704 int xenbus_read_integer(const char *path)
705 {
706 char *res, *buf;
707 int t;
709 res = xenbus_read(XBT_NIL, path, &buf);
710 if (res) {
711 printk("Failed to read %s.\n", path);
712 free(res);
713 return -1;
714 }
715 sscanf(buf, "%d", &t);
716 free(buf);
717 return t;
718 }
720 char* xenbus_printf(xenbus_transaction_t xbt,
721 const char* node, const char* path,
722 const char* fmt, ...)
723 {
724 #define BUFFER_SIZE 256
725 char fullpath[BUFFER_SIZE];
726 char val[BUFFER_SIZE];
727 va_list args;
729 BUG_ON(strlen(node) + strlen(path) + 1 >= BUFFER_SIZE);
730 sprintf(fullpath,"%s/%s", node, path);
731 va_start(args, fmt);
732 vsprintf(val, fmt, args);
733 va_end(args);
734 return xenbus_write(xbt,fullpath,val);
735 }
737 domid_t xenbus_get_self_id(void)
738 {
739 char *dom_id;
740 domid_t ret;
742 BUG_ON(xenbus_read(XBT_NIL, "domid", &dom_id));
743 sscanf(dom_id, "%d", &ret);
745 return ret;
746 }
748 static void do_ls_test(const char *pre)
749 {
750 char **dirs, *msg;
751 int x;
753 DEBUG("ls %s...\n", pre);
754 msg = xenbus_ls(XBT_NIL, pre, &dirs);
755 if (msg) {
756 DEBUG("Error in xenbus ls: %s\n", msg);
757 free(msg);
758 return;
759 }
760 for (x = 0; dirs[x]; x++)
761 {
762 DEBUG("ls %s[%d] -> %s\n", pre, x, dirs[x]);
763 free(dirs[x]);
764 }
765 free(dirs);
766 }
768 static void do_read_test(const char *path)
769 {
770 char *res, *msg;
771 DEBUG("Read %s...\n", path);
772 msg = xenbus_read(XBT_NIL, path, &res);
773 if (msg) {
774 DEBUG("Error in xenbus read: %s\n", msg);
775 free(msg);
776 return;
777 }
778 DEBUG("Read %s -> %s.\n", path, res);
779 free(res);
780 }
782 static void do_write_test(const char *path, const char *val)
783 {
784 char *msg;
785 DEBUG("Write %s to %s...\n", val, path);
786 msg = xenbus_write(XBT_NIL, path, val);
787 if (msg) {
788 DEBUG("Result %s\n", msg);
789 free(msg);
790 } else {
791 DEBUG("Success.\n");
792 }
793 }
795 static void do_rm_test(const char *path)
796 {
797 char *msg;
798 DEBUG("rm %s...\n", path);
799 msg = xenbus_rm(XBT_NIL, path);
800 if (msg) {
801 DEBUG("Result %s\n", msg);
802 free(msg);
803 } else {
804 DEBUG("Success.\n");
805 }
806 }
808 /* Simple testing thing */
809 void test_xenbus(void)
810 {
811 DEBUG("Doing xenbus test.\n");
812 xenbus_debug_msg("Testing xenbus...\n");
814 DEBUG("Doing ls test.\n");
815 do_ls_test("device");
816 do_ls_test("device/vif");
817 do_ls_test("device/vif/0");
819 DEBUG("Doing read test.\n");
820 do_read_test("device/vif/0/mac");
821 do_read_test("device/vif/0/backend");
823 DEBUG("Doing write test.\n");
824 do_write_test("device/vif/0/flibble", "flobble");
825 do_read_test("device/vif/0/flibble");
826 do_write_test("device/vif/0/flibble", "widget");
827 do_read_test("device/vif/0/flibble");
829 DEBUG("Doing rm test.\n");
830 do_rm_test("device/vif/0/flibble");
831 do_read_test("device/vif/0/flibble");
832 DEBUG("(Should have said ENOENT)\n");
833 }
835 /*
836 * Local variables:
837 * mode: C
838 * c-basic-offset: 4
839 * End:
840 */