1 /* $NetBSD: xenbus_xs.c,v 1.17 2008/10/29 13:53:15 cegger Exp $ */
2 /******************************************************************************
5 * This is the kernel equivalent of the "xs" library. We don't need everything
6 * and we use xenbus_comms for communication.
8 * Copyright (C) 2005 Rusty Russell, IBM Corporation
10 * This file may be distributed separately from the Linux kernel, or
11 * incorporated into other software packages, subject to the following license:
13 * Permission is hereby granted, free of charge, to any person obtaining a copy
14 * of this source file (the "Software"), to deal in the Software without
15 * restriction, including without limitation the rights to use, copy, modify,
16 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
17 * and to permit persons to whom the Software is furnished to do so, subject to
18 * the following conditions:
20 * The above copyright notice and this permission notice shall be included in
21 * all copies or substantial portions of the Software.
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: xenbus_xs.c,v 1.17 2008/10/29 13:53:15 cegger Exp $");
36 #define DPRINTK(fmt, args...) \
37 printf("xenbus_xs (%s:%d) " fmt ".\n", __func__, __LINE__, ##args)
39 #define DPRINTK(fmt, args...) ((void)0)
42 #include <sys/types.h>
44 #include <sys/errno.h>
45 #include <sys/malloc.h>
46 #include <sys/systm.h>
47 #include <sys/param.h>
49 #include <sys/mutex.h>
50 #include <sys/kthread.h>
51 #include <sys/simplelock.h>
53 #include <machine/stdarg.h>
55 #include <xen/xen.h> /* for xendomain_is_dom0() */
56 #include <xen/xenbus.h>
57 #include "xenbus_comms.h"
59 #define streq(a, b) (strcmp((a), (b)) == 0)
61 struct xs_stored_msg
{
62 SIMPLEQ_ENTRY(xs_stored_msg
) msg_next
;
64 struct xsd_sockmsg hdr
;
72 /* Queued watch events. */
74 struct xenbus_watch
*handle
;
76 unsigned int vec_size
;
82 /* A list of replies. Currently only one will ever be outstanding. */
83 SIMPLEQ_HEAD(, xs_stored_msg
) reply_list
;
84 struct simplelock reply_lock
;
85 kmutex_t xs_lock
; /* serialize access to xenstore */
90 static struct xs_handle xs_state
;
92 /* List of registered watches, and a lock to protect it. */
93 static SLIST_HEAD(, xenbus_watch
) watches
=
94 SLIST_HEAD_INITIALIZER(watches
);
95 static struct simplelock watches_lock
= SIMPLELOCK_INITIALIZER
;
97 /* List of pending watch callback events, and a lock to protect it. */
98 static SIMPLEQ_HEAD(, xs_stored_msg
) watch_events
=
99 SIMPLEQ_HEAD_INITIALIZER(watch_events
);
100 static struct simplelock watch_events_lock
= SIMPLELOCK_INITIALIZER
;
103 get_error(const char *errorstring
)
107 for (i
= 0; !streq(errorstring
, xsd_errors
[i
].errstring
); i
++) {
108 if (i
== (sizeof(xsd_errors
) / sizeof(xsd_errors
[0]) - 1)) {
110 "XENBUS xen store gave: unknown error %s",
115 return xsd_errors
[i
].errnum
;
119 read_reply(enum xsd_sockmsg_type
*type
, unsigned int *len
)
121 struct xs_stored_msg
*msg
;
125 simple_lock(&xs_state
.reply_lock
);
128 while (SIMPLEQ_EMPTY(&xs_state
.reply_list
)) {
129 ltsleep(&xs_state
.reply_list
, PRIBIO
, "rplq", 0,
130 &xs_state
.reply_lock
);
133 msg
= SIMPLEQ_FIRST(&xs_state
.reply_list
);
134 SIMPLEQ_REMOVE_HEAD(&xs_state
.reply_list
, msg_next
);
137 simple_unlock(&xs_state
.reply_lock
);
139 *type
= msg
->hdr
.type
;
142 body
= msg
->u
.reply
.body
;
143 DPRINTK("read_reply: type %d body %s",
144 msg
->hdr
.type
, body
);
152 /* Emergency write. */
154 xenbus_debug_write(const char *str
, unsigned int count
)
156 struct xsd_sockmsg msg
= { 0 };
159 msg
.len
= sizeof("print") + count
+ 1;
161 xb_write(&msg
, sizeof(msg
));
162 xb_write("print", sizeof("print"));
163 xb_write(str
, count
);
169 xenbus_dev_request_and_reply(struct xsd_sockmsg
*msg
, void**reply
)
174 mutex_enter(&xs_state
.xs_lock
);
175 err
= xb_write(msg
, sizeof(*msg
) + msg
->len
);
177 msg
->type
= XS_ERROR
;
180 *reply
= read_reply(&msg
->type
, &msg
->len
);
182 mutex_exit(&xs_state
.xs_lock
);
188 /* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */
190 xs_talkv(struct xenbus_transaction
*t
,
191 enum xsd_sockmsg_type type
,
192 const struct iovec
*iovec
,
193 unsigned int num_vecs
,
197 struct xsd_sockmsg msg
;
202 msg
.tx_id
= (uint32_t)(unsigned long)t
;
206 for (i
= 0; i
< num_vecs
; i
++)
207 msg
.len
+= iovec
[i
].iov_len
;
210 mutex_enter(&xs_state
.xs_lock
);
212 DPRINTK("write msg");
213 err
= xb_write(&msg
, sizeof(msg
));
214 DPRINTK("write msg err %d", err
);
216 mutex_exit(&xs_state
.xs_lock
);
221 for (i
= 0; i
< num_vecs
; i
++) {
222 DPRINTK("write iovect");
223 err
= xb_write(iovec
[i
].iov_base
, iovec
[i
].iov_len
);
224 DPRINTK("write iovect err %d", err
);
226 mutex_exit(&xs_state
.xs_lock
);
233 ret
= read_reply(&msg
.type
, len
);
234 DPRINTK("read done");
236 mutex_exit(&xs_state
.xs_lock
);
239 if (msg
.type
== XS_ERROR
) {
240 err
= get_error(ret
);
245 KASSERT(msg
.type
== type
);
253 /* Simplified version of xs_talkv: single message. */
255 xs_single(struct xenbus_transaction
*t
,
256 enum xsd_sockmsg_type type
,
263 /* xs_talkv only reads iovec */
264 iovec
.iov_base
= __UNCONST(string
);
265 iovec
.iov_len
= strlen(string
) + 1;
266 return xs_talkv(t
, type
, &iovec
, 1, len
, ret
);
270 count_strings(const char *strings
, unsigned int len
)
275 for (p
= strings
, num
= 0; p
< strings
+ len
; p
+= strlen(p
) + 1)
281 /* Return the path to dir with /name appended. Buffer must be kfree()'ed. */
283 join(const char *dir
, const char *name
)
287 buffer
= malloc(strlen(dir
) + strlen("/") + strlen(name
) + 1,
293 if (!streq(name
, "")) {
295 strcat(buffer
, name
);
302 split(char *strings
, unsigned int len
, unsigned int *num
)
306 /* Count the strings. */
307 *num
= count_strings(strings
, len
);
309 /* Transfer to one big alloc for easy freeing. */
310 ret
= malloc(*num
* sizeof(char *) + len
, M_DEVBUF
, M_NOWAIT
);
312 free(strings
, M_DEVBUF
);
315 memcpy(&ret
[*num
], strings
, len
);
316 free(strings
, M_DEVBUF
);
318 strings
= (char *)&ret
[*num
];
319 for (p
= strings
, *num
= 0; p
< strings
+ len
; p
+= strlen(p
) + 1)
326 xenbus_directory(struct xenbus_transaction
*t
,
327 const char *dir
, const char *node
, unsigned int *num
,
330 char *strings
, *path
;
334 path
= join(dir
, node
);
338 err
= xs_single(t
, XS_DIRECTORY
, path
, &len
, &strings
);
339 DPRINTK("xs_single %d %d", err
, len
);
340 free(path
, M_DEVBUF
);
344 DPRINTK("xs_single strings %s", strings
);
345 *retbuf
= split(strings
, len
, num
);
351 /* Check if a path exists. Return 1 if it does. */
353 xenbus_exists(struct xenbus_transaction
*t
,
354 const char *dir
, const char *node
)
359 err
= xenbus_directory(t
, dir
, node
, &dir_n
, &d
);
366 /* Get the value of a single file.
367 * Returns a kmalloced value: call free() on it after use.
368 * len indicates length in bytes.
371 xenbus_read(struct xenbus_transaction
*t
,
372 const char *dir
, const char *node
, unsigned int *len
,
378 path
= join(dir
, node
);
382 err
= xs_single(t
, XS_READ
, path
, len
, ret
);
383 free(path
, M_DEVBUF
);
387 /* Read a node and convert it to unsigned long. */
389 xenbus_read_ul(struct xenbus_transaction
*t
,
390 const char *dir
, const char *node
, unsigned long *val
,
396 err
= xenbus_read(t
, dir
, node
, NULL
, &string
);
399 *val
= strtoul(string
, &ep
, base
);
401 free(string
, M_DEVBUF
);
404 free(string
, M_DEVBUF
);
408 /* Read a node and convert it to unsigned long long. */
410 xenbus_read_ull(struct xenbus_transaction
*t
,
411 const char *dir
, const char *node
, unsigned long long *val
,
417 err
= xenbus_read(t
, dir
, node
, NULL
, &string
);
420 *val
= strtoull(string
, &ep
, base
);
422 free(string
, M_DEVBUF
);
425 free(string
, M_DEVBUF
);
429 /* Write the value of a single file.
430 * Returns -err on failure.
433 xenbus_write(struct xenbus_transaction
*t
,
434 const char *dir
, const char *node
, const char *string
)
437 struct iovec iovec
[2];
440 path
= join(dir
, node
);
444 /* xs_talkv only reads iovec */
445 iovec
[0].iov_base
= __UNCONST(path
);
446 iovec
[0].iov_len
= strlen(path
) + 1;
447 iovec
[1].iov_base
= __UNCONST(string
);
448 iovec
[1].iov_len
= strlen(string
);
450 ret
= xs_talkv(t
, XS_WRITE
, iovec
, 2, NULL
, NULL
);
454 /* Create a new directory. */
456 xenbus_mkdir(struct xenbus_transaction
*t
,
457 const char *dir
, const char *node
)
462 path
= join(dir
, node
);
466 ret
= xs_single(t
, XS_MKDIR
, path
, NULL
, NULL
);
467 free(path
, M_DEVBUF
);
471 /* Destroy a file or directory (directories must be empty). */
472 int xenbus_rm(struct xenbus_transaction
*t
, const char *dir
, const char *node
)
477 path
= join(dir
, node
);
481 ret
= xs_single(t
, XS_RM
, path
, NULL
, NULL
);
482 free(path
, M_DEVBUF
);
486 /* Start a transaction: changes by others will not be seen during this
487 * transaction, and changes will not be visible to others until end.
488 * MUST BE CALLED AT IPL_TTY !
490 struct xenbus_transaction
*
491 xenbus_transaction_start(void)
494 unsigned long id
, err
;
496 err
= xs_single(NULL
, XS_TRANSACTION_START
, "", NULL
, &id_str
);
501 id
= strtoul(id_str
, NULL
, 0);
502 free(id_str
, M_DEVBUF
);
504 return (struct xenbus_transaction
*)id
;
507 /* End a transaction.
508 * If abandon is true, transaction is discarded instead of committed.
509 * MUST BE CALLED AT IPL_TTY !
511 int xenbus_transaction_end(struct xenbus_transaction
*t
, int abort
)
517 strcpy(abortstr
, "F");
519 strcpy(abortstr
, "T");
521 err
= xs_single(t
, XS_TRANSACTION_END
, abortstr
, NULL
, NULL
);
526 /* Single read and scanf: returns -errno or num scanned. */
528 xenbus_scanf(struct xenbus_transaction
*t
,
529 const char *dir
, const char *node
, const char *fmt
, ...)
535 ret
= xenbus_read(t
, dir
, node
, NULL
, &val
);
540 //ret = vsscanf(val, fmt, ap);
542 printf("xb_scanf format %s in %s\n", fmt
, val
);
548 /* Single printf and write: returns -errno or 0. */
550 xenbus_printf(struct xenbus_transaction
*t
,
551 const char *dir
, const char *node
, const char *fmt
, ...)
555 #define PRINTF_BUFFER_SIZE 4096
558 printf_buffer
= malloc(PRINTF_BUFFER_SIZE
, M_DEVBUF
, M_NOWAIT
);
559 if (printf_buffer
== NULL
)
563 ret
= vsnprintf(printf_buffer
, PRINTF_BUFFER_SIZE
, fmt
, ap
);
566 KASSERT(ret
< PRINTF_BUFFER_SIZE
);
567 ret
= xenbus_write(t
, dir
, node
, printf_buffer
);
569 free(printf_buffer
, M_DEVBUF
);
574 /* Takes tuples of names, scanf-style args, and void **, NULL terminated. */
576 xenbus_gather(struct xenbus_transaction
*t
, const char *dir
, ...)
583 while (ret
== 0 && (name
= va_arg(ap
, char *)) != NULL
) {
584 const char *fmt
= va_arg(ap
, char *);
585 void *result
= va_arg(ap
, void *);
588 ret
= xenbus_read(t
, dir
, name
, NULL
, &p
);
592 // XXX if (sscanf(p, fmt, result) == 0)
596 *(char **)result
= p
;
603 xs_watch(const char *path
, const char *token
)
607 /* xs_talkv only reads iovec */
608 iov
[0].iov_base
= __UNCONST(path
);
609 iov
[0].iov_len
= strlen(path
) + 1;
610 iov
[1].iov_base
= __UNCONST(token
);
611 iov
[1].iov_len
= strlen(token
) + 1;
613 return xs_talkv(NULL
, XS_WATCH
, iov
, 2, NULL
, NULL
);
617 xs_unwatch(const char *path
, const char *token
)
621 /* xs_talkv only reads iovec */
622 iov
[0].iov_base
= __UNCONST(path
);
623 iov
[0].iov_len
= strlen(path
) + 1;
624 iov
[1].iov_base
= __UNCONST(token
);
625 iov
[1].iov_len
= strlen(token
) + 1;
627 return xs_talkv(NULL
, XS_UNWATCH
, iov
, 2, NULL
, NULL
);
630 static struct xenbus_watch
*
631 find_watch(const char *token
)
633 struct xenbus_watch
*i
, *cmp
;
635 cmp
= (void *)strtoul(token
, NULL
, 16);
637 SLIST_FOREACH(i
, &watches
, watch_next
) {
645 /* Register callback to watch this node. */
647 register_xenbus_watch(struct xenbus_watch
*watch
)
649 /* Pointer in ascii is the token. */
650 char token
[sizeof(watch
) * 2 + 1];
654 snprintf(token
, sizeof(token
), "%lX", (long)watch
);
658 simple_lock(&watches_lock
);
659 KASSERT(find_watch(token
) == 0);
660 SLIST_INSERT_HEAD(&watches
, watch
, watch_next
);
661 simple_unlock(&watches_lock
);
663 err
= xs_watch(watch
->node
, token
);
665 /* Ignore errors due to multiple registration. */
666 if ((err
!= 0) && (err
!= EEXIST
)) {
667 simple_lock(&watches_lock
);
668 SLIST_REMOVE(&watches
, watch
, xenbus_watch
, watch_next
);
669 simple_unlock(&watches_lock
);
678 unregister_xenbus_watch(struct xenbus_watch
*watch
)
680 struct xs_stored_msg
*msg
, *next_msg
;
681 char token
[sizeof(watch
) * 2 + 1];
684 snprintf(token
, sizeof(token
), "%lX", (long)watch
);
688 simple_lock(&watches_lock
);
689 KASSERT(find_watch(token
));
690 SLIST_REMOVE(&watches
, watch
, xenbus_watch
, watch_next
);
691 simple_unlock(&watches_lock
);
693 err
= xs_unwatch(watch
->node
, token
);
696 "XENBUS Failed to release watch %s: %i\n",
701 /* Cancel pending watch events. */
702 simple_lock(&watch_events_lock
);
703 for (msg
= SIMPLEQ_FIRST(&watch_events
); msg
!= NULL
; msg
= next_msg
) {
704 next_msg
= SIMPLEQ_NEXT(msg
, msg_next
);
705 if (msg
->u
.watch
.handle
!= watch
)
707 SIMPLEQ_REMOVE(&watch_events
, msg
, xs_stored_msg
, msg_next
);
708 free(msg
->u
.watch
.vec
, M_DEVBUF
);
711 simple_unlock(&watch_events_lock
);
718 xs_state
.suspend_spl
= spltty();
724 struct xenbus_watch
*watch
;
725 char token
[sizeof(watch
) * 2 + 1];
726 /* No need for watches_lock: the suspend_mutex is sufficient. */
727 SLIST_FOREACH(watch
, &watches
, watch_next
) {
728 snprintf(token
, sizeof(token
), "%lX", (long)watch
);
729 xs_watch(watch
->node
, token
);
732 splx(xs_state
.suspend_spl
);
736 xenwatch_thread(void *unused
)
738 struct xs_stored_msg
*msg
;
742 tsleep(&watch_events
, PRIBIO
, "evtsq", 0);
743 s
= spltty(); /* to block IPL_CTRL */
744 while (!SIMPLEQ_EMPTY(&watch_events
)) {
745 msg
= SIMPLEQ_FIRST(&watch_events
);
747 simple_lock(&watch_events_lock
);
748 SIMPLEQ_REMOVE_HEAD(&watch_events
, msg_next
);
749 simple_unlock(&watch_events_lock
);
750 DPRINTK("xenwatch_thread: got event");
752 msg
->u
.watch
.handle
->xbw_callback(
754 (const char **)msg
->u
.watch
.vec
,
755 msg
->u
.watch
.vec_size
);
756 free(msg
->u
.watch
.vec
, M_DEVBUF
);
767 struct xs_stored_msg
*msg
;
771 msg
= malloc(sizeof(*msg
), M_DEVBUF
, M_NOWAIT
);
775 err
= xb_read(&msg
->hdr
, sizeof(msg
->hdr
));
776 DPRINTK("xb_read hdr %d", err
);
782 body
= malloc(msg
->hdr
.len
+ 1, M_DEVBUF
, M_NOWAIT
);
788 err
= xb_read(body
, msg
->hdr
.len
);
789 DPRINTK("xb_read body %d", err
);
791 free(body
, M_DEVBUF
);
795 body
[msg
->hdr
.len
] = '\0';
797 if (msg
->hdr
.type
== XS_WATCH_EVENT
) {
798 DPRINTK("process_msg: XS_WATCH_EVENT");
799 msg
->u
.watch
.vec
= split(body
, msg
->hdr
.len
,
800 &msg
->u
.watch
.vec_size
);
801 if (msg
->u
.watch
.vec
== NULL
) {
806 simple_lock(&watches_lock
);
808 msg
->u
.watch
.handle
= find_watch(
809 msg
->u
.watch
.vec
[XS_WATCH_TOKEN
]);
810 if (msg
->u
.watch
.handle
!= NULL
) {
811 simple_lock(&watch_events_lock
);
812 SIMPLEQ_INSERT_TAIL(&watch_events
, msg
, msg_next
);
813 wakeup(&watch_events
);
814 simple_unlock(&watch_events_lock
);
816 free(msg
->u
.watch
.vec
, M_DEVBUF
);
820 simple_unlock(&watches_lock
);
822 DPRINTK("process_msg: type %d body %s", msg
->hdr
.type
, body
);
824 msg
->u
.reply
.body
= body
;
825 simple_lock(&xs_state
.reply_lock
);
827 SIMPLEQ_INSERT_TAIL(&xs_state
.reply_list
, msg
, msg_next
);
829 simple_unlock(&xs_state
.reply_lock
);
830 wakeup(&xs_state
.reply_list
);
837 xenbus_thread(void *unused
)
844 printk("XENBUS error %d while reading message\n", err
);
849 xs_init(device_t dev
)
853 SIMPLEQ_INIT(&xs_state
.reply_list
);
854 simple_lock_init(&xs_state
.reply_lock
);
855 mutex_init(&xs_state
.xs_lock
, MUTEX_DEFAULT
, IPL_NONE
);
857 err
= kthread_create(PRI_NONE
, 0, NULL
, xenwatch_thread
,
858 NULL
, NULL
, "xenwatch");
860 aprint_error_dev(dev
, "kthread_create(xenwatch): %d\n", err
);
864 err
= kthread_create(PRI_NONE
, 0, NULL
, xenbus_thread
,
865 NULL
, NULL
, "xenbus");
867 aprint_error_dev(dev
, "kthread_create(xenbus): %d\n", err
);
876 * c-file-style: "linux"
877 * indent-tabs-mode: t