ia64/xen-unstable

view extras/mini-os/xenbus/xenbus_xs.c @ 6726:0c7379b702e5

common/kernel.o contains changeset/compiler info.
Blow away on every build.
author kaf24@firebug.cl.cam.ac.uk
date Fri Sep 09 16:26:20 2005 +0000 (2005-09-09)
parents cdfa7dd00c44
children b2f4823b6ff0 b35215021b32 9af349b055e5 3233e7ecfa9f
line source
1 /******************************************************************************
2 * xenbus_xs.c
3 *
4 * This is the kernel equivalent of the "xs" library. We don't need everything
5 * and we use xenbus_comms for communication.
6 *
7 * Copyright (C) 2005 Rusty Russell, IBM Corporation
8 *
9 * This file may be distributed separately from the Linux kernel, or
10 * incorporated into other software packages, subject to the following license:
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a copy
13 * of this source file (the "Software"), to deal in the Software without
14 * restriction, including without limitation the rights to use, copy, modify,
15 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
16 * and to permit persons to whom the Software is furnished to do so, subject to
17 * the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included in
20 * all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
28 * IN THE SOFTWARE.
29 */
30 #include <errno.h>
31 #include <types.h>
32 #include <list.h>
33 #include <lib.h>
34 #include <err.h>
35 #include <os.h>
36 #include <xmalloc.h>
37 #include <fcntl.h>
38 #include <xenbus.h>
39 #include <wait.h>
40 #include <sched.h>
41 #include <semaphore.h>
42 #include "xenstored.h"
43 #include "xenbus_comms.h"
45 #define streq(a, b) (strcmp((a), (b)) == 0)
47 static char printf_buffer[4096];
48 static LIST_HEAD(watches);
49 //TODO
50 DECLARE_MUTEX(xenbus_lock);
52 static int get_error(const char *errorstring)
53 {
54 unsigned int i;
56 for (i = 0; !streq(errorstring, xsd_errors[i].errstring); i++) {
57 if (i == ARRAY_SIZE(xsd_errors) - 1) {
58 printk("XENBUS xen store gave: unknown error %s",
59 errorstring);
60 return EINVAL;
61 }
62 }
63 return xsd_errors[i].errnum;
64 }
66 static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len)
67 {
68 struct xsd_sockmsg msg;
69 void *ret;
70 int err;
72 err = xb_read(&msg, sizeof(msg));
73 if (err)
74 return ERR_PTR(err);
76 ret = xmalloc_array(char, msg.len + 1);
77 if (!ret)
78 return ERR_PTR(-ENOMEM);
80 err = xb_read(ret, msg.len);
81 if (err) {
82 xfree(ret);
83 return ERR_PTR(err);
84 }
85 ((char*)ret)[msg.len] = '\0';
87 *type = msg.type;
88 if (len)
89 *len = msg.len;
90 return ret;
91 }
93 /* Emergency write. */
94 void xenbus_debug_write(const char *str, unsigned int count)
95 {
96 struct xsd_sockmsg msg;
98 msg.type = XS_DEBUG;
99 msg.len = sizeof("print") + count + 1;
101 xb_write(&msg, sizeof(msg));
102 xb_write("print", sizeof("print"));
103 xb_write(str, count);
104 xb_write("", 1);
105 }
107 /* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */
108 static void *xs_talkv(enum xsd_sockmsg_type type,
109 const struct kvec *iovec,
110 unsigned int num_vecs,
111 unsigned int *len)
112 {
113 struct xsd_sockmsg msg;
114 void *ret = NULL;
115 unsigned int i;
116 int err;
118 //WARN_ON(down_trylock(&xenbus_lock) == 0);
120 msg.type = type;
121 msg.len = 0;
122 for (i = 0; i < num_vecs; i++)
123 msg.len += iovec[i].iov_len;
125 err = xb_write(&msg, sizeof(msg));
126 if (err)
127 return ERR_PTR(err);
129 for (i = 0; i < num_vecs; i++) {
130 err = xb_write(iovec[i].iov_base, iovec[i].iov_len);;
131 if (err)
132 return ERR_PTR(err);
133 }
135 /* Watches can have fired before reply comes: daemon detects
136 * and re-transmits, so we can ignore this. */
137 do {
138 xfree(ret);
139 ret = read_reply(&msg.type, len);
140 if (IS_ERR(ret))
141 return ret;
142 } while (msg.type == XS_WATCH_EVENT);
144 if (msg.type == XS_ERROR) {
145 err = get_error(ret);
146 xfree(ret);
147 return ERR_PTR(-err);
148 }
150 //BUG_ON(msg.type != type);
151 return ret;
152 }
154 /* Simplified version of xs_talkv: single message. */
155 static void *xs_single(enum xsd_sockmsg_type type,
156 const char *string, unsigned int *len)
157 {
158 struct kvec iovec;
160 iovec.iov_base = (void *)string;
161 iovec.iov_len = strlen(string) + 1;
162 return xs_talkv(type, &iovec, 1, len);
163 }
165 /* Many commands only need an ack, don't care what it says. */
166 static int xs_error(char *reply)
167 {
168 if (IS_ERR(reply))
169 return PTR_ERR(reply);
170 xfree(reply);
171 return 0;
172 }
174 static unsigned int count_strings(const char *strings, unsigned int len)
175 {
176 unsigned int num;
177 const char *p;
179 for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1)
180 num++;
182 return num;
183 }
185 /* Return the path to dir with /name appended. */
186 static char *join(const char *dir, const char *name)
187 {
188 static char buffer[4096];
190 //BUG_ON(down_trylock(&xenbus_lock) == 0);
191 /* XXX FIXME: might not be correct if name == "" */
192 //BUG_ON(strlen(dir) + strlen("/") + strlen(name) + 1 > sizeof(buffer));
194 strcpy(buffer, dir);
195 if (!streq(name, "")) {
196 strcat(buffer, "/");
197 strcat(buffer, name);
198 }
199 return buffer;
200 }
202 char **xenbus_directory(const char *dir, const char *node, unsigned int *num)
203 {
204 char *strings, *p, **ret;
205 unsigned int len;
207 strings = xs_single(XS_DIRECTORY, join(dir, node), &len);
208 if (IS_ERR(strings))
209 return (char **)strings;
211 /* Count the strings. */
212 *num = count_strings(strings, len);
214 /* Transfer to one big alloc for easy freeing. */
215 ret = (char **)xmalloc_array(char, *num * sizeof(char *) + len);
216 if (!ret) {
217 xfree(strings);
218 return ERR_PTR(-ENOMEM);
219 }
220 memcpy(&ret[*num], strings, len);
221 xfree(strings);
223 strings = (char *)&ret[*num];
224 for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1)
225 ret[(*num)++] = p;
226 return ret;
227 }
229 /* Check if a path exists. Return 1 if it does. */
230 int xenbus_exists(const char *dir, const char *node)
231 {
232 char **d;
233 int dir_n;
235 d = xenbus_directory(dir, node, &dir_n);
236 if (IS_ERR(d))
237 return 0;
238 xfree(d);
239 return 1;
240 }
242 /* Get the value of a single file.
243 * Returns a kmalloced value: call free() on it after use.
244 * len indicates length in bytes.
245 */
246 void *xenbus_read(const char *dir, const char *node, unsigned int *len)
247 {
248 return xs_single(XS_READ, join(dir, node), len);
249 }
251 /* Write the value of a single file.
252 * Returns -err on failure. createflags can be 0, O_CREAT, or O_CREAT|O_EXCL.
253 */
254 int xenbus_write(const char *dir, const char *node,
255 const char *string, int createflags)
256 {
257 const char *flags, *path;
258 struct kvec iovec[3];
260 path = join(dir, node);
261 /* Format: Flags (as string), path, data. */
262 if (createflags == 0)
263 flags = XS_WRITE_NONE;
264 else if (createflags == O_CREAT)
265 flags = XS_WRITE_CREATE;
266 else if (createflags == (O_CREAT|O_EXCL))
267 flags = XS_WRITE_CREATE_EXCL;
268 else
269 return -EINVAL;
271 iovec[0].iov_base = (void *)path;
272 iovec[0].iov_len = strlen(path) + 1;
273 iovec[1].iov_base = (void *)flags;
274 iovec[1].iov_len = strlen(flags) + 1;
275 iovec[2].iov_base = (void *)string;
276 iovec[2].iov_len = strlen(string);
278 return xs_error(xs_talkv(XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL));
279 }
281 /* Create a new directory. */
282 int xenbus_mkdir(const char *dir, const char *node)
283 {
284 return xs_error(xs_single(XS_MKDIR, join(dir, node), NULL));
285 }
287 /* Destroy a file or directory (directories must be empty). */
288 int xenbus_rm(const char *dir, const char *node)
289 {
290 return xs_error(xs_single(XS_RM, join(dir, node), NULL));
291 }
293 /* Start a transaction: changes by others will not be seen during this
294 * transaction, and changes will not be visible to others until end.
295 * Transaction only applies to the given subtree.
296 * You can only have one transaction at any time.
297 */
298 int xenbus_transaction_start(const char *subtree)
299 {
300 return xs_error(xs_single(XS_TRANSACTION_START, subtree, NULL));
301 }
303 /* End a transaction.
304 * If abandon is true, transaction is discarded instead of committed.
305 */
306 int xenbus_transaction_end(int abort)
307 {
308 char abortstr[2];
310 if (abort)
311 strcpy(abortstr, "F");
312 else
313 strcpy(abortstr, "T");
314 return xs_error(xs_single(XS_TRANSACTION_END, abortstr, NULL));
315 }
317 /* Single read and scanf: returns -errno or num scanned. */
318 int xenbus_scanf(const char *dir, const char *node, const char *fmt, ...)
319 {
320 va_list ap;
321 int ret;
322 char *val;
324 val = xenbus_read(dir, node, NULL);
325 if (IS_ERR(val))
326 return PTR_ERR(val);
328 va_start(ap, fmt);
329 ret = vsscanf(val, fmt, ap);
330 va_end(ap);
331 xfree(val);
332 /* Distinctive errno. */
333 if (ret == 0)
334 return -ERANGE;
335 return ret;
336 }
338 /* Single printf and write: returns -errno or 0. */
339 int xenbus_printf(const char *dir, const char *node, const char *fmt, ...)
340 {
341 va_list ap;
342 int ret;
344 //BUG_ON(down_trylock(&xenbus_lock) == 0);
345 va_start(ap, fmt);
346 ret = vsnprintf(printf_buffer, sizeof(printf_buffer), fmt, ap);
347 va_end(ap);
349 //BUG_ON(ret > sizeof(printf_buffer)-1);
350 return xenbus_write(dir, node, printf_buffer, O_CREAT);
351 }
354 /* Takes tuples of names, scanf-style args, and void **, NULL terminated. */
355 int xenbus_gather(const char *dir, ...)
356 {
357 va_list ap;
358 const char *name;
359 int ret = 0;
361 va_start(ap, dir);
362 while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
363 const char *fmt = va_arg(ap, char *);
364 void *result = va_arg(ap, void *);
365 char *p;
367 p = xenbus_read(dir, name, NULL);
368 if (IS_ERR(p)) {
369 ret = PTR_ERR(p);
370 break;
371 }
372 if (fmt) {
373 if (sscanf(p, fmt, result) == 0)
374 ret = -EINVAL;
375 xfree(p);
376 } else
377 *(char **)result = p;
378 }
379 va_end(ap);
380 return ret;
381 }
383 static int xs_watch(const char *path, const char *token)
384 {
385 struct kvec iov[2];
387 iov[0].iov_base = (void *)path;
388 iov[0].iov_len = strlen(path) + 1;
389 iov[1].iov_base = (void *)token;
390 iov[1].iov_len = strlen(token) + 1;
392 return xs_error(xs_talkv(XS_WATCH, iov, ARRAY_SIZE(iov), NULL));
393 }
395 static char *xs_read_watch(char **token)
396 {
397 enum xsd_sockmsg_type type;
398 char *ret;
400 ret = read_reply(&type, NULL);
401 if (IS_ERR(ret))
402 return ret;
404 //BUG_ON(type != XS_WATCH_EVENT);
405 *token = ret + strlen(ret) + 1;
406 return ret;
407 }
409 static int xs_acknowledge_watch(const char *token)
410 {
411 return xs_error(xs_single(XS_WATCH_ACK, token, NULL));
412 }
414 static int xs_unwatch(const char *path, const char *token)
415 {
416 struct kvec iov[2];
418 iov[0].iov_base = (char *)path;
419 iov[0].iov_len = strlen(path) + 1;
420 iov[1].iov_base = (char *)token;
421 iov[1].iov_len = strlen(token) + 1;
423 return xs_error(xs_talkv(XS_UNWATCH, iov, ARRAY_SIZE(iov), NULL));
424 }
426 /* A little paranoia: we don't just trust token. */
427 static struct xenbus_watch *find_watch(const char *token)
428 {
429 struct xenbus_watch *i, *cmp;
431 cmp = (void *)simple_strtoul(token, NULL, 16);
433 list_for_each_entry(i, &watches, list)
434 if (i == cmp)
435 return i;
436 return NULL;
437 }
439 /* Register callback to watch this node. */
440 int register_xenbus_watch(struct xenbus_watch *watch)
441 {
442 /* Pointer in ascii is the token. */
443 char token[sizeof(watch) * 2 + 1];
444 int err;
446 sprintf(token, "%lX", (long)watch);
447 //BUG_ON(find_watch(token));
448 printk("Registered watch for: %s\n", token);
449 err = xs_watch(watch->node, token);
450 if (!err)
451 list_add(&watch->list, &watches);
452 return err;
453 }
455 void unregister_xenbus_watch(struct xenbus_watch *watch)
456 {
457 char token[sizeof(watch) * 2 + 1];
458 int err;
460 sprintf(token, "%lX", (long)watch);
461 //BUG_ON(!find_watch(token));
463 err = xs_unwatch(watch->node, token);
464 list_del(&watch->list);
466 if (err)
467 printk("XENBUS Failed to release watch %s: %i\n",
468 watch->node, err);
469 }
471 /* Re-register callbacks to all watches. */
472 void reregister_xenbus_watches(void)
473 {
474 struct xenbus_watch *watch;
475 char token[sizeof(watch) * 2 + 1];
477 list_for_each_entry(watch, &watches, list) {
478 sprintf(token, "%lX", (long)watch);
479 xs_watch(watch->node, token);
480 }
481 }
483 void watch_thread(void *unused)
484 {
485 for (;;) {
486 char *token;
487 char *node = NULL;
489 wait_event(xb_waitq, xs_input_avail());
491 /* If this is a spurious wakeup caused by someone
492 * doing an op, they'll hold the lock and the buffer
493 * will be empty by the time we get there.
494 */
495 down(&xenbus_lock);
496 if (xs_input_avail())
497 node = xs_read_watch(&token);
499 if (node && !IS_ERR(node)) {
500 struct xenbus_watch *w;
501 int err;
503 err = xs_acknowledge_watch(token);
504 if (err)
505 printk("XENBUS ack %s fail %i\n", node, err);
506 w = find_watch(token);
507 //BUG_ON(!w);
508 w->callback(w, node);
509 xfree(node);
510 } else
511 printk("XENBUS xs_read_watch: %li\n", PTR_ERR(node));
512 up(&xenbus_lock);
513 }
514 }
517 static void ballon_changed(struct xenbus_watch *watch, const char *node)
518 {
519 unsigned long new_target;
520 int err;
521 err = xenbus_scanf("memory", "target", "%lu", &new_target);
523 if(err != 1)
524 {
525 printk("Unable to read memory/target\n");
526 return;
527 }
529 printk("Memory target changed to: %ld bytes, ignoring.\n", new_target);
530 }
533 static struct xenbus_watch ballon_watch = {
534 .node = "memory/target",
535 .callback = ballon_changed,
536 };
540 int xs_init(void)
541 {
542 int err;
543 struct thread *watcher;
544 printk("xb_init_comms\n");
545 err = xb_init_comms();
546 if (err)
547 return err;
549 watcher = create_thread("kxwatch", watch_thread, NULL);
550 down(&xenbus_lock);
551 register_xenbus_watch(&ballon_watch);
552 up(&xenbus_lock);
553 return 0;
554 }