debuggers.hg

view extras/mini-os/xenbus/xenbus.c @ 16771:10101bc8181f

minios: use ASSERT for BUG_ON

Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jan 17 14:40:23 2008 +0000 (2008-01-17)
parents 6fd17d0dcbcd
children 76d88d1da324
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 static DECLARE_WAIT_QUEUE_HEAD(watch_queue);
47 struct xenbus_req_info
48 {
49 int in_use:1;
50 struct wait_queue_head waitq;
51 void *reply;
52 };
54 #define NR_REQS 32
55 static struct xenbus_req_info req_info[NR_REQS];
57 static void memcpy_from_ring(const void *Ring,
58 void *Dest,
59 int off,
60 int len)
61 {
62 int c1, c2;
63 const char *ring = Ring;
64 char *dest = Dest;
65 c1 = min(len, XENSTORE_RING_SIZE - off);
66 c2 = len - c1;
67 memcpy(dest, ring + off, c1);
68 memcpy(dest + c1, ring, c2);
69 }
71 void wait_for_watch(void)
72 {
73 DEFINE_WAIT(w);
74 add_waiter(w,watch_queue);
75 schedule();
76 remove_waiter(w);
77 wake(current);
78 }
80 char* xenbus_wait_for_value(const char* path,const char* value)
81 {
82 for(;;)
83 {
84 char *res, *msg;
85 int r;
87 msg = xenbus_read(XBT_NIL, path, &res);
88 if(msg) return msg;
90 r = strcmp(value,res);
91 free(res);
93 if(r==0) break;
94 else wait_for_watch();
95 }
96 return NULL;
97 }
100 static void xenbus_thread_func(void *ign)
101 {
102 struct xsd_sockmsg msg;
103 unsigned prod = 0;
105 for (;;)
106 {
107 wait_event(xb_waitq, prod != xenstore_buf->rsp_prod);
108 while (1)
109 {
110 prod = xenstore_buf->rsp_prod;
111 DEBUG("Rsp_cons %d, rsp_prod %d.\n", xenstore_buf->rsp_cons,
112 xenstore_buf->rsp_prod);
113 if (xenstore_buf->rsp_prod - xenstore_buf->rsp_cons < sizeof(msg))
114 break;
115 rmb();
116 memcpy_from_ring(xenstore_buf->rsp,
117 &msg,
118 MASK_XENSTORE_IDX(xenstore_buf->rsp_cons),
119 sizeof(msg));
120 DEBUG("Msg len %d, %d avail, id %d.\n",
121 msg.len + sizeof(msg),
122 xenstore_buf->rsp_prod - xenstore_buf->rsp_cons,
123 msg.req_id);
124 if (xenstore_buf->rsp_prod - xenstore_buf->rsp_cons <
125 sizeof(msg) + msg.len)
126 break;
128 DEBUG("Message is good.\n");
130 if(msg.type == XS_WATCH_EVENT)
131 {
132 char* payload = (char*)malloc(sizeof(msg) + msg.len);
133 char *path,*token;
135 memcpy_from_ring(xenstore_buf->rsp,
136 payload,
137 MASK_XENSTORE_IDX(xenstore_buf->rsp_cons),
138 msg.len + sizeof(msg));
140 path = payload + sizeof(msg);
141 token = path + strlen(path) + 1;
143 xenstore_buf->rsp_cons += msg.len + sizeof(msg);
144 free(payload);
145 wake_up(&watch_queue);
146 }
148 else
149 {
150 req_info[msg.req_id].reply = malloc(sizeof(msg) + msg.len);
151 memcpy_from_ring(xenstore_buf->rsp,
152 req_info[msg.req_id].reply,
153 MASK_XENSTORE_IDX(xenstore_buf->rsp_cons),
154 msg.len + sizeof(msg));
155 xenstore_buf->rsp_cons += msg.len + sizeof(msg);
156 wake_up(&req_info[msg.req_id].waitq);
157 }
158 }
159 }
160 }
162 static void xenbus_evtchn_handler(evtchn_port_t port, struct pt_regs *regs,
163 void *ign)
164 {
165 wake_up(&xb_waitq);
166 }
168 static int nr_live_reqs;
169 static spinlock_t req_lock = SPIN_LOCK_UNLOCKED;
170 static DECLARE_WAIT_QUEUE_HEAD(req_wq);
172 /* Release a xenbus identifier */
173 static void release_xenbus_id(int id)
174 {
175 BUG_ON(!req_info[id].in_use);
176 spin_lock(&req_lock);
177 req_info[id].in_use = 0;
178 nr_live_reqs--;
179 req_info[id].in_use = 0;
180 if (nr_live_reqs == NR_REQS - 1)
181 wake_up(&req_wq);
182 spin_unlock(&req_lock);
183 }
185 /* Allocate an identifier for a xenbus request. Blocks if none are
186 available. */
187 static int allocate_xenbus_id(void)
188 {
189 static int probe;
190 int o_probe;
192 while (1)
193 {
194 spin_lock(&req_lock);
195 if (nr_live_reqs < NR_REQS)
196 break;
197 spin_unlock(&req_lock);
198 wait_event(req_wq, (nr_live_reqs < NR_REQS));
199 }
201 o_probe = probe;
202 for (;;)
203 {
204 if (!req_info[o_probe].in_use)
205 break;
206 o_probe = (o_probe + 1) % NR_REQS;
207 BUG_ON(o_probe == probe);
208 }
209 nr_live_reqs++;
210 req_info[o_probe].in_use = 1;
211 probe = (o_probe + 1) % NR_REQS;
212 spin_unlock(&req_lock);
213 init_waitqueue_head(&req_info[o_probe].waitq);
215 return o_probe;
216 }
218 /* Initialise xenbus. */
219 void init_xenbus(void)
220 {
221 int err;
222 printk("Initialising xenbus\n");
223 DEBUG("init_xenbus called.\n");
224 xenstore_buf = mfn_to_virt(start_info.store_mfn);
225 create_thread("xenstore", xenbus_thread_func, NULL);
226 DEBUG("buf at %p.\n", xenstore_buf);
227 err = bind_evtchn(start_info.store_evtchn,
228 xenbus_evtchn_handler,
229 NULL);
230 DEBUG("xenbus on irq %d\n", err);
231 }
233 struct write_req {
234 const void *data;
235 unsigned len;
236 };
238 /* Send data to xenbus. This can block. All of the requests are seen
239 by xenbus as if sent atomically. The header is added
240 automatically, using type %type, req_id %req_id, and trans_id
241 %trans_id. */
242 static void xb_write(int type, int req_id, xenbus_transaction_t trans_id,
243 const struct write_req *req, int nr_reqs)
244 {
245 XENSTORE_RING_IDX prod;
246 int r;
247 int len = 0;
248 const struct write_req *cur_req;
249 int req_off;
250 int total_off;
251 int this_chunk;
252 struct xsd_sockmsg m = {.type = type, .req_id = req_id,
253 .tx_id = trans_id };
254 struct write_req header_req = { &m, sizeof(m) };
256 for (r = 0; r < nr_reqs; r++)
257 len += req[r].len;
258 m.len = len;
259 len += sizeof(m);
261 cur_req = &header_req;
263 BUG_ON(len > XENSTORE_RING_SIZE);
264 /* Wait for the ring to drain to the point where we can send the
265 message. */
266 prod = xenstore_buf->req_prod;
267 if (prod + len - xenstore_buf->req_cons > XENSTORE_RING_SIZE)
268 {
269 /* Wait for there to be space on the ring */
270 DEBUG("prod %d, len %d, cons %d, size %d; waiting.\n",
271 prod, len, xenstore_buf->req_cons, XENSTORE_RING_SIZE);
272 wait_event(xb_waitq,
273 xenstore_buf->req_prod + len - xenstore_buf->req_cons <=
274 XENSTORE_RING_SIZE);
275 DEBUG("Back from wait.\n");
276 prod = xenstore_buf->req_prod;
277 }
279 /* We're now guaranteed to be able to send the message without
280 overflowing the ring. Do so. */
281 total_off = 0;
282 req_off = 0;
283 while (total_off < len)
284 {
285 this_chunk = min(cur_req->len - req_off,
286 XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod));
287 memcpy((char *)xenstore_buf->req + MASK_XENSTORE_IDX(prod),
288 (char *)cur_req->data + req_off, this_chunk);
289 prod += this_chunk;
290 req_off += this_chunk;
291 total_off += this_chunk;
292 if (req_off == cur_req->len)
293 {
294 req_off = 0;
295 if (cur_req == &header_req)
296 cur_req = req;
297 else
298 cur_req++;
299 }
300 }
302 DEBUG("Complete main loop of xb_write.\n");
303 BUG_ON(req_off != 0);
304 BUG_ON(total_off != len);
305 BUG_ON(prod > xenstore_buf->req_cons + XENSTORE_RING_SIZE);
307 /* Remote must see entire message before updating indexes */
308 wmb();
310 xenstore_buf->req_prod += len;
312 /* Send evtchn to notify remote */
313 notify_remote_via_evtchn(start_info.store_evtchn);
314 }
316 /* Send a mesasge to xenbus, in the same fashion as xb_write, and
317 block waiting for a reply. The reply is malloced and should be
318 freed by the caller. */
319 static struct xsd_sockmsg *
320 xenbus_msg_reply(int type,
321 xenbus_transaction_t trans,
322 struct write_req *io,
323 int nr_reqs)
324 {
325 int id;
326 DEFINE_WAIT(w);
327 struct xsd_sockmsg *rep;
329 id = allocate_xenbus_id();
330 add_waiter(w, req_info[id].waitq);
332 xb_write(type, id, trans, io, nr_reqs);
334 schedule();
335 remove_waiter(w);
336 wake(current);
338 rep = req_info[id].reply;
339 BUG_ON(rep->req_id != id);
340 release_xenbus_id(id);
341 return rep;
342 }
344 static char *errmsg(struct xsd_sockmsg *rep)
345 {
346 if (!rep) {
347 char msg[] = "No reply";
348 size_t len = strlen(msg) + 1;
349 return memcpy(malloc(len), msg, len);
350 }
351 if (rep->type != XS_ERROR)
352 return NULL;
353 char *res = malloc(rep->len + 1);
354 memcpy(res, rep + 1, rep->len);
355 res[rep->len] = 0;
356 free(rep);
357 return res;
358 }
360 /* Send a debug message to xenbus. Can block. */
361 static void xenbus_debug_msg(const char *msg)
362 {
363 int len = strlen(msg);
364 struct write_req req[] = {
365 { "print", sizeof("print") },
366 { msg, len },
367 { "", 1 }};
368 struct xsd_sockmsg *reply;
370 reply = xenbus_msg_reply(XS_DEBUG, 0, req, ARRAY_SIZE(req));
371 DEBUG("Got a reply, type %d, id %d, len %d.\n",
372 reply->type, reply->req_id, reply->len);
373 }
375 /* List the contents of a directory. Returns a malloc()ed array of
376 pointers to malloc()ed strings. The array is NULL terminated. May
377 block. */
378 char *xenbus_ls(xenbus_transaction_t xbt, const char *pre, char ***contents)
379 {
380 struct xsd_sockmsg *reply, *repmsg;
381 struct write_req req[] = { { pre, strlen(pre)+1 } };
382 int nr_elems, x, i;
383 char **res;
385 repmsg = xenbus_msg_reply(XS_DIRECTORY, xbt, req, ARRAY_SIZE(req));
386 char *msg = errmsg(repmsg);
387 if (msg) {
388 *contents = NULL;
389 return msg;
390 }
391 reply = repmsg + 1;
392 for (x = nr_elems = 0; x < repmsg->len; x++)
393 nr_elems += (((char *)reply)[x] == 0);
394 res = malloc(sizeof(res[0]) * (nr_elems + 1));
395 for (x = i = 0; i < nr_elems; i++) {
396 int l = strlen((char *)reply + x);
397 res[i] = malloc(l + 1);
398 memcpy(res[i], (char *)reply + x, l + 1);
399 x += l + 1;
400 }
401 res[i] = NULL;
402 free(repmsg);
403 *contents = res;
404 return NULL;
405 }
407 char *xenbus_read(xenbus_transaction_t xbt, const char *path, char **value)
408 {
409 struct write_req req[] = { {path, strlen(path) + 1} };
410 struct xsd_sockmsg *rep;
411 char *res;
412 rep = xenbus_msg_reply(XS_READ, xbt, req, ARRAY_SIZE(req));
413 char *msg = errmsg(rep);
414 if (msg) {
415 *value = NULL;
416 return msg;
417 }
418 res = malloc(rep->len + 1);
419 memcpy(res, rep + 1, rep->len);
420 res[rep->len] = 0;
421 free(rep);
422 *value = res;
423 return NULL;
424 }
426 char *xenbus_write(xenbus_transaction_t xbt, const char *path, const char *value)
427 {
428 struct write_req req[] = {
429 {path, strlen(path) + 1},
430 {value, strlen(value) + 1},
431 };
432 struct xsd_sockmsg *rep;
433 rep = xenbus_msg_reply(XS_WRITE, xbt, req, ARRAY_SIZE(req));
434 char *msg = errmsg(rep);
435 if (msg) return msg;
436 free(rep);
437 return NULL;
438 }
440 char* xenbus_watch_path( xenbus_transaction_t xbt, const char *path)
441 {
442 /* in the future one could have multiple watch queues, and use
443 * the token for demuxing. For now the token is 0. */
445 struct xsd_sockmsg *rep;
447 struct write_req req[] = {
448 {path, strlen(path) + 1},
449 {"0",2 },
450 };
452 rep = xenbus_msg_reply(XS_WATCH, xbt, req, ARRAY_SIZE(req));
454 char *msg = errmsg(rep);
455 if (msg) return msg;
456 free(rep);
458 return NULL;
459 }
461 char *xenbus_rm(xenbus_transaction_t xbt, const char *path)
462 {
463 struct write_req req[] = { {path, strlen(path) + 1} };
464 struct xsd_sockmsg *rep;
465 rep = xenbus_msg_reply(XS_RM, xbt, req, ARRAY_SIZE(req));
466 char *msg = errmsg(rep);
467 if (msg)
468 return msg;
469 free(rep);
470 return NULL;
471 }
473 char *xenbus_get_perms(xenbus_transaction_t xbt, const char *path, char **value)
474 {
475 struct write_req req[] = { {path, strlen(path) + 1} };
476 struct xsd_sockmsg *rep;
477 char *res;
478 rep = xenbus_msg_reply(XS_GET_PERMS, xbt, req, ARRAY_SIZE(req));
479 char *msg = errmsg(rep);
480 if (msg) {
481 *value = NULL;
482 return msg;
483 }
484 res = malloc(rep->len + 1);
485 memcpy(res, rep + 1, rep->len);
486 res[rep->len] = 0;
487 free(rep);
488 *value = res;
489 return NULL;
490 }
492 #define PERM_MAX_SIZE 32
493 char *xenbus_set_perms(xenbus_transaction_t xbt, const char *path, domid_t dom, char perm)
494 {
495 char value[PERM_MAX_SIZE];
496 snprintf(value, PERM_MAX_SIZE, "%c%hu", perm, dom);
497 struct write_req req[] = {
498 {path, strlen(path) + 1},
499 {value, strlen(value) + 1},
500 };
501 struct xsd_sockmsg *rep;
502 rep = xenbus_msg_reply(XS_SET_PERMS, xbt, req, ARRAY_SIZE(req));
503 char *msg = errmsg(rep);
504 if (msg)
505 return msg;
506 free(rep);
507 return NULL;
508 }
510 char *xenbus_transaction_start(xenbus_transaction_t *xbt)
511 {
512 /* xenstored becomes angry if you send a length 0 message, so just
513 shove a nul terminator on the end */
514 struct write_req req = { "", 1};
515 struct xsd_sockmsg *rep;
516 char *err;
518 rep = xenbus_msg_reply(XS_TRANSACTION_START, 0, &req, 1);
519 err = errmsg(rep);
520 if (err)
521 return err;
522 sscanf((char *)(rep + 1), "%u", xbt);
523 free(rep);
524 return NULL;
525 }
527 char *
528 xenbus_transaction_end(xenbus_transaction_t t, int abort, int *retry)
529 {
530 struct xsd_sockmsg *rep;
531 struct write_req req;
532 char *err;
534 *retry = 0;
536 req.data = abort ? "F" : "T";
537 req.len = 2;
538 rep = xenbus_msg_reply(XS_TRANSACTION_END, t, &req, 1);
539 err = errmsg(rep);
540 if (err) {
541 if (!strcmp(err, "EAGAIN")) {
542 *retry = 1;
543 free(err);
544 return NULL;
545 } else {
546 return err;
547 }
548 }
549 free(rep);
550 return NULL;
551 }
553 int xenbus_read_integer(char *path)
554 {
555 char *res, *buf;
556 int t;
558 res = xenbus_read(XBT_NIL, path, &buf);
559 if (res) {
560 printk("Failed to read %s.\n", path);
561 free(res);
562 return -1;
563 }
564 sscanf(buf, "%d", &t);
565 free(buf);
566 return t;
567 }
569 static void do_ls_test(const char *pre)
570 {
571 char **dirs;
572 int x;
574 DEBUG("ls %s...\n", pre);
575 char *msg = xenbus_ls(XBT_NIL, pre, &dirs);
576 if (msg) {
577 DEBUG("Error in xenbus ls: %s\n", msg);
578 free(msg);
579 return;
580 }
581 for (x = 0; dirs[x]; x++)
582 {
583 DEBUG("ls %s[%d] -> %s\n", pre, x, dirs[x]);
584 free(dirs[x]);
585 }
586 free(dirs);
587 }
589 static void do_read_test(const char *path)
590 {
591 char *res;
592 DEBUG("Read %s...\n", path);
593 char *msg = xenbus_read(XBT_NIL, path, &res);
594 if (msg) {
595 DEBUG("Error in xenbus read: %s\n", msg);
596 free(msg);
597 return;
598 }
599 DEBUG("Read %s -> %s.\n", path, res);
600 free(res);
601 }
603 static void do_write_test(const char *path, const char *val)
604 {
605 DEBUG("Write %s to %s...\n", val, path);
606 char *msg = xenbus_write(XBT_NIL, path, val);
607 if (msg) {
608 DEBUG("Result %s\n", msg);
609 free(msg);
610 } else {
611 DEBUG("Success.\n");
612 }
613 }
615 static void do_rm_test(const char *path)
616 {
617 DEBUG("rm %s...\n", path);
618 char *msg = xenbus_rm(XBT_NIL, path);
619 if (msg) {
620 DEBUG("Result %s\n", msg);
621 free(msg);
622 } else {
623 DEBUG("Success.\n");
624 }
625 }
627 /* Simple testing thing */
628 void test_xenbus(void)
629 {
630 DEBUG("Doing xenbus test.\n");
631 xenbus_debug_msg("Testing xenbus...\n");
633 DEBUG("Doing ls test.\n");
634 do_ls_test("device");
635 do_ls_test("device/vif");
636 do_ls_test("device/vif/0");
638 DEBUG("Doing read test.\n");
639 do_read_test("device/vif/0/mac");
640 do_read_test("device/vif/0/backend");
642 DEBUG("Doing write test.\n");
643 do_write_test("device/vif/0/flibble", "flobble");
644 do_read_test("device/vif/0/flibble");
645 do_write_test("device/vif/0/flibble", "widget");
646 do_read_test("device/vif/0/flibble");
648 DEBUG("Doing rm test.\n");
649 do_rm_test("device/vif/0/flibble");
650 do_read_test("device/vif/0/flibble");
651 DEBUG("(Should have said ENOENT)\n");
652 }
654 /*
655 * Local variables:
656 * mode: C
657 * c-basic-offset: 4
658 * End:
659 */