ia64/xen-unstable

view extras/mini-os/xenbus/xenbus.c @ 14006:ee6e484403a9

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