xen-vtx-unstable

view linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c @ 6774:4d899a738d59

merge?
author cl349@firebug.cl.cam.ac.uk
date Tue Sep 13 15:05:49 2005 +0000 (2005-09-13)
parents 1cb7adaa3355 b6c98fe62e1a
children e7c7196fa329 8ca0f98ba8e2
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 */
31 #include <linux/errno.h>
32 #include <linux/types.h>
33 #include <linux/uio.h>
34 #include <linux/kernel.h>
35 #include <linux/string.h>
36 #include <linux/err.h>
37 #include <linux/slab.h>
38 #include <linux/fcntl.h>
39 #include <linux/kthread.h>
40 #include <asm-xen/xenbus.h>
41 #include <asm-xen/linux-public/xenstored.h>
42 #include "xenbus_comms.h"
44 #define streq(a, b) (strcmp((a), (b)) == 0)
46 static char printf_buffer[4096];
47 static LIST_HEAD(watches);
49 DECLARE_MUTEX(xenbus_lock);
50 EXPORT_SYMBOL(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(KERN_WARNING
59 "XENBUS xen store gave: unknown error %s",
60 errorstring);
61 return EINVAL;
62 }
63 }
64 return xsd_errors[i].errnum;
65 }
67 static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len)
68 {
69 struct xsd_sockmsg msg;
70 void *ret;
71 int err;
73 err = xb_read(&msg, sizeof(msg));
74 if (err)
75 return ERR_PTR(err);
77 ret = kmalloc(msg.len + 1, GFP_KERNEL);
78 if (!ret)
79 return ERR_PTR(-ENOMEM);
81 err = xb_read(ret, msg.len);
82 if (err) {
83 kfree(ret);
84 return ERR_PTR(err);
85 }
86 ((char*)ret)[msg.len] = '\0';
88 *type = msg.type;
89 if (len)
90 *len = msg.len;
91 return ret;
92 }
94 /* Emergency write. */
95 void xenbus_debug_write(const char *str, unsigned int count)
96 {
97 struct xsd_sockmsg msg;
99 msg.type = XS_DEBUG;
100 msg.len = sizeof("print") + count + 1;
102 xb_write(&msg, sizeof(msg));
103 xb_write("print", sizeof("print"));
104 xb_write(str, count);
105 xb_write("", 1);
106 }
108 /* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */
109 static void *xs_talkv(enum xsd_sockmsg_type type,
110 const struct kvec *iovec,
111 unsigned int num_vecs,
112 unsigned int *len)
113 {
114 struct xsd_sockmsg msg;
115 void *ret = NULL;
116 unsigned int i;
117 int err;
119 WARN_ON(down_trylock(&xenbus_lock) == 0);
121 msg.type = type;
122 msg.len = 0;
123 for (i = 0; i < num_vecs; i++)
124 msg.len += iovec[i].iov_len;
126 err = xb_write(&msg, sizeof(msg));
127 if (err)
128 return ERR_PTR(err);
130 for (i = 0; i < num_vecs; i++) {
131 err = xb_write(iovec[i].iov_base, iovec[i].iov_len);;
132 if (err)
133 return ERR_PTR(err);
134 }
136 /* Watches can have fired before reply comes: daemon detects
137 * and re-transmits, so we can ignore this. */
138 do {
139 kfree(ret);
140 ret = read_reply(&msg.type, len);
141 if (IS_ERR(ret))
142 return ret;
143 } while (msg.type == XS_WATCH_EVENT);
145 if (msg.type == XS_ERROR) {
146 err = get_error(ret);
147 kfree(ret);
148 return ERR_PTR(-err);
149 }
151 BUG_ON(msg.type != type);
152 return ret;
153 }
155 /* Simplified version of xs_talkv: single message. */
156 static void *xs_single(enum xsd_sockmsg_type type,
157 const char *string, unsigned int *len)
158 {
159 struct kvec iovec;
161 iovec.iov_base = (void *)string;
162 iovec.iov_len = strlen(string) + 1;
163 return xs_talkv(type, &iovec, 1, len);
164 }
166 /* Many commands only need an ack, don't care what it says. */
167 static int xs_error(char *reply)
168 {
169 if (IS_ERR(reply))
170 return PTR_ERR(reply);
171 kfree(reply);
172 return 0;
173 }
175 static unsigned int count_strings(const char *strings, unsigned int len)
176 {
177 unsigned int num;
178 const char *p;
180 for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1)
181 num++;
183 return num;
184 }
186 /* Return the path to dir with /name appended. */
187 static char *join(const char *dir, const char *name)
188 {
189 static char buffer[4096];
191 BUG_ON(down_trylock(&xenbus_lock) == 0);
192 /* XXX FIXME: might not be correct if name == "" */
193 BUG_ON(strlen(dir) + strlen("/") + strlen(name) + 1 > sizeof(buffer));
195 strcpy(buffer, dir);
196 if (!streq(name, "")) {
197 strcat(buffer, "/");
198 strcat(buffer, name);
199 }
200 return buffer;
201 }
203 char **xenbus_directory(const char *dir, const char *node, unsigned int *num)
204 {
205 char *strings, *p, **ret;
206 unsigned int len;
208 strings = xs_single(XS_DIRECTORY, join(dir, node), &len);
209 if (IS_ERR(strings))
210 return (char **)strings;
212 /* Count the strings. */
213 *num = count_strings(strings, len);
215 /* Transfer to one big alloc for easy freeing. */
216 ret = kmalloc(*num * sizeof(char *) + len, GFP_ATOMIC);
217 if (!ret) {
218 kfree(strings);
219 return ERR_PTR(-ENOMEM);
220 }
221 memcpy(&ret[*num], strings, len);
222 kfree(strings);
224 strings = (char *)&ret[*num];
225 for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1)
226 ret[(*num)++] = p;
227 return ret;
228 }
229 EXPORT_SYMBOL(xenbus_directory);
231 /* Check if a path exists. Return 1 if it does. */
232 int xenbus_exists(const char *dir, const char *node)
233 {
234 char **d;
235 int dir_n;
237 d = xenbus_directory(dir, node, &dir_n);
238 if (IS_ERR(d))
239 return 0;
240 kfree(d);
241 return 1;
242 }
243 EXPORT_SYMBOL(xenbus_exists);
245 /* Get the value of a single file.
246 * Returns a kmalloced value: call free() on it after use.
247 * len indicates length in bytes.
248 */
249 void *xenbus_read(const char *dir, const char *node, unsigned int *len)
250 {
251 return xs_single(XS_READ, join(dir, node), len);
252 }
253 EXPORT_SYMBOL(xenbus_read);
255 /* Write the value of a single file.
256 * Returns -err on failure. createflags can be 0, O_CREAT, or O_CREAT|O_EXCL.
257 */
258 int xenbus_write(const char *dir, const char *node,
259 const char *string, int createflags)
260 {
261 const char *flags, *path;
262 struct kvec iovec[3];
264 path = join(dir, node);
265 /* Format: Flags (as string), path, data. */
266 if (createflags == 0)
267 flags = XS_WRITE_NONE;
268 else if (createflags == O_CREAT)
269 flags = XS_WRITE_CREATE;
270 else if (createflags == (O_CREAT|O_EXCL))
271 flags = XS_WRITE_CREATE_EXCL;
272 else
273 return -EINVAL;
275 iovec[0].iov_base = (void *)path;
276 iovec[0].iov_len = strlen(path) + 1;
277 iovec[1].iov_base = (void *)flags;
278 iovec[1].iov_len = strlen(flags) + 1;
279 iovec[2].iov_base = (void *)string;
280 iovec[2].iov_len = strlen(string);
282 return xs_error(xs_talkv(XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL));
283 }
284 EXPORT_SYMBOL(xenbus_write);
286 /* Create a new directory. */
287 int xenbus_mkdir(const char *dir, const char *node)
288 {
289 return xs_error(xs_single(XS_MKDIR, join(dir, node), NULL));
290 }
291 EXPORT_SYMBOL(xenbus_mkdir);
293 /* Destroy a file or directory (directories must be empty). */
294 int xenbus_rm(const char *dir, const char *node)
295 {
296 return xs_error(xs_single(XS_RM, join(dir, node), NULL));
297 }
298 EXPORT_SYMBOL(xenbus_rm);
300 /* Start a transaction: changes by others will not be seen during this
301 * transaction, and changes will not be visible to others until end.
302 * Transaction only applies to the given subtree.
303 * You can only have one transaction at any time.
304 */
305 int xenbus_transaction_start(const char *subtree)
306 {
307 return xs_error(xs_single(XS_TRANSACTION_START, subtree, NULL));
308 }
309 EXPORT_SYMBOL(xenbus_transaction_start);
311 /* End a transaction.
312 * If abandon is true, transaction is discarded instead of committed.
313 */
314 int xenbus_transaction_end(int abort)
315 {
316 char abortstr[2];
318 if (abort)
319 strcpy(abortstr, "F");
320 else
321 strcpy(abortstr, "T");
322 return xs_error(xs_single(XS_TRANSACTION_END, abortstr, NULL));
323 }
324 EXPORT_SYMBOL(xenbus_transaction_end);
326 /* Single read and scanf: returns -errno or num scanned. */
327 int xenbus_scanf(const char *dir, const char *node, const char *fmt, ...)
328 {
329 va_list ap;
330 int ret;
331 char *val;
333 val = xenbus_read(dir, node, NULL);
334 if (IS_ERR(val))
335 return PTR_ERR(val);
337 va_start(ap, fmt);
338 ret = vsscanf(val, fmt, ap);
339 va_end(ap);
340 kfree(val);
341 /* Distinctive errno. */
342 if (ret == 0)
343 return -ERANGE;
344 return ret;
345 }
346 EXPORT_SYMBOL(xenbus_scanf);
348 /* Single printf and write: returns -errno or 0. */
349 int xenbus_printf(const char *dir, const char *node, const char *fmt, ...)
350 {
351 va_list ap;
352 int ret;
354 BUG_ON(down_trylock(&xenbus_lock) == 0);
355 va_start(ap, fmt);
356 ret = vsnprintf(printf_buffer, sizeof(printf_buffer), fmt, ap);
357 va_end(ap);
359 BUG_ON(ret > sizeof(printf_buffer)-1);
360 return xenbus_write(dir, node, printf_buffer, O_CREAT);
361 }
362 EXPORT_SYMBOL(xenbus_printf);
364 /* Report a (negative) errno into the store, with explanation. */
365 void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ...)
366 {
367 va_list ap;
368 int ret;
369 unsigned int len;
371 BUG_ON(down_trylock(&xenbus_lock) == 0);
373 len = sprintf(printf_buffer, "%i ", -err);
374 va_start(ap, fmt);
375 ret = vsnprintf(printf_buffer+len, sizeof(printf_buffer)-len, fmt, ap);
376 va_end(ap);
378 BUG_ON(len + ret > sizeof(printf_buffer)-1);
379 dev->has_error = 1;
380 if (xenbus_write(dev->nodename, "error", printf_buffer, O_CREAT) != 0)
381 printk("xenbus: failed to write error node for %s (%s)\n",
382 dev->nodename, printf_buffer);
383 }
384 EXPORT_SYMBOL(xenbus_dev_error);
386 /* Clear any error. */
387 void xenbus_dev_ok(struct xenbus_device *dev)
388 {
389 if (dev->has_error) {
390 if (xenbus_rm(dev->nodename, "error") != 0)
391 printk("xenbus: failed to clear error node for %s\n",
392 dev->nodename);
393 else
394 dev->has_error = 0;
395 }
396 }
397 EXPORT_SYMBOL(xenbus_dev_ok);
399 /* Takes tuples of names, scanf-style args, and void **, NULL terminated. */
400 int xenbus_gather(const char *dir, ...)
401 {
402 va_list ap;
403 const char *name;
404 int ret = 0;
406 va_start(ap, dir);
407 while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
408 const char *fmt = va_arg(ap, char *);
409 void *result = va_arg(ap, void *);
410 char *p;
412 p = xenbus_read(dir, name, NULL);
413 if (IS_ERR(p)) {
414 ret = PTR_ERR(p);
415 break;
416 }
417 if (fmt) {
418 if (sscanf(p, fmt, result) == 0)
419 ret = -EINVAL;
420 kfree(p);
421 } else
422 *(char **)result = p;
423 }
424 va_end(ap);
425 return ret;
426 }
427 EXPORT_SYMBOL(xenbus_gather);
429 static int xs_watch(const char *path, const char *token)
430 {
431 struct kvec iov[2];
433 iov[0].iov_base = (void *)path;
434 iov[0].iov_len = strlen(path) + 1;
435 iov[1].iov_base = (void *)token;
436 iov[1].iov_len = strlen(token) + 1;
438 return xs_error(xs_talkv(XS_WATCH, iov, ARRAY_SIZE(iov), NULL));
439 }
441 static char *xs_read_watch(char **token)
442 {
443 enum xsd_sockmsg_type type;
444 char *ret;
446 ret = read_reply(&type, NULL);
447 if (IS_ERR(ret))
448 return ret;
450 BUG_ON(type != XS_WATCH_EVENT);
451 *token = ret + strlen(ret) + 1;
452 return ret;
453 }
455 static int xs_acknowledge_watch(const char *token)
456 {
457 return xs_error(xs_single(XS_WATCH_ACK, token, NULL));
458 }
460 static int xs_unwatch(const char *path, const char *token)
461 {
462 struct kvec iov[2];
464 iov[0].iov_base = (char *)path;
465 iov[0].iov_len = strlen(path) + 1;
466 iov[1].iov_base = (char *)token;
467 iov[1].iov_len = strlen(token) + 1;
469 return xs_error(xs_talkv(XS_UNWATCH, iov, ARRAY_SIZE(iov), NULL));
470 }
472 /* A little paranoia: we don't just trust token. */
473 static struct xenbus_watch *find_watch(const char *token)
474 {
475 struct xenbus_watch *i, *cmp;
477 cmp = (void *)simple_strtoul(token, NULL, 16);
479 list_for_each_entry(i, &watches, list)
480 if (i == cmp)
481 return i;
482 return NULL;
483 }
485 /* Register callback to watch this node. */
486 int register_xenbus_watch(struct xenbus_watch *watch)
487 {
488 /* Pointer in ascii is the token. */
489 char token[sizeof(watch) * 2 + 1];
490 int err;
492 sprintf(token, "%lX", (long)watch);
493 BUG_ON(find_watch(token));
495 err = xs_watch(watch->node, token);
496 if (!err)
497 list_add(&watch->list, &watches);
498 return err;
499 }
500 EXPORT_SYMBOL(register_xenbus_watch);
502 void unregister_xenbus_watch(struct xenbus_watch *watch)
503 {
504 char token[sizeof(watch) * 2 + 1];
505 int err;
507 sprintf(token, "%lX", (long)watch);
508 BUG_ON(!find_watch(token));
510 err = xs_unwatch(watch->node, token);
511 list_del(&watch->list);
513 if (err)
514 printk(KERN_WARNING
515 "XENBUS Failed to release watch %s: %i\n",
516 watch->node, err);
517 }
518 EXPORT_SYMBOL(unregister_xenbus_watch);
520 /* Re-register callbacks to all watches. */
521 void reregister_xenbus_watches(void)
522 {
523 struct xenbus_watch *watch;
524 char token[sizeof(watch) * 2 + 1];
526 list_for_each_entry(watch, &watches, list) {
527 sprintf(token, "%lX", (long)watch);
528 xs_watch(watch->node, token);
529 }
530 }
532 static int watch_thread(void *unused)
533 {
534 for (;;) {
535 char *token;
536 char *node = NULL;
538 wait_event(xb_waitq, xs_input_avail());
540 /* If this is a spurious wakeup caused by someone
541 * doing an op, they'll hold the lock and the buffer
542 * will be empty by the time we get there.
543 */
544 down(&xenbus_lock);
545 if (xs_input_avail())
546 node = xs_read_watch(&token);
548 if (node && !IS_ERR(node)) {
549 struct xenbus_watch *w;
550 int err;
552 err = xs_acknowledge_watch(token);
553 if (err)
554 printk(KERN_WARNING "XENBUS ack %s fail %i\n",
555 node, err);
556 w = find_watch(token);
557 BUG_ON(!w);
558 w->callback(w, node);
559 kfree(node);
560 } else if (node)
561 printk(KERN_WARNING "XENBUS xs_read_watch: %li\n",
562 PTR_ERR(node));
563 up(&xenbus_lock);
564 }
565 }
567 int xs_init(void)
568 {
569 int err;
570 struct task_struct *watcher;
572 err = xb_init_comms();
573 if (err)
574 return err;
576 watcher = kthread_run(watch_thread, NULL, "kxbwatch");
577 if (IS_ERR(watcher))
578 return PTR_ERR(watcher);
579 return 0;
580 }