direct-io.hg

view extras/mini-os/xenbus/xenbus.c @ 10338:e9dd58963e97

Expand test_xenbus a little.

Signed-off-by: Steven Smith <sos22@cam.ac.uk>
author sos22@douglas.cl.cam.ac.uk
date Tue Jun 13 15:19:09 2006 +0100 (2006-06-13)
parents 464324585311
children fed18f971f72
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(int port, struct pt_regs *regs)
116 {
117 wake_up(&xb_waitq);
118 }
120 static int nr_live_reqs;
121 static spinlock_t req_lock = SPIN_LOCK_UNLOCKED;
122 static DECLARE_WAIT_QUEUE_HEAD(req_wq);
124 /* Release a xenbus identifier */
125 static void release_xenbus_id(int id)
126 {
127 BUG_ON(!req_info[id].in_use);
128 spin_lock(&req_lock);
129 nr_live_reqs--;
130 if (nr_live_reqs == NR_REQS - 1)
131 wake_up(&req_wq);
132 spin_unlock(&req_lock);
133 }
135 /* Allocate an identifier for a xenbus request. Blocks if none are
136 available. */
137 static int allocate_xenbus_id(void)
138 {
139 static int probe;
140 int o_probe;
142 while (1)
143 {
144 spin_lock(&req_lock);
145 if (nr_live_reqs < NR_REQS)
146 break;
147 spin_unlock(&req_lock);
148 wait_event(req_wq, (nr_live_reqs < NR_REQS));
149 }
151 o_probe = probe;
152 for (;;)
153 {
154 if (!req_info[o_probe].in_use)
155 break;
156 o_probe = (o_probe + 1) % NR_REQS;
157 BUG_ON(o_probe == probe);
158 }
159 nr_live_reqs++;
160 req_info[o_probe].in_use = 1;
161 probe = o_probe + 1;
162 spin_unlock(&req_lock);
163 init_waitqueue_head(&req_info[o_probe].waitq);
164 return o_probe;
165 }
167 /* Initialise xenbus. */
168 void init_xenbus(void)
169 {
170 int err;
171 printk("Initialising xenbus\n");
172 DEBUG("init_xenbus called.\n");
173 xenstore_buf = mfn_to_virt(start_info.store_mfn);
174 create_thread("xenstore", xenbus_thread_func, NULL);
175 DEBUG("buf at %p.\n", xenstore_buf);
176 err = bind_evtchn(start_info.store_evtchn,
177 xenbus_evtchn_handler);
178 DEBUG("xenbus on irq %d\n", err);
179 }
181 struct write_req {
182 const void *data;
183 unsigned len;
184 };
186 /* Send data to xenbus. This can block. All of the requests are seen
187 by xenbus as if sent atomically. The header is added
188 automatically, using type %type, req_id %req_id, and trans_id
189 %trans_id. */
190 static void xb_write(int type, int req_id, int trans_id,
191 const struct write_req *req, int nr_reqs)
192 {
193 XENSTORE_RING_IDX prod;
194 int r;
195 int len = 0;
196 const struct write_req *cur_req;
197 int req_off;
198 int total_off;
199 int this_chunk;
200 struct xsd_sockmsg m = {.type = type, .req_id = req_id,
201 .tx_id = trans_id };
202 struct write_req header_req = { &m, sizeof(m) };
204 for (r = 0; r < nr_reqs; r++)
205 len += req[r].len;
206 m.len = len;
207 len += sizeof(m);
209 cur_req = &header_req;
211 BUG_ON(len > XENSTORE_RING_SIZE);
212 /* Wait for the ring to drain to the point where we can send the
213 message. */
214 prod = xenstore_buf->req_prod;
215 if (prod + len - xenstore_buf->req_cons > XENSTORE_RING_SIZE)
216 {
217 /* Wait for there to be space on the ring */
218 DEBUG("prod %d, len %d, cons %d, size %d; waiting.\n",
219 prod, len, xenstore_buf->req_cons, XENSTORE_RING_SIZE);
220 wait_event(xb_waitq,
221 xenstore_buf->req_prod + len - xenstore_buf->req_cons <=
222 XENSTORE_RING_SIZE);
223 DEBUG("Back from wait.\n");
224 prod = xenstore_buf->req_prod;
225 }
227 /* We're now guaranteed to be able to send the message without
228 overflowing the ring. Do so. */
229 total_off = 0;
230 req_off = 0;
231 while (total_off < len)
232 {
233 this_chunk = min(cur_req->len - req_off,
234 XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod));
235 memcpy((char *)xenstore_buf->req + MASK_XENSTORE_IDX(prod),
236 (char *)cur_req->data + req_off, this_chunk);
237 prod += this_chunk;
238 req_off += this_chunk;
239 total_off += this_chunk;
240 if (req_off == cur_req->len)
241 {
242 req_off = 0;
243 if (cur_req == &header_req)
244 cur_req = req;
245 else
246 cur_req++;
247 }
248 }
250 DEBUG("Complete main loop of xb_write.\n");
251 BUG_ON(req_off != 0);
252 BUG_ON(total_off != len);
253 BUG_ON(prod > xenstore_buf->req_cons + XENSTORE_RING_SIZE);
255 /* Remote must see entire message before updating indexes */
256 wmb();
258 xenstore_buf->req_prod += len;
260 /* Send evtchn to notify remote */
261 notify_remote_via_evtchn(start_info.store_evtchn);
262 }
264 /* Send a mesasge to xenbus, in the same fashion as xb_write, and
265 block waiting for a reply. The reply is malloced and should be
266 freed by the caller. */
267 static struct xsd_sockmsg *
268 xenbus_msg_reply(int type,
269 int trans,
270 struct write_req *io,
271 int nr_reqs)
272 {
273 int id;
274 DEFINE_WAIT(w);
275 struct xsd_sockmsg *rep;
277 id = allocate_xenbus_id();
278 add_waiter(w, req_info[id].waitq);
280 xb_write(type, id, trans, io, nr_reqs);
282 schedule();
283 wake(current);
285 rep = req_info[id].reply;
286 BUG_ON(rep->req_id != id);
287 release_xenbus_id(id);
288 return rep;
289 }
291 static char *errmsg(struct xsd_sockmsg *rep)
292 {
293 if (!rep) {
294 char msg[] = "No reply";
295 size_t len = strlen(msg) + 1;
296 return memcpy(malloc(len), msg, len);
297 }
298 if (rep->type != XS_ERROR)
299 return NULL;
300 char *res = malloc(rep->len + 1);
301 memcpy(res, rep + 1, rep->len);
302 res[rep->len] = 0;
303 free(rep);
304 return res;
305 }
307 /* Send a debug message to xenbus. Can block. */
308 static void xenbus_debug_msg(const char *msg)
309 {
310 int len = strlen(msg);
311 struct write_req req[] = {
312 { "print", sizeof("print") },
313 { msg, len },
314 { "", 1 }};
315 struct xsd_sockmsg *reply;
317 reply = xenbus_msg_reply(XS_DEBUG, 0, req, ARRAY_SIZE(req));
318 DEBUG("Got a reply, type %d, id %d, len %d.\n",
319 reply->type, reply->req_id, reply->len);
320 }
322 /* List the contents of a directory. Returns a malloc()ed array of
323 pointers to malloc()ed strings. The array is NULL terminated. May
324 block. */
325 char *xenbus_ls(const char *pre, char ***contents)
326 {
327 struct xsd_sockmsg *reply, *repmsg;
328 struct write_req req[] = { { pre, strlen(pre)+1 } };
329 int nr_elems, x, i;
330 char **res;
332 repmsg = xenbus_msg_reply(XS_DIRECTORY, 0, req, ARRAY_SIZE(req));
333 char *msg = errmsg(repmsg);
334 if (msg) {
335 *contents = NULL;
336 return msg;
337 }
338 reply = repmsg + 1;
339 for (x = nr_elems = 0; x < repmsg->len; x++)
340 nr_elems += (((char *)reply)[x] == 0);
341 res = malloc(sizeof(res[0]) * (nr_elems + 1));
342 for (x = i = 0; i < nr_elems; i++) {
343 int l = strlen((char *)reply + x);
344 res[i] = malloc(l + 1);
345 memcpy(res[i], (char *)reply + x, l + 1);
346 x += l + 1;
347 }
348 res[i] = NULL;
349 free(repmsg);
350 *contents = res;
351 return NULL;
352 }
354 char *xenbus_read(const char *path, char **value)
355 {
356 struct write_req req[] = { {path, strlen(path) + 1} };
357 struct xsd_sockmsg *rep;
358 char *res;
359 rep = xenbus_msg_reply(XS_READ, 0, req, ARRAY_SIZE(req));
360 char *msg = errmsg(rep);
361 if (msg) {
362 *value = NULL;
363 return msg;
364 }
365 res = malloc(rep->len + 1);
366 memcpy(res, rep + 1, rep->len);
367 res[rep->len] = 0;
368 free(rep);
369 *value = res;
370 return NULL;
371 }
373 char *xenbus_write(const char *path, const char *value)
374 {
375 struct write_req req[] = {
376 {path, strlen(path) + 1},
377 {value, strlen(value) + 1},
378 };
379 struct xsd_sockmsg *rep;
380 rep = xenbus_msg_reply(XS_WRITE, 0, req, ARRAY_SIZE(req));
381 char *msg = errmsg(rep);
382 if (msg)
383 return msg;
384 free(rep);
385 return NULL;
386 }
388 char *xenbus_rm(const char *path)
389 {
390 struct write_req req[] = { {path, strlen(path) + 1} };
391 struct xsd_sockmsg *rep;
392 rep = xenbus_msg_reply(XS_RM, 0, req, ARRAY_SIZE(req));
393 char *msg = errmsg(rep);
394 if (msg)
395 return msg;
396 free(rep);
397 return NULL;
398 }
400 char *xenbus_get_perms(const char *path, char **value)
401 {
402 struct write_req req[] = { {path, strlen(path) + 1} };
403 struct xsd_sockmsg *rep;
404 char *res;
405 rep = xenbus_msg_reply(XS_GET_PERMS, 0, req, ARRAY_SIZE(req));
406 char *msg = errmsg(rep);
407 if (msg) {
408 *value = NULL;
409 return msg;
410 }
411 res = malloc(rep->len + 1);
412 memcpy(res, rep + 1, rep->len);
413 res[rep->len] = 0;
414 free(rep);
415 *value = res;
416 return NULL;
417 }
419 #define PERM_MAX_SIZE 32
420 char *xenbus_set_perms(const char *path, domid_t dom, char perm)
421 {
422 char value[PERM_MAX_SIZE];
423 snprintf(value, PERM_MAX_SIZE, "%c%hu", perm, dom);
424 struct write_req req[] = {
425 {path, strlen(path) + 1},
426 {value, strlen(value) + 1},
427 };
428 struct xsd_sockmsg *rep;
429 rep = xenbus_msg_reply(XS_SET_PERMS, 0, req, ARRAY_SIZE(req));
430 char *msg = errmsg(rep);
431 if (msg)
432 return msg;
433 free(rep);
434 return NULL;
435 }
437 static void do_ls_test(const char *pre)
438 {
439 char **dirs;
440 int x;
442 DEBUG("ls %s...\n", pre);
443 char *msg = xenbus_ls(pre, &dirs);
444 if (msg) {
445 DEBUG("Error in xenbus ls: %s\n", msg);
446 free(msg);
447 return;
448 }
449 for (x = 0; dirs[x]; x++)
450 {
451 DEBUG("ls %s[%d] -> %s\n", pre, x, dirs[x]);
452 free(dirs[x]);
453 }
454 free(dirs);
455 }
457 static void do_read_test(const char *path)
458 {
459 char *res;
460 DEBUG("Read %s...\n", path);
461 char *msg = xenbus_read(path, &res);
462 if (msg) {
463 DEBUG("Error in xenbus read: %s\n", msg);
464 free(msg);
465 return;
466 }
467 DEBUG("Read %s -> %s.\n", path, res);
468 free(res);
469 }
471 static void do_write_test(const char *path, const char *val)
472 {
473 DEBUG("Write %s to %s...\n", val, path);
474 char *msg = xenbus_write(path, val);
475 if (msg) {
476 DEBUG("Result %s\n", msg);
477 free(msg);
478 } else {
479 DEBUG("Success.\n");
480 }
481 }
483 static void do_rm_test(const char *path)
484 {
485 DEBUG("rm %s...\n", path);
486 char *msg = xenbus_rm(path);
487 if (msg) {
488 DEBUG("Result %s\n", msg);
489 free(msg);
490 } else {
491 DEBUG("Success.\n");
492 }
493 }
495 /* Simple testing thing */
496 void test_xenbus(void)
497 {
498 DEBUG("Doing xenbus test.\n");
499 xenbus_debug_msg("Testing xenbus...\n");
501 DEBUG("Doing ls test.\n");
502 do_ls_test("device");
503 do_ls_test("device/vif");
504 do_ls_test("device/vif/0");
506 DEBUG("Doing read test.\n");
507 do_read_test("device/vif/0/mac");
508 do_read_test("device/vif/0/backend");
510 DEBUG("Doing write test.\n");
511 do_write_test("device/vif/0/flibble", "flobble");
512 do_read_test("device/vif/0/flibble");
513 do_write_test("device/vif/0/flibble", "widget");
514 do_read_test("device/vif/0/flibble");
516 DEBUG("Doing rm test.\n");
517 do_rm_test("device/vif/0/flibble");
518 do_read_test("device/vif/0/flibble");
519 DEBUG("(Should have said ENOENT)\n");
520 }
522 /*
523 * Local variables:
524 * mode: C
525 * c-basic-offset: 4
526 * End:
527 */