ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c @ 6265:5a97aa8698d9

Add support to xenbus_gather to scan for strings and return them in allocated memory.
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Thu Aug 18 19:24:42 2005 +0000 (2005-08-18)
parents 8203b7d536d3
children 509316987d65 66348ff38ec1 87dec3b9c546
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 "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);
48 DECLARE_MUTEX(xenbus_lock);
50 static int get_error(const char *errorstring)
51 {
52 unsigned int i;
54 for (i = 0; !streq(errorstring, xsd_errors[i].errstring); i++) {
55 if (i == ARRAY_SIZE(xsd_errors) - 1) {
56 printk(KERN_WARNING
57 "XENBUS xen store gave: unknown error %s",
58 errorstring);
59 return EINVAL;
60 }
61 }
62 return xsd_errors[i].errnum;
63 }
65 static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len)
66 {
67 struct xsd_sockmsg msg;
68 void *ret;
69 int err;
71 err = xb_read(&msg, sizeof(msg));
72 if (err)
73 return ERR_PTR(err);
75 ret = kmalloc(msg.len + 1, GFP_KERNEL);
76 if (!ret)
77 return ERR_PTR(-ENOMEM);
79 err = xb_read(ret, msg.len);
80 if (err) {
81 kfree(ret);
82 return ERR_PTR(err);
83 }
84 ((char*)ret)[msg.len] = '\0';
86 *type = msg.type;
87 if (len)
88 *len = msg.len;
89 return ret;
90 }
92 /* Emergency write. */
93 void xenbus_debug_write(const char *str, unsigned int count)
94 {
95 struct xsd_sockmsg msg;
97 msg.type = XS_DEBUG;
98 msg.len = sizeof("print") + count + 1;
100 xb_write(&msg, sizeof(msg));
101 xb_write("print", sizeof("print"));
102 xb_write(str, count);
103 xb_write("", 1);
104 }
106 /* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */
107 static void *xs_talkv(enum xsd_sockmsg_type type,
108 const struct kvec *iovec,
109 unsigned int num_vecs,
110 unsigned int *len)
111 {
112 struct xsd_sockmsg msg;
113 void *ret = NULL;
114 unsigned int i;
115 int err;
117 WARN_ON(down_trylock(&xenbus_lock) == 0);
119 msg.type = type;
120 msg.len = 0;
121 for (i = 0; i < num_vecs; i++)
122 msg.len += iovec[i].iov_len;
124 err = xb_write(&msg, sizeof(msg));
125 if (err)
126 return ERR_PTR(err);
128 for (i = 0; i < num_vecs; i++) {
129 err = xb_write(iovec[i].iov_base, iovec[i].iov_len);;
130 if (err)
131 return ERR_PTR(err);
132 }
134 /* Watches can have fired before reply comes: daemon detects
135 * and re-transmits, so we can ignore this. */
136 do {
137 kfree(ret);
138 ret = read_reply(&msg.type, len);
139 if (IS_ERR(ret))
140 return ret;
141 } while (msg.type == XS_WATCH_EVENT);
143 if (msg.type == XS_ERROR) {
144 err = get_error(ret);
145 kfree(ret);
146 return ERR_PTR(-err);
147 }
149 BUG_ON(msg.type != type);
150 return ret;
151 }
153 /* Simplified version of xs_talkv: single message. */
154 static void *xs_single(enum xsd_sockmsg_type type,
155 const char *string, unsigned int *len)
156 {
157 struct kvec iovec;
159 iovec.iov_base = (void *)string;
160 iovec.iov_len = strlen(string) + 1;
161 return xs_talkv(type, &iovec, 1, len);
162 }
164 /* Many commands only need an ack, don't care what it says. */
165 static int xs_error(char *reply)
166 {
167 if (IS_ERR(reply))
168 return PTR_ERR(reply);
169 kfree(reply);
170 return 0;
171 }
173 static unsigned int count_strings(const char *strings, unsigned int len)
174 {
175 unsigned int num;
176 const char *p;
178 for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1)
179 num++;
181 return num;
182 }
184 /* Return the path to dir with /name appended. */
185 static char *join(const char *dir, const char *name)
186 {
187 static char buffer[4096];
189 BUG_ON(down_trylock(&xenbus_lock) == 0);
190 /* XXX FIXME: might not be correct if name == "" */
191 BUG_ON(strlen(dir) + strlen("/") + strlen(name) + 1 > sizeof(buffer));
193 strcpy(buffer, dir);
194 if (!streq(name, "")) {
195 strcat(buffer, "/");
196 strcat(buffer, name);
197 }
198 return buffer;
199 }
201 char **xenbus_directory(const char *dir, const char *node, unsigned int *num)
202 {
203 char *strings, *p, **ret;
204 unsigned int len;
206 strings = xs_single(XS_DIRECTORY, join(dir, node), &len);
207 if (IS_ERR(strings))
208 return (char **)strings;
210 /* Count the strings. */
211 *num = count_strings(strings, len);
213 /* Transfer to one big alloc for easy freeing. */
214 ret = kmalloc(*num * sizeof(char *) + len, GFP_ATOMIC);
215 if (!ret) {
216 kfree(strings);
217 return ERR_PTR(-ENOMEM);
218 }
219 memcpy(&ret[*num], strings, len);
220 kfree(strings);
222 strings = (char *)&ret[*num];
223 for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1)
224 ret[(*num)++] = p;
225 return ret;
226 }
228 /* Check if a path exists. Return 1 if it does. */
229 int xenbus_exists(const char *dir, const char *node)
230 {
231 char **d;
232 int dir_n;
234 d = xenbus_directory(dir, node, &dir_n);
235 if (IS_ERR(d))
236 return 0;
237 kfree(d);
238 return 1;
239 }
241 /* Get the value of a single file.
242 * Returns a kmalloced value: call free() on it after use.
243 * len indicates length in bytes.
244 */
245 void *xenbus_read(const char *dir, const char *node, unsigned int *len)
246 {
247 return xs_single(XS_READ, join(dir, node), len);
248 }
250 /* Write the value of a single file.
251 * Returns -err on failure. createflags can be 0, O_CREAT, or O_CREAT|O_EXCL.
252 */
253 int xenbus_write(const char *dir, const char *node,
254 const char *string, int createflags)
255 {
256 const char *flags, *path;
257 struct kvec iovec[3];
259 path = join(dir, node);
260 /* Format: Flags (as string), path, data. */
261 if (createflags == 0)
262 flags = XS_WRITE_NONE;
263 else if (createflags == O_CREAT)
264 flags = XS_WRITE_CREATE;
265 else if (createflags == (O_CREAT|O_EXCL))
266 flags = XS_WRITE_CREATE_EXCL;
267 else
268 return -EINVAL;
270 iovec[0].iov_base = (void *)path;
271 iovec[0].iov_len = strlen(path) + 1;
272 iovec[1].iov_base = (void *)flags;
273 iovec[1].iov_len = strlen(flags) + 1;
274 iovec[2].iov_base = (void *)string;
275 iovec[2].iov_len = strlen(string);
277 return xs_error(xs_talkv(XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL));
278 }
280 /* Create a new directory. */
281 int xenbus_mkdir(const char *dir, const char *node)
282 {
283 return xs_error(xs_single(XS_MKDIR, join(dir, node), NULL));
284 }
286 /* Destroy a file or directory (directories must be empty). */
287 int xenbus_rm(const char *dir, const char *node)
288 {
289 return xs_error(xs_single(XS_RM, join(dir, node), NULL));
290 }
292 /* Start a transaction: changes by others will not be seen during this
293 * transaction, and changes will not be visible to others until end.
294 * Transaction only applies to the given subtree.
295 * You can only have one transaction at any time.
296 */
297 int xenbus_transaction_start(const char *subtree)
298 {
299 return xs_error(xs_single(XS_TRANSACTION_START, subtree, NULL));
300 }
302 /* End a transaction.
303 * If abandon is true, transaction is discarded instead of committed.
304 */
305 int xenbus_transaction_end(int abort)
306 {
307 char abortstr[2];
309 if (abort)
310 strcpy(abortstr, "F");
311 else
312 strcpy(abortstr, "T");
313 return xs_error(xs_single(XS_TRANSACTION_END, abortstr, NULL));
314 }
316 /* Single read and scanf: returns -errno or num scanned. */
317 int xenbus_scanf(const char *dir, const char *node, const char *fmt, ...)
318 {
319 va_list ap;
320 int ret;
321 char *val;
323 val = xenbus_read(dir, node, NULL);
324 if (IS_ERR(val))
325 return PTR_ERR(val);
327 va_start(ap, fmt);
328 ret = vsscanf(val, fmt, ap);
329 va_end(ap);
330 kfree(val);
331 /* Distinctive errno. */
332 if (ret == 0)
333 return -ERANGE;
334 return ret;
335 }
337 /* Single printf and write: returns -errno or 0. */
338 int xenbus_printf(const char *dir, const char *node, const char *fmt, ...)
339 {
340 va_list ap;
341 int ret;
343 BUG_ON(down_trylock(&xenbus_lock) == 0);
344 va_start(ap, fmt);
345 ret = vsnprintf(printf_buffer, sizeof(printf_buffer), fmt, ap);
346 va_end(ap);
348 BUG_ON(ret > sizeof(printf_buffer)-1);
349 return xenbus_write(dir, node, printf_buffer, O_CREAT);
350 }
352 /* Report a (negative) errno into the store, with explanation. */
353 void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ...)
354 {
355 va_list ap;
356 int ret;
357 unsigned int len;
359 BUG_ON(down_trylock(&xenbus_lock) == 0);
361 len = sprintf(printf_buffer, "%i ", -err);
362 va_start(ap, fmt);
363 ret = vsnprintf(printf_buffer+len, sizeof(printf_buffer)-len, fmt, ap);
364 va_end(ap);
366 BUG_ON(len + ret > sizeof(printf_buffer)-1);
367 dev->has_error = 1;
368 if (xenbus_write(dev->nodename, "error", printf_buffer, O_CREAT) != 0)
369 printk("xenbus: failed to write error node for %s (%s)\n",
370 dev->nodename, printf_buffer);
371 }
373 /* Clear any error. */
374 void xenbus_dev_ok(struct xenbus_device *dev)
375 {
376 if (dev->has_error) {
377 if (xenbus_rm(dev->nodename, "error") != 0)
378 printk("xenbus: failed to clear error node for %s\n",
379 dev->nodename);
380 else
381 dev->has_error = 0;
382 }
383 }
385 /* Takes tuples of names, scanf-style args, and void **, NULL terminated. */
386 int xenbus_gather(const char *dir, ...)
387 {
388 va_list ap;
389 const char *name;
390 int ret = 0;
392 va_start(ap, dir);
393 while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
394 const char *fmt = va_arg(ap, char *);
395 void *result = va_arg(ap, void *);
396 char *p;
398 p = xenbus_read(dir, name, NULL);
399 if (IS_ERR(p)) {
400 ret = PTR_ERR(p);
401 break;
402 }
403 if (fmt) {
404 if (sscanf(p, fmt, result) == 0)
405 ret = -EINVAL;
406 kfree(p);
407 } else
408 *(char **)result = p;
409 }
410 va_end(ap);
411 return ret;
412 }
414 static int xs_watch(const char *path, const char *token)
415 {
416 struct kvec iov[2];
418 iov[0].iov_base = (void *)path;
419 iov[0].iov_len = strlen(path) + 1;
420 iov[1].iov_base = (void *)token;
421 iov[1].iov_len = strlen(token) + 1;
423 return xs_error(xs_talkv(XS_WATCH, iov, ARRAY_SIZE(iov), NULL));
424 }
426 static char *xs_read_watch(char **token)
427 {
428 enum xsd_sockmsg_type type;
429 char *ret;
431 ret = read_reply(&type, NULL);
432 if (IS_ERR(ret))
433 return ret;
435 BUG_ON(type != XS_WATCH_EVENT);
436 *token = ret + strlen(ret) + 1;
437 return ret;
438 }
440 static int xs_acknowledge_watch(const char *token)
441 {
442 return xs_error(xs_single(XS_WATCH_ACK, token, NULL));
443 }
445 static int xs_unwatch(const char *path, const char *token)
446 {
447 struct kvec iov[2];
449 iov[0].iov_base = (char *)path;
450 iov[0].iov_len = strlen(path) + 1;
451 iov[1].iov_base = (char *)token;
452 iov[1].iov_len = strlen(token) + 1;
454 return xs_error(xs_talkv(XS_UNWATCH, iov, ARRAY_SIZE(iov), NULL));
455 }
457 /* A little paranoia: we don't just trust token. */
458 static struct xenbus_watch *find_watch(const char *token)
459 {
460 struct xenbus_watch *i, *cmp;
462 cmp = (void *)simple_strtoul(token, NULL, 16);
464 list_for_each_entry(i, &watches, list)
465 if (i == cmp)
466 return i;
467 return NULL;
468 }
470 /* Register callback to watch this node. */
471 int register_xenbus_watch(struct xenbus_watch *watch)
472 {
473 /* Pointer in ascii is the token. */
474 char token[sizeof(watch) * 2 + 1];
475 int err;
477 sprintf(token, "%lX", (long)watch);
478 BUG_ON(find_watch(token));
480 err = xs_watch(watch->node, token);
481 if (!err)
482 list_add(&watch->list, &watches);
483 return err;
484 }
486 void unregister_xenbus_watch(struct xenbus_watch *watch)
487 {
488 char token[sizeof(watch) * 2 + 1];
489 int err;
491 sprintf(token, "%lX", (long)watch);
492 BUG_ON(!find_watch(token));
494 err = xs_unwatch(watch->node, token);
495 list_del(&watch->list);
497 if (err)
498 printk(KERN_WARNING
499 "XENBUS Failed to release watch %s: %i\n",
500 watch->node, err);
501 }
503 /* Re-register callbacks to all watches. */
504 void reregister_xenbus_watches(void)
505 {
506 struct xenbus_watch *watch;
507 char token[sizeof(watch) * 2 + 1];
509 list_for_each_entry(watch, &watches, list) {
510 sprintf(token, "%lX", (long)watch);
511 xs_watch(watch->node, token);
512 }
513 }
515 static int watch_thread(void *unused)
516 {
517 for (;;) {
518 char *token;
519 char *node = NULL;
521 wait_event(xb_waitq, xs_input_avail());
523 /* If this is a spurious wakeup caused by someone
524 * doing an op, they'll hold the lock and the buffer
525 * will be empty by the time we get there.
526 */
527 down(&xenbus_lock);
528 if (xs_input_avail())
529 node = xs_read_watch(&token);
531 if (node && !IS_ERR(node)) {
532 struct xenbus_watch *w;
533 int err;
535 err = xs_acknowledge_watch(token);
536 if (err)
537 printk(KERN_WARNING "XENBUS ack %s fail %i\n",
538 node, err);
539 w = find_watch(token);
540 BUG_ON(!w);
541 w->callback(w, node);
542 kfree(node);
543 } else
544 printk(KERN_WARNING "XENBUS xs_read_watch: %li\n",
545 PTR_ERR(node));
546 up(&xenbus_lock);
547 }
548 }
550 int xs_init(void)
551 {
552 int err;
553 struct task_struct *watcher;
555 err = xb_init_comms();
556 if (err)
557 return err;
559 watcher = kthread_run(watch_thread, NULL, "kxbwatch");
560 if (IS_ERR(watcher))
561 return PTR_ERR(watcher);
562 return 0;
563 }