ia64/xen-unstable

view extras/mini-os/xenbus/xenbus.c @ 11584:a49f9c33aa93

[XM] Text wrapping fix, xm create --help_config fix.

* Fix text wrap so it doesn't chop off last word in help message for
certain cases.
* Fix handling of xm create --help_config
* Remove redundant gopts.usage() call.

Signed-off-by: Alastair Tse <atse@xensource.com>
author atse@norwich.uk.xensource.com
date Fri Sep 22 15:06:00 2006 +0100 (2006-09-22)
parents 98a802d25848
children 1fc8fb8ea425
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
49 static struct xenstore_domain_interface *xenstore_buf;
50 static DECLARE_WAIT_QUEUE_HEAD(xb_waitq);
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 void xenbus_thread_func(void *ign)
76 {
77 struct xsd_sockmsg msg;
78 unsigned prod;
80 for (;;)
81 {
82 wait_event(xb_waitq, prod != xenstore_buf->rsp_prod);
83 while (1)
84 {
85 prod = xenstore_buf->rsp_prod;
86 DEBUG("Rsp_cons %d, rsp_prod %d.\n", xenstore_buf->rsp_cons,
87 xenstore_buf->rsp_prod);
88 if (xenstore_buf->rsp_prod - xenstore_buf->rsp_cons < sizeof(msg))
89 break;
90 rmb();
91 memcpy_from_ring(xenstore_buf->rsp,
92 &msg,
93 MASK_XENSTORE_IDX(xenstore_buf->rsp_cons),
94 sizeof(msg));
95 DEBUG("Msg len %d, %d avail, id %d.\n",
96 msg.len + sizeof(msg),
97 xenstore_buf->rsp_prod - xenstore_buf->rsp_cons,
98 msg.req_id);
99 if (xenstore_buf->rsp_prod - xenstore_buf->rsp_cons <
100 sizeof(msg) + msg.len)
101 break;
103 DEBUG("Message is good.\n");
104 req_info[msg.req_id].reply = malloc(sizeof(msg) + msg.len);
105 memcpy_from_ring(xenstore_buf->rsp,
106 req_info[msg.req_id].reply,
107 MASK_XENSTORE_IDX(xenstore_buf->rsp_cons),
108 msg.len + sizeof(msg));
109 wake_up(&req_info[msg.req_id].waitq);
110 xenstore_buf->rsp_cons += msg.len + sizeof(msg);
111 }
112 }
113 }
115 static void xenbus_evtchn_handler(evtchn_port_t port, struct pt_regs *regs,
116 void *ign)
117 {
118 wake_up(&xb_waitq);
119 }
121 static int nr_live_reqs;
122 static spinlock_t req_lock = SPIN_LOCK_UNLOCKED;
123 static DECLARE_WAIT_QUEUE_HEAD(req_wq);
125 /* Release a xenbus identifier */
126 static void release_xenbus_id(int id)
127 {
128 BUG_ON(!req_info[id].in_use);
129 spin_lock(&req_lock);
130 nr_live_reqs--;
131 if (nr_live_reqs == NR_REQS - 1)
132 wake_up(&req_wq);
133 spin_unlock(&req_lock);
134 }
136 /* Allocate an identifier for a xenbus request. Blocks if none are
137 available. */
138 static int allocate_xenbus_id(void)
139 {
140 static int probe;
141 int o_probe;
143 while (1)
144 {
145 spin_lock(&req_lock);
146 if (nr_live_reqs < NR_REQS)
147 break;
148 spin_unlock(&req_lock);
149 wait_event(req_wq, (nr_live_reqs < NR_REQS));
150 }
152 o_probe = probe;
153 for (;;)
154 {
155 if (!req_info[o_probe].in_use)
156 break;
157 o_probe = (o_probe + 1) % NR_REQS;
158 BUG_ON(o_probe == probe);
159 }
160 nr_live_reqs++;
161 req_info[o_probe].in_use = 1;
162 probe = o_probe + 1;
163 spin_unlock(&req_lock);
164 init_waitqueue_head(&req_info[o_probe].waitq);
165 return o_probe;
166 }
168 /* Initialise xenbus. */
169 void init_xenbus(void)
170 {
171 int err;
172 printk("Initialising xenbus\n");
173 DEBUG("init_xenbus called.\n");
174 xenstore_buf = mfn_to_virt(start_info.store_mfn);
175 create_thread("xenstore", xenbus_thread_func, NULL);
176 DEBUG("buf at %p.\n", xenstore_buf);
177 err = bind_evtchn(start_info.store_evtchn,
178 xenbus_evtchn_handler,
179 NULL);
180 DEBUG("xenbus on irq %d\n", err);
181 }
183 struct write_req {
184 const void *data;
185 unsigned len;
186 };
188 /* Send data to xenbus. This can block. All of the requests are seen
189 by xenbus as if sent atomically. The header is added
190 automatically, using type %type, req_id %req_id, and trans_id
191 %trans_id. */
192 static void xb_write(int type, int req_id, xenbus_transaction_t trans_id,
193 const struct write_req *req, int nr_reqs)
194 {
195 XENSTORE_RING_IDX prod;
196 int r;
197 int len = 0;
198 const struct write_req *cur_req;
199 int req_off;
200 int total_off;
201 int this_chunk;
202 struct xsd_sockmsg m = {.type = type, .req_id = req_id,
203 .tx_id = trans_id };
204 struct write_req header_req = { &m, sizeof(m) };
206 for (r = 0; r < nr_reqs; r++)
207 len += req[r].len;
208 m.len = len;
209 len += sizeof(m);
211 cur_req = &header_req;
213 BUG_ON(len > XENSTORE_RING_SIZE);
214 /* Wait for the ring to drain to the point where we can send the
215 message. */
216 prod = xenstore_buf->req_prod;
217 if (prod + len - xenstore_buf->req_cons > XENSTORE_RING_SIZE)
218 {
219 /* Wait for there to be space on the ring */
220 DEBUG("prod %d, len %d, cons %d, size %d; waiting.\n",
221 prod, len, xenstore_buf->req_cons, XENSTORE_RING_SIZE);
222 wait_event(xb_waitq,
223 xenstore_buf->req_prod + len - xenstore_buf->req_cons <=
224 XENSTORE_RING_SIZE);
225 DEBUG("Back from wait.\n");
226 prod = xenstore_buf->req_prod;
227 }
229 /* We're now guaranteed to be able to send the message without
230 overflowing the ring. Do so. */
231 total_off = 0;
232 req_off = 0;
233 while (total_off < len)
234 {
235 this_chunk = min(cur_req->len - req_off,
236 XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod));
237 memcpy((char *)xenstore_buf->req + MASK_XENSTORE_IDX(prod),
238 (char *)cur_req->data + req_off, this_chunk);
239 prod += this_chunk;
240 req_off += this_chunk;
241 total_off += this_chunk;
242 if (req_off == cur_req->len)
243 {
244 req_off = 0;
245 if (cur_req == &header_req)
246 cur_req = req;
247 else
248 cur_req++;
249 }
250 }
252 DEBUG("Complete main loop of xb_write.\n");
253 BUG_ON(req_off != 0);
254 BUG_ON(total_off != len);
255 BUG_ON(prod > xenstore_buf->req_cons + XENSTORE_RING_SIZE);
257 /* Remote must see entire message before updating indexes */
258 wmb();
260 xenstore_buf->req_prod += len;
262 /* Send evtchn to notify remote */
263 notify_remote_via_evtchn(start_info.store_evtchn);
264 }
266 /* Send a mesasge to xenbus, in the same fashion as xb_write, and
267 block waiting for a reply. The reply is malloced and should be
268 freed by the caller. */
269 static struct xsd_sockmsg *
270 xenbus_msg_reply(int type,
271 xenbus_transaction_t trans,
272 struct write_req *io,
273 int nr_reqs)
274 {
275 int id;
276 DEFINE_WAIT(w);
277 struct xsd_sockmsg *rep;
279 id = allocate_xenbus_id();
280 add_waiter(w, req_info[id].waitq);
282 xb_write(type, id, trans, io, nr_reqs);
284 schedule();
285 wake(current);
287 rep = req_info[id].reply;
288 BUG_ON(rep->req_id != id);
289 release_xenbus_id(id);
290 return rep;
291 }
293 static char *errmsg(struct xsd_sockmsg *rep)
294 {
295 if (!rep) {
296 char msg[] = "No reply";
297 size_t len = strlen(msg) + 1;
298 return memcpy(malloc(len), msg, len);
299 }
300 if (rep->type != XS_ERROR)
301 return NULL;
302 char *res = malloc(rep->len + 1);
303 memcpy(res, rep + 1, rep->len);
304 res[rep->len] = 0;
305 free(rep);
306 return res;
307 }
309 /* Send a debug message to xenbus. Can block. */
310 static void xenbus_debug_msg(const char *msg)
311 {
312 int len = strlen(msg);
313 struct write_req req[] = {
314 { "print", sizeof("print") },
315 { msg, len },
316 { "", 1 }};
317 struct xsd_sockmsg *reply;
319 reply = xenbus_msg_reply(XS_DEBUG, 0, req, ARRAY_SIZE(req));
320 DEBUG("Got a reply, type %d, id %d, len %d.\n",
321 reply->type, reply->req_id, reply->len);
322 }
324 /* List the contents of a directory. Returns a malloc()ed array of
325 pointers to malloc()ed strings. The array is NULL terminated. May
326 block. */
327 char *xenbus_ls(xenbus_transaction_t xbt, const char *pre, char ***contents)
328 {
329 struct xsd_sockmsg *reply, *repmsg;
330 struct write_req req[] = { { pre, strlen(pre)+1 } };
331 int nr_elems, x, i;
332 char **res;
334 repmsg = xenbus_msg_reply(XS_DIRECTORY, xbt, req, ARRAY_SIZE(req));
335 char *msg = errmsg(repmsg);
336 if (msg) {
337 *contents = NULL;
338 return msg;
339 }
340 reply = repmsg + 1;
341 for (x = nr_elems = 0; x < repmsg->len; x++)
342 nr_elems += (((char *)reply)[x] == 0);
343 res = malloc(sizeof(res[0]) * (nr_elems + 1));
344 for (x = i = 0; i < nr_elems; i++) {
345 int l = strlen((char *)reply + x);
346 res[i] = malloc(l + 1);
347 memcpy(res[i], (char *)reply + x, l + 1);
348 x += l + 1;
349 }
350 res[i] = NULL;
351 free(repmsg);
352 *contents = res;
353 return NULL;
354 }
356 char *xenbus_read(xenbus_transaction_t xbt, const char *path, char **value)
357 {
358 struct write_req req[] = { {path, strlen(path) + 1} };
359 struct xsd_sockmsg *rep;
360 char *res;
361 rep = xenbus_msg_reply(XS_READ, xbt, req, ARRAY_SIZE(req));
362 char *msg = errmsg(rep);
363 if (msg) {
364 *value = NULL;
365 return msg;
366 }
367 res = malloc(rep->len + 1);
368 memcpy(res, rep + 1, rep->len);
369 res[rep->len] = 0;
370 free(rep);
371 *value = res;
372 return NULL;
373 }
375 char *xenbus_write(xenbus_transaction_t xbt, const char *path, const char *value)
376 {
377 struct write_req req[] = {
378 {path, strlen(path) + 1},
379 {value, strlen(value) + 1},
380 };
381 struct xsd_sockmsg *rep;
382 rep = xenbus_msg_reply(XS_WRITE, xbt, req, ARRAY_SIZE(req));
383 char *msg = errmsg(rep);
384 if (msg)
385 return msg;
386 free(rep);
387 return NULL;
388 }
390 char *xenbus_rm(xenbus_transaction_t xbt, const char *path)
391 {
392 struct write_req req[] = { {path, strlen(path) + 1} };
393 struct xsd_sockmsg *rep;
394 rep = xenbus_msg_reply(XS_RM, xbt, req, ARRAY_SIZE(req));
395 char *msg = errmsg(rep);
396 if (msg)
397 return msg;
398 free(rep);
399 return NULL;
400 }
402 char *xenbus_get_perms(xenbus_transaction_t xbt, const char *path, char **value)
403 {
404 struct write_req req[] = { {path, strlen(path) + 1} };
405 struct xsd_sockmsg *rep;
406 char *res;
407 rep = xenbus_msg_reply(XS_GET_PERMS, xbt, req, ARRAY_SIZE(req));
408 char *msg = errmsg(rep);
409 if (msg) {
410 *value = NULL;
411 return msg;
412 }
413 res = malloc(rep->len + 1);
414 memcpy(res, rep + 1, rep->len);
415 res[rep->len] = 0;
416 free(rep);
417 *value = res;
418 return NULL;
419 }
421 #define PERM_MAX_SIZE 32
422 char *xenbus_set_perms(xenbus_transaction_t xbt, const char *path, domid_t dom, char perm)
423 {
424 char value[PERM_MAX_SIZE];
425 snprintf(value, PERM_MAX_SIZE, "%c%hu", perm, dom);
426 struct write_req req[] = {
427 {path, strlen(path) + 1},
428 {value, strlen(value) + 1},
429 };
430 struct xsd_sockmsg *rep;
431 rep = xenbus_msg_reply(XS_SET_PERMS, xbt, req, ARRAY_SIZE(req));
432 char *msg = errmsg(rep);
433 if (msg)
434 return msg;
435 free(rep);
436 return NULL;
437 }
439 char *xenbus_transaction_start(xenbus_transaction_t *xbt)
440 {
441 /* xenstored becomes angry if you send a length 0 message, so just
442 shove a nul terminator on the end */
443 struct write_req req = { "", 1};
444 struct xsd_sockmsg *rep;
445 char *err;
447 rep = xenbus_msg_reply(XS_TRANSACTION_START, 0, &req, 1);
448 err = errmsg(rep);
449 if (err)
450 return err;
451 sscanf((char *)(rep + 1), "%u", xbt);
452 free(rep);
453 return NULL;
454 }
456 char *
457 xenbus_transaction_end(xenbus_transaction_t t, int abort, int *retry)
458 {
459 struct xsd_sockmsg *rep;
460 struct write_req req;
461 char *err;
463 *retry = 0;
465 req.data = abort ? "F" : "T";
466 req.len = 2;
467 rep = xenbus_msg_reply(XS_TRANSACTION_END, t, &req, 1);
468 err = errmsg(rep);
469 if (err) {
470 if (!strcmp(err, "EAGAIN")) {
471 *retry = 1;
472 free(err);
473 return NULL;
474 } else {
475 return err;
476 }
477 }
478 free(rep);
479 return NULL;
480 }
482 int xenbus_read_integer(char *path)
483 {
484 char *res, *buf;
485 int t;
487 res = xenbus_read(XBT_NIL, path, &buf);
488 if (res) {
489 printk("Failed to read %s.\n", path);
490 free(res);
491 return -1;
492 }
493 sscanf(buf, "%d", &t);
494 free(buf);
495 return t;
496 }
498 static void do_ls_test(const char *pre)
499 {
500 char **dirs;
501 int x;
503 DEBUG("ls %s...\n", pre);
504 char *msg = xenbus_ls(XBT_NIL, pre, &dirs);
505 if (msg) {
506 DEBUG("Error in xenbus ls: %s\n", msg);
507 free(msg);
508 return;
509 }
510 for (x = 0; dirs[x]; x++)
511 {
512 DEBUG("ls %s[%d] -> %s\n", pre, x, dirs[x]);
513 free(dirs[x]);
514 }
515 free(dirs);
516 }
518 static void do_read_test(const char *path)
519 {
520 char *res;
521 DEBUG("Read %s...\n", path);
522 char *msg = xenbus_read(XBT_NIL, path, &res);
523 if (msg) {
524 DEBUG("Error in xenbus read: %s\n", msg);
525 free(msg);
526 return;
527 }
528 DEBUG("Read %s -> %s.\n", path, res);
529 free(res);
530 }
532 static void do_write_test(const char *path, const char *val)
533 {
534 DEBUG("Write %s to %s...\n", val, path);
535 char *msg = xenbus_write(XBT_NIL, path, val);
536 if (msg) {
537 DEBUG("Result %s\n", msg);
538 free(msg);
539 } else {
540 DEBUG("Success.\n");
541 }
542 }
544 static void do_rm_test(const char *path)
545 {
546 DEBUG("rm %s...\n", path);
547 char *msg = xenbus_rm(XBT_NIL, path);
548 if (msg) {
549 DEBUG("Result %s\n", msg);
550 free(msg);
551 } else {
552 DEBUG("Success.\n");
553 }
554 }
556 /* Simple testing thing */
557 void test_xenbus(void)
558 {
559 DEBUG("Doing xenbus test.\n");
560 xenbus_debug_msg("Testing xenbus...\n");
562 DEBUG("Doing ls test.\n");
563 do_ls_test("device");
564 do_ls_test("device/vif");
565 do_ls_test("device/vif/0");
567 DEBUG("Doing read test.\n");
568 do_read_test("device/vif/0/mac");
569 do_read_test("device/vif/0/backend");
571 DEBUG("Doing write test.\n");
572 do_write_test("device/vif/0/flibble", "flobble");
573 do_read_test("device/vif/0/flibble");
574 do_write_test("device/vif/0/flibble", "widget");
575 do_read_test("device/vif/0/flibble");
577 DEBUG("Doing rm test.\n");
578 do_rm_test("device/vif/0/flibble");
579 do_read_test("device/vif/0/flibble");
580 DEBUG("(Should have said ENOENT)\n");
581 }
583 /*
584 * Local variables:
585 * mode: C
586 * c-basic-offset: 4
587 * End:
588 */