direct-io.hg

view extras/mini-os/xenbus/xenbus_xs.c @ 8693:491a8798945e

Remove shadow-translate Linux patches for now. We'll merge this stuff
in piecemeal.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Sat Jan 28 12:09:45 2006 +0100 (2006-01-28)
parents 7557f0b4098c
children
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 <spinlock.h>
43 #include <xen/io/xs_wire.h>
44 #include "xenbus_comms.h"
46 #define streq(a, b) (strcmp((a), (b)) == 0)
48 struct xs_stored_msg {
49 struct list_head list;
51 struct xsd_sockmsg hdr;
53 union {
54 /* Queued replies. */
55 struct {
56 char *body;
57 } reply;
59 /* Queued watch events. */
60 struct {
61 struct xenbus_watch *handle;
62 char **vec;
63 unsigned int vec_size;
64 } watch;
65 } u;
66 };
68 struct xs_handle {
69 /* A list of replies. Currently only one will ever be outstanding. */
70 struct list_head reply_list;
71 spinlock_t reply_lock;
72 struct wait_queue_head reply_waitq;
74 /* One request at a time. */
75 struct semaphore request_mutex;
77 /* Protect transactions against save/restore. */
78 struct rw_semaphore suspend_mutex;
79 };
81 static struct xs_handle xs_state;
83 /* List of registered watches, and a lock to protect it. */
84 static LIST_HEAD(watches);
85 static DEFINE_SPINLOCK(watches_lock);
87 /* List of pending watch callback events, and a lock to protect it. */
88 static LIST_HEAD(watch_events);
89 static DEFINE_SPINLOCK(watch_events_lock);
91 /*
92 * Details of the xenwatch callback kernel thread. The thread waits on the
93 * watch_events_waitq for work to do (queued on watch_events list). When it
94 * wakes up it acquires the xenwatch_mutex before reading the list and
95 * carrying out work.
96 */
97 /* static */ DECLARE_MUTEX(xenwatch_mutex);
98 static DECLARE_WAIT_QUEUE_HEAD(watch_events_waitq);
100 static int get_error(const char *errorstring)
101 {
102 unsigned int i;
104 for (i = 0; !streq(errorstring, xsd_errors[i].errstring); i++) {
105 if (i == ARRAY_SIZE(xsd_errors) - 1) {
106 printk("XENBUS xen store gave: unknown error %s",
107 errorstring);
108 return EINVAL;
109 }
110 }
111 return xsd_errors[i].errnum;
112 }
114 static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len)
115 {
116 struct xs_stored_msg *msg;
117 char *body;
119 spin_lock(&xs_state.reply_lock);
121 while (list_empty(&xs_state.reply_list)) {
122 spin_unlock(&xs_state.reply_lock);
123 wait_event(xs_state.reply_waitq,
124 !list_empty(&xs_state.reply_list));
125 spin_lock(&xs_state.reply_lock);
126 }
128 msg = list_entry(xs_state.reply_list.next,
129 struct xs_stored_msg, list);
130 list_del(&msg->list);
132 spin_unlock(&xs_state.reply_lock);
134 *type = msg->hdr.type;
135 if (len)
136 *len = msg->hdr.len;
137 body = msg->u.reply.body;
139 free(msg);
141 return body;
142 }
144 /* Emergency write. */
145 void xenbus_debug_write(const char *str, unsigned int count)
146 {
147 struct xsd_sockmsg msg = { 0 };
149 msg.type = XS_DEBUG;
150 msg.len = sizeof("print") + count + 1;
152 down(&xs_state.request_mutex);
153 xb_write(&msg, sizeof(msg));
154 xb_write("print", sizeof("print"));
155 xb_write(str, count);
156 xb_write("", 1);
157 up(&xs_state.request_mutex);
158 }
160 void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg)
161 {
162 void *ret;
163 struct xsd_sockmsg req_msg = *msg;
164 int err;
166 if (req_msg.type == XS_TRANSACTION_START)
167 down_read(&xs_state.suspend_mutex);
169 down(&xs_state.request_mutex);
171 err = xb_write(msg, sizeof(*msg) + msg->len);
172 if (err) {
173 msg->type = XS_ERROR;
174 ret = ERR_PTR(err);
175 } else {
176 ret = read_reply(&msg->type, &msg->len);
177 }
179 up(&xs_state.request_mutex);
181 if ((msg->type == XS_TRANSACTION_END) ||
182 ((req_msg.type == XS_TRANSACTION_START) &&
183 (msg->type == XS_ERROR)))
184 up_read(&xs_state.suspend_mutex);
186 return ret;
187 }
189 /* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */
190 static void *xs_talkv(struct xenbus_transaction *t,
191 enum xsd_sockmsg_type type,
192 const struct kvec *iovec,
193 unsigned int num_vecs,
194 unsigned int *len)
195 {
196 struct xsd_sockmsg msg;
197 void *ret = NULL;
198 unsigned int i;
199 int err;
201 msg.tx_id = (u32)(unsigned long)t;
202 msg.req_id = 0;
203 msg.type = type;
204 msg.len = 0;
205 for (i = 0; i < num_vecs; i++)
206 msg.len += iovec[i].iov_len;
208 down(&xs_state.request_mutex);
210 err = xb_write(&msg, sizeof(msg));
211 if (err) {
212 up(&xs_state.request_mutex);
213 return ERR_PTR(err);
214 }
216 for (i = 0; i < num_vecs; i++) {
217 err = xb_write(iovec[i].iov_base, iovec[i].iov_len);;
218 if (err) {
219 up(&xs_state.request_mutex);
220 return ERR_PTR(err);
221 }
222 }
224 ret = read_reply(&msg.type, len);
226 up(&xs_state.request_mutex);
228 if (IS_ERR(ret))
229 return ret;
231 if (msg.type == XS_ERROR) {
232 err = get_error(ret);
233 free(ret);
234 return ERR_PTR(-err);
235 }
237 // BUG_ON(msg.type != type);
238 return ret;
239 }
241 /* Simplified version of xs_talkv: single message. */
242 static void *xs_single(struct xenbus_transaction *t,
243 enum xsd_sockmsg_type type,
244 const char *string,
245 unsigned int *len)
246 {
247 struct kvec iovec;
249 iovec.iov_base = (void *)string;
250 iovec.iov_len = strlen(string) + 1;
251 return xs_talkv(t, type, &iovec, 1, len);
252 }
254 /* Many commands only need an ack, don't care what it says. */
255 static int xs_error(char *reply)
256 {
257 if (IS_ERR(reply))
258 return PTR_ERR(reply);
259 free(reply);
260 return 0;
261 }
263 static unsigned int count_strings(const char *strings, unsigned int len)
264 {
265 unsigned int num;
266 const char *p;
268 for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1)
269 num++;
271 return num;
272 }
274 /* Return the path to dir with /name appended. Buffer must be kfree()'ed. */
275 static char *join(const char *dir, const char *name)
276 {
277 char *buffer;
279 buffer = malloc(strlen(dir) + strlen("/") + strlen(name) + 1);
280 if (buffer == NULL)
281 return ERR_PTR(-ENOMEM);
283 strcpy(buffer, dir);
284 if (!streq(name, "")) {
285 strcat(buffer, "/");
286 strcat(buffer, name);
287 }
289 return buffer;
290 }
292 static char **split(char *strings, unsigned int len, unsigned int *num)
293 {
294 char *p, **ret;
296 /* Count the strings. */
297 *num = count_strings(strings, len);
299 /* Transfer to one big alloc for easy freeing. */
300 ret = malloc(*num * sizeof(char *) + len);
301 if (!ret) {
302 free(strings);
303 return ERR_PTR(-ENOMEM);
304 }
305 memcpy(&ret[*num], strings, len);
306 free(strings);
308 strings = (char *)&ret[*num];
309 for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1)
310 ret[(*num)++] = p;
312 return ret;
313 }
315 char **xenbus_directory(struct xenbus_transaction *t,
316 const char *dir, const char *node, unsigned int *num)
317 {
318 char *strings, *path;
319 unsigned int len;
321 path = join(dir, node);
322 if (IS_ERR(path))
323 return (char **)path;
325 strings = xs_single(t, XS_DIRECTORY, path, &len);
326 free(path);
327 if (IS_ERR(strings))
328 return (char **)strings;
330 return split(strings, len, num);
331 }
333 /* Check if a path exists. Return 1 if it does. */
334 int xenbus_exists(struct xenbus_transaction *t,
335 const char *dir, const char *node)
336 {
337 char **d;
338 int dir_n;
340 d = xenbus_directory(t, dir, node, &dir_n);
341 if (IS_ERR(d))
342 return 0;
343 free(d);
344 return 1;
345 }
347 /* Get the value of a single file.
348 * Returns a kmalloced value: call free() on it after use.
349 * len indicates length in bytes.
350 */
351 void *xenbus_read(struct xenbus_transaction *t,
352 const char *dir, const char *node, unsigned int *len)
353 {
354 char *path;
355 void *ret;
357 path = join(dir, node);
358 if (IS_ERR(path))
359 return (void *)path;
361 ret = xs_single(t, XS_READ, path, len);
362 free(path);
363 return ret;
364 }
366 /* Write the value of a single file.
367 * Returns -err on failure.
368 */
369 int xenbus_write(struct xenbus_transaction *t,
370 const char *dir, const char *node, const char *string)
371 {
372 const char *path;
373 struct kvec iovec[2];
374 int ret;
376 path = join(dir, node);
377 if (IS_ERR(path))
378 return PTR_ERR(path);
380 iovec[0].iov_base = (void *)path;
381 iovec[0].iov_len = strlen(path) + 1;
382 iovec[1].iov_base = (void *)string;
383 iovec[1].iov_len = strlen(string);
385 ret = xs_error(xs_talkv(t, XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL));
386 free(path);
387 return ret;
388 }
390 /* Create a new directory. */
391 int xenbus_mkdir(struct xenbus_transaction *t,
392 const char *dir, const char *node)
393 {
394 char *path;
395 int ret;
397 path = join(dir, node);
398 if (IS_ERR(path))
399 return PTR_ERR(path);
401 ret = xs_error(xs_single(t, XS_MKDIR, path, NULL));
402 free(path);
403 return ret;
404 }
406 /* Destroy a file or directory (directories must be empty). */
407 int xenbus_rm(struct xenbus_transaction *t, const char *dir, const char *node)
408 {
409 char *path;
410 int ret;
412 path = join(dir, node);
413 if (IS_ERR(path))
414 return PTR_ERR(path);
416 ret = xs_error(xs_single(t, XS_RM, path, NULL));
417 free(path);
418 return ret;
419 }
421 /* Start a transaction: changes by others will not be seen during this
422 * transaction, and changes will not be visible to others until end.
423 */
424 struct xenbus_transaction *xenbus_transaction_start(void)
425 {
426 char *id_str;
427 unsigned long id;
429 down_read(&xs_state.suspend_mutex);
431 id_str = xs_single(NULL, XS_TRANSACTION_START, "", NULL);
432 if (IS_ERR(id_str)) {
433 up_read(&xs_state.suspend_mutex);
434 return (struct xenbus_transaction *)id_str;
435 }
437 id = simple_strtoul(id_str, NULL, 0);
438 free(id_str);
440 return (struct xenbus_transaction *)id;
441 }
443 /* End a transaction.
444 * If abandon is true, transaction is discarded instead of committed.
445 */
446 int xenbus_transaction_end(struct xenbus_transaction *t, int abort)
447 {
448 char abortstr[2];
449 int err;
451 if (abort)
452 strcpy(abortstr, "F");
453 else
454 strcpy(abortstr, "T");
456 err = xs_error(xs_single(t, XS_TRANSACTION_END, abortstr, NULL));
458 up_read(&xs_state.suspend_mutex);
460 return err;
461 }
463 /* Single read and scanf: returns -errno or num scanned. */
464 int xenbus_scanf(struct xenbus_transaction *t,
465 const char *dir, const char *node, const char *fmt, ...)
466 {
467 va_list ap;
468 int ret;
469 char *val;
471 val = xenbus_read(t, dir, node, NULL);
472 if (IS_ERR(val))
473 return PTR_ERR(val);
475 va_start(ap, fmt);
476 ret = vsscanf(val, fmt, ap);
477 va_end(ap);
478 free(val);
479 /* Distinctive errno. */
480 if (ret == 0)
481 return -ERANGE;
482 return ret;
483 }
485 /* Single printf and write: returns -errno or 0. */
486 int xenbus_printf(struct xenbus_transaction *t,
487 const char *dir, const char *node, const char *fmt, ...)
488 {
489 va_list ap;
490 int ret;
491 #define PRINTF_BUFFER_SIZE 4096
492 char *printf_buffer;
494 printf_buffer = malloc(PRINTF_BUFFER_SIZE);
495 if (printf_buffer == NULL)
496 return -ENOMEM;
498 va_start(ap, fmt);
499 ret = vsnprintf(printf_buffer, PRINTF_BUFFER_SIZE, fmt, ap);
500 va_end(ap);
502 // BUG_ON(ret > PRINTF_BUFFER_SIZE-1);
503 ret = xenbus_write(t, dir, node, printf_buffer);
505 free(printf_buffer);
507 return ret;
508 }
510 /* Takes tuples of names, scanf-style args, and void **, NULL terminated. */
511 int xenbus_gather(struct xenbus_transaction *t, const char *dir, ...)
512 {
513 va_list ap;
514 const char *name;
515 int ret = 0;
517 va_start(ap, dir);
518 while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
519 const char *fmt = va_arg(ap, char *);
520 void *result = va_arg(ap, void *);
521 char *p;
523 p = xenbus_read(t, dir, name, NULL);
524 if (IS_ERR(p)) {
525 ret = PTR_ERR(p);
526 break;
527 }
528 if (fmt) {
529 if (sscanf(p, fmt, result) == 0)
530 ret = -EINVAL;
531 free(p);
532 } else
533 *(char **)result = p;
534 }
535 va_end(ap);
536 return ret;
537 }
539 static int xs_watch(const char *path, const char *token)
540 {
541 struct kvec iov[2];
543 iov[0].iov_base = (void *)path;
544 iov[0].iov_len = strlen(path) + 1;
545 iov[1].iov_base = (void *)token;
546 iov[1].iov_len = strlen(token) + 1;
548 return xs_error(xs_talkv(NULL, XS_WATCH, iov,
549 ARRAY_SIZE(iov), NULL));
550 }
552 static int xs_unwatch(const char *path, const char *token)
553 {
554 struct kvec iov[2];
556 iov[0].iov_base = (char *)path;
557 iov[0].iov_len = strlen(path) + 1;
558 iov[1].iov_base = (char *)token;
559 iov[1].iov_len = strlen(token) + 1;
561 return xs_error(xs_talkv(NULL, XS_UNWATCH, iov,
562 ARRAY_SIZE(iov), NULL));
563 }
565 static struct xenbus_watch *find_watch(const char *token)
566 {
567 struct xenbus_watch *i, *cmp;
569 cmp = (void *)simple_strtoul(token, NULL, 16);
571 list_for_each_entry(i, &watches, list)
572 if (i == cmp)
573 return i;
575 return NULL;
576 }
578 /* Register callback to watch this node. */
579 int register_xenbus_watch(struct xenbus_watch *watch)
580 {
581 /* Pointer in ascii is the token. */
582 char token[sizeof(watch) * 2 + 1];
583 int err;
585 sprintf(token, "%lX", (long)watch);
587 down_read(&xs_state.suspend_mutex);
589 spin_lock(&watches_lock);
590 // BUG_ON(find_watch(token));
591 list_add(&watch->list, &watches);
592 spin_unlock(&watches_lock);
594 err = xs_watch(watch->node, token);
596 /* Ignore errors due to multiple registration. */
597 if ((err != 0) && (err != -EEXIST)) {
598 spin_lock(&watches_lock);
599 list_del(&watch->list);
600 spin_unlock(&watches_lock);
601 }
603 up_read(&xs_state.suspend_mutex);
605 return err;
606 }
608 void unregister_xenbus_watch(struct xenbus_watch *watch)
609 {
610 struct xs_stored_msg *msg, *tmp;
611 char token[sizeof(watch) * 2 + 1];
612 int err;
614 sprintf(token, "%lX", (long)watch);
616 down_read(&xs_state.suspend_mutex);
618 spin_lock(&watches_lock);
619 // BUG_ON(!find_watch(token));
620 list_del(&watch->list);
621 spin_unlock(&watches_lock);
623 err = xs_unwatch(watch->node, token);
624 if (err)
625 printk("XENBUS Failed to release watch %s: %i\n",
626 watch->node, err);
628 up_read(&xs_state.suspend_mutex);
630 /* Cancel pending watch events. */
631 spin_lock(&watch_events_lock);
632 list_for_each_entry_safe(msg, tmp, &watch_events, list) {
633 if (msg->u.watch.handle != watch)
634 continue;
635 list_del(&msg->list);
636 free(msg->u.watch.vec);
637 free(msg);
638 }
639 spin_unlock(&watch_events_lock);
640 }
642 void xs_suspend(void)
643 {
644 down_write(&xs_state.suspend_mutex);
645 down(&xs_state.request_mutex);
646 }
648 void xs_resume(void)
649 {
650 struct xenbus_watch *watch;
651 char token[sizeof(watch) * 2 + 1];
653 up(&xs_state.request_mutex);
655 /* No need for watches_lock: the suspend_mutex is sufficient. */
656 list_for_each_entry(watch, &watches, list) {
657 sprintf(token, "%lX", (long)watch);
658 xs_watch(watch->node, token);
659 }
661 up_write(&xs_state.suspend_mutex);
662 }
664 static void xenwatch_thread(void *unused)
665 {
666 struct list_head *ent;
667 struct xs_stored_msg *msg;
669 for (;;) {
670 wait_event(watch_events_waitq,
671 !list_empty(&watch_events));
673 down(&xenwatch_mutex);
675 spin_lock(&watch_events_lock);
676 ent = watch_events.next;
677 if (ent != &watch_events)
678 list_del(ent);
679 spin_unlock(&watch_events_lock);
681 if (ent != &watch_events) {
682 msg = list_entry(ent, struct xs_stored_msg, list);
683 msg->u.watch.handle->callback(
684 msg->u.watch.handle,
685 (const char **)msg->u.watch.vec,
686 msg->u.watch.vec_size);
687 free(msg->u.watch.vec);
688 free(msg);
689 }
691 up(&xenwatch_mutex);
692 }
693 }
695 static int process_msg(void)
696 {
697 struct xs_stored_msg *msg;
698 char *body;
699 int err;
701 msg = malloc(sizeof(*msg));
702 if (msg == NULL)
703 return -ENOMEM;
705 err = xb_read(&msg->hdr, sizeof(msg->hdr));
706 if (err) {
707 free(msg);
708 return err;
709 }
711 body = malloc(msg->hdr.len + 1);
712 if (body == NULL) {
713 free(msg);
714 return -ENOMEM;
715 }
717 err = xb_read(body, msg->hdr.len);
718 if (err) {
719 free(body);
720 free(msg);
721 return err;
722 }
723 body[msg->hdr.len] = '\0';
725 if (msg->hdr.type == XS_WATCH_EVENT) {
726 msg->u.watch.vec = split(body, msg->hdr.len,
727 &msg->u.watch.vec_size);
728 if (IS_ERR(msg->u.watch.vec)) {
729 free(msg);
730 return PTR_ERR(msg->u.watch.vec);
731 }
733 spin_lock(&watches_lock);
734 msg->u.watch.handle = find_watch(
735 msg->u.watch.vec[XS_WATCH_TOKEN]);
736 if (msg->u.watch.handle != NULL) {
737 spin_lock(&watch_events_lock);
738 list_add_tail(&msg->list, &watch_events);
739 wake_up(&watch_events_waitq);
740 spin_unlock(&watch_events_lock);
741 } else {
742 free(msg->u.watch.vec);
743 free(msg);
744 }
745 spin_unlock(&watches_lock);
746 } else {
747 msg->u.reply.body = body;
748 spin_lock(&xs_state.reply_lock);
749 list_add_tail(&msg->list, &xs_state.reply_list);
750 spin_unlock(&xs_state.reply_lock);
751 wake_up(&xs_state.reply_waitq);
752 }
754 return 0;
755 }
757 static void xenbus_thread(void *unused)
758 {
759 int err;
761 for (;;) {
762 err = process_msg();
763 if (err)
764 printk("XENBUS error %d while reading "
765 "message\n", err);
766 }
767 }
769 int xs_init(void)
770 {
771 int err;
772 struct thread *kxwatcher_thread;
773 struct thread *kxenbus_thread;
775 INIT_LIST_HEAD(&xs_state.reply_list);
776 spin_lock_init(&xs_state.reply_lock);
777 init_waitqueue_head(&xs_state.reply_waitq);
779 init_MUTEX(&xs_state.request_mutex);
780 init_rwsem(&xs_state.suspend_mutex);
782 /* Initialize the shared memory rings to talk to xenstored */
783 err = xb_init_comms();
784 if (err)
785 return err;
787 kxwatcher_thread = create_thread("kxwatch", xenwatch_thread, NULL);
788 if (IS_ERR(kxwatcher_thread))
789 return PTR_ERR(kxwatcher_thread);
791 kxenbus_thread = create_thread("kxenbus", xenbus_thread, NULL);
792 if (IS_ERR(kxenbus_thread))
793 return PTR_ERR(kxenbus_thread);
795 return 0;
796 }