ia64/xen-unstable

view extras/mini-os/xenbus/xenbus.c @ 16486:6fd17d0dcbcd

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