xref: /netbsd/sys/arch/xen/xenbus/xenbus_xs.c (revision 6550d01e)
1 /* $NetBSD: xenbus_xs.c,v 1.18 2009/04/28 05:44:43 cegger Exp $ */
2 /******************************************************************************
3  * xenbus_xs.c
4  *
5  * This is the kernel equivalent of the "xs" library.  We don't need everything
6  * and we use xenbus_comms for communication.
7  *
8  * Copyright (C) 2005 Rusty Russell, IBM Corporation
9  *
10  * This file may be distributed separately from the Linux kernel, or
11  * incorporated into other software packages, subject to the following license:
12  *
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:
19  *
20  * The above copyright notice and this permission notice shall be included in
21  * all copies or substantial portions of the Software.
22  *
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
29  * IN THE SOFTWARE.
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: xenbus_xs.c,v 1.18 2009/04/28 05:44:43 cegger Exp $");
34 
35 #if 0
36 #define DPRINTK(fmt, args...) \
37     printf("xenbus_xs (%s:%d) " fmt ".\n", __func__, __LINE__, ##args)
38 #else
39 #define DPRINTK(fmt, args...) ((void)0)
40 #endif
41 
42 #include <sys/types.h>
43 #include <sys/null.h>
44 #include <sys/errno.h>
45 #include <sys/malloc.h>
46 #include <sys/systm.h>
47 #include <sys/param.h>
48 #include <sys/proc.h>
49 #include <sys/mutex.h>
50 #include <sys/kthread.h>
51 #include <sys/simplelock.h>
52 
53 #include <machine/stdarg.h>
54 
55 #include <xen/xen.h>	/* for xendomain_is_dom0() */
56 #include <xen/xenbus.h>
57 #include "xenbus_comms.h"
58 
59 #define streq(a, b) (strcmp((a), (b)) == 0)
60 
61 struct xs_stored_msg {
62 	SIMPLEQ_ENTRY(xs_stored_msg) msg_next;
63 
64 	struct xsd_sockmsg hdr;
65 
66 	union {
67 		/* Queued replies. */
68 		struct {
69 			char *body;
70 		} reply;
71 
72 		/* Queued watch events. */
73 		struct {
74 			struct xenbus_watch *handle;
75 			char **vec;
76 			unsigned int vec_size;
77 		} watch;
78 	} u;
79 };
80 
81 struct xs_handle {
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 */
86 	int suspend_spl;
87 
88 };
89 
90 static struct xs_handle xs_state;
91 
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;
96 
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;
101 
102 static int
103 get_error(const char *errorstring)
104 {
105 	unsigned int i;
106 
107 	for (i = 0; !streq(errorstring, xsd_errors[i].errstring); i++) {
108 		if (i == (sizeof(xsd_errors) / sizeof(xsd_errors[0]) - 1)) {
109 			printf(
110 			       "XENBUS xen store gave: unknown error %s",
111 			       errorstring);
112 			return EINVAL;
113 		}
114 	}
115 	return xsd_errors[i].errnum;
116 }
117 
118 static void *
119 read_reply(enum xsd_sockmsg_type *type, unsigned int *len)
120 {
121 	struct xs_stored_msg *msg;
122 	char *body;
123 	int s;
124 
125 	simple_lock(&xs_state.reply_lock);
126 	s = spltty();
127 
128 	while (SIMPLEQ_EMPTY(&xs_state.reply_list)) {
129 		ltsleep(&xs_state.reply_list, PRIBIO, "rplq", 0,
130 		    &xs_state.reply_lock);
131 	}
132 
133 	msg = SIMPLEQ_FIRST(&xs_state.reply_list);
134 	SIMPLEQ_REMOVE_HEAD(&xs_state.reply_list, msg_next);
135 
136 	splx(s);
137 	simple_unlock(&xs_state.reply_lock);
138 
139 	*type = msg->hdr.type;
140 	if (len)
141 		*len = msg->hdr.len;
142 	body = msg->u.reply.body;
143 	DPRINTK("read_reply: type %d body %s",
144 	    msg->hdr.type, body);
145 
146 	free(msg, M_DEVBUF);
147 
148 	return body;
149 }
150 
151 #if 0
152 /* Emergency write. */
153 void
154 xenbus_debug_write(const char *str, unsigned int count)
155 {
156 	struct xsd_sockmsg msg = { 0 };
157 
158 	msg.type = XS_DEBUG;
159 	msg.len = sizeof("print") + count + 1;
160 
161 	xb_write(&msg, sizeof(msg));
162 	xb_write("print", sizeof("print"));
163 	xb_write(str, count);
164 	xb_write("", 1);
165 }
166 #endif
167 
168 int
169 xenbus_dev_request_and_reply(struct xsd_sockmsg *msg, void**reply)
170 {
171 	int err = 0, s;
172 
173 	s = spltty();
174 	mutex_enter(&xs_state.xs_lock);
175 	err = xb_write(msg, sizeof(*msg) + msg->len);
176 	if (err) {
177 		msg->type = XS_ERROR;
178 		*reply = NULL;
179 	} else {
180 		*reply = read_reply(&msg->type, &msg->len);
181 	}
182 	mutex_exit(&xs_state.xs_lock);
183 	splx(s);
184 
185 	return err;
186 }
187 
188 /* Send message to xs, get kmalloc'ed reply.  ERR_PTR() on error. */
189 static int
190 xs_talkv(struct xenbus_transaction *t,
191 		      enum xsd_sockmsg_type type,
192 		      const struct iovec *iovec,
193 		      unsigned int num_vecs,
194 		      unsigned int *len,
195 		      char **retbuf)
196 {
197 	struct xsd_sockmsg msg;
198 	unsigned int i;
199 	int err, s;
200 	void *ret;
201 
202 	msg.tx_id = (uint32_t)(unsigned long)t;
203 	msg.req_id = 0;
204 	msg.type = type;
205 	msg.len = 0;
206 	for (i = 0; i < num_vecs; i++)
207 		msg.len += iovec[i].iov_len;
208 
209 	s = spltty();
210 	mutex_enter(&xs_state.xs_lock);
211 
212 	DPRINTK("write msg");
213 	err = xb_write(&msg, sizeof(msg));
214 	DPRINTK("write msg err %d", err);
215 	if (err) {
216 		mutex_exit(&xs_state.xs_lock);
217 		splx(s);
218 		return (err);
219 	}
220 
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);
225 		if (err) {
226 			mutex_exit(&xs_state.xs_lock);
227 			splx(s);
228 			return (err);
229 		}
230 	}
231 
232 	DPRINTK("read");
233 	ret = read_reply(&msg.type, len);
234 	DPRINTK("read done");
235 
236 	mutex_exit(&xs_state.xs_lock);
237 	splx(s);
238 
239 	if (msg.type == XS_ERROR) {
240 		err = get_error(ret);
241 		free(ret, M_DEVBUF);
242 		return (err);
243 	}
244 
245 	KASSERT(msg.type == type);
246 	if (retbuf != NULL)
247 		*retbuf = ret;
248 	else
249 		free(ret, M_DEVBUF);
250 	return 0;
251 }
252 
253 /* Simplified version of xs_talkv: single message. */
254 static int
255 xs_single(struct xenbus_transaction *t,
256 		       enum xsd_sockmsg_type type,
257 		       const char *string,
258 		       unsigned int *len,
259 		       char **ret)
260 {
261 	struct iovec iovec;
262 
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);
267 }
268 
269 static unsigned int
270 count_strings(const char *strings, unsigned int len)
271 {
272 	unsigned int num;
273 	const char *p;
274 
275 	for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1)
276 		num++;
277 
278 	return num;
279 }
280 
281 /* Return the path to dir with /name appended. Buffer must be kfree()'ed. */
282 static char *
283 join(const char *dir, const char *name)
284 {
285 	char *buffer;
286 
287 	buffer = malloc(strlen(dir) + strlen("/") + strlen(name) + 1,
288 			 M_DEVBUF, M_NOWAIT);
289 	if (buffer == NULL)
290 		return NULL;
291 
292 	strcpy(buffer, dir);
293 	if (!streq(name, "")) {
294 		strcat(buffer, "/");
295 		strcat(buffer, name);
296 	}
297 
298 	return buffer;
299 }
300 
301 static char **
302 split(char *strings, unsigned int len, unsigned int *num)
303 {
304 	char *p, **ret;
305 
306 	/* Count the strings. */
307 	*num = count_strings(strings, len);
308 
309 	/* Transfer to one big alloc for easy freeing. */
310 	ret = malloc(*num * sizeof(char *) + len, M_DEVBUF, M_NOWAIT);
311 	if (!ret) {
312 		free(strings, M_DEVBUF);
313 		return NULL;
314 	}
315 	memcpy(&ret[*num], strings, len);
316 	free(strings, M_DEVBUF);
317 
318 	strings = (char *)&ret[*num];
319 	for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1)
320 		ret[(*num)++] = p;
321 
322 	return ret;
323 }
324 
325 int
326 xenbus_directory(struct xenbus_transaction *t,
327 			const char *dir, const char *node, unsigned int *num,
328 			char ***retbuf)
329 {
330 	char *strings, *path;
331 	unsigned int len;
332 	int err;
333 
334 	path = join(dir, node);
335 	if (path == NULL)
336 		return ENOMEM;
337 
338 	err = xs_single(t, XS_DIRECTORY, path, &len, &strings);
339 	DPRINTK("xs_single %d %d", err, len);
340 	free(path, M_DEVBUF);
341 	if (err)
342 		return err;
343 
344 	DPRINTK("xs_single strings %s", strings);
345 	*retbuf = split(strings, len, num);
346 	if (*retbuf == NULL)
347 		return ENOMEM;
348 	return 0;
349 }
350 
351 /* Check if a path exists. Return 1 if it does. */
352 int
353 xenbus_exists(struct xenbus_transaction *t,
354 		  const char *dir, const char *node)
355 {
356 	char **d;
357 	int dir_n, err;
358 
359 	err = xenbus_directory(t, dir, node, &dir_n, &d);
360 	if (err)
361 		return 0;
362 	free(d, M_DEVBUF);
363 	return 1;
364 }
365 
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.
369  */
370 int
371 xenbus_read(struct xenbus_transaction *t,
372 		  const char *dir, const char *node, unsigned int *len,
373 		  char **ret)
374 {
375 	char *path;
376 	int err;
377 
378 	path = join(dir, node);
379 	if (path == NULL)
380 		return ENOMEM;
381 
382 	err = xs_single(t, XS_READ, path, len, ret);
383 	free(path, M_DEVBUF);
384 	return err;
385 }
386 
387 /* Read a node and convert it to unsigned long. */
388 int
389 xenbus_read_ul(struct xenbus_transaction *t,
390 		  const char *dir, const char *node, unsigned long *val,
391 		  int base)
392 {
393 	char *string, *ep;
394 	int err;
395 
396 	err = xenbus_read(t, dir, node, NULL, &string);
397 	if (err)
398 		return err;
399 	*val = strtoul(string, &ep, base);
400 	if (*ep != '\0') {
401 		free(string, M_DEVBUF);
402 		return EFTYPE;
403 	}
404 	free(string, M_DEVBUF);
405 	return 0;
406 }
407 
408 /* Read a node and convert it to unsigned long long. */
409 int
410 xenbus_read_ull(struct xenbus_transaction *t,
411 		  const char *dir, const char *node, unsigned long long *val,
412 		  int base)
413 {
414 	char *string, *ep;
415 	int err;
416 
417 	err = xenbus_read(t, dir, node, NULL, &string);
418 	if (err)
419 		return err;
420 	*val = strtoull(string, &ep, base);
421 	if (*ep != '\0') {
422 		free(string, M_DEVBUF);
423 		return EFTYPE;
424 	}
425 	free(string, M_DEVBUF);
426 	return 0;
427 }
428 
429 /* Write the value of a single file.
430  * Returns -err on failure.
431  */
432 int
433 xenbus_write(struct xenbus_transaction *t,
434 		 const char *dir, const char *node, const char *string)
435 {
436 	const char *path;
437 	struct iovec iovec[2];
438 	int ret;
439 
440 	path = join(dir, node);
441 	if (path == NULL)
442 		return ENOMEM;
443 
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);
449 
450 	ret = xs_talkv(t, XS_WRITE, iovec, 2, NULL, NULL);
451 	return ret;
452 }
453 
454 /* Create a new directory. */
455 int
456 xenbus_mkdir(struct xenbus_transaction *t,
457 		 const char *dir, const char *node)
458 {
459 	char *path;
460 	int ret;
461 
462 	path = join(dir, node);
463 	if (path == NULL)
464 		return ENOMEM;
465 
466 	ret = xs_single(t, XS_MKDIR, path, NULL, NULL);
467 	free(path, M_DEVBUF);
468 	return ret;
469 }
470 
471 /* Destroy a file or directory (directories must be empty). */
472 int xenbus_rm(struct xenbus_transaction *t, const char *dir, const char *node)
473 {
474 	char *path;
475 	int ret;
476 
477 	path = join(dir, node);
478 	if (path == NULL)
479 		return ENOMEM;
480 
481 	ret = xs_single(t, XS_RM, path, NULL, NULL);
482 	free(path, M_DEVBUF);
483 	return ret;
484 }
485 
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 !
489  */
490 struct xenbus_transaction *
491 xenbus_transaction_start(void)
492 {
493 	char *id_str;
494 	unsigned long id, err;
495 
496 	err = xs_single(NULL, XS_TRANSACTION_START, "", NULL, &id_str);
497 	if (err) {
498 		return NULL;
499 	}
500 
501 	id = strtoul(id_str, NULL, 0);
502 	free(id_str, M_DEVBUF);
503 
504 	return (struct xenbus_transaction *)id;
505 }
506 
507 /* End a transaction.
508  * If abandon is true, transaction is discarded instead of committed.
509  * MUST BE CALLED AT IPL_TTY !
510  */
511 int xenbus_transaction_end(struct xenbus_transaction *t, int abort)
512 {
513 	char abortstr[2];
514 	int err;
515 
516 	if (abort)
517 		strcpy(abortstr, "F");
518 	else
519 		strcpy(abortstr, "T");
520 
521 	err = xs_single(t, XS_TRANSACTION_END, abortstr, NULL, NULL);
522 
523 	return err;
524 }
525 
526 /* Single read and scanf: returns -errno or num scanned. */
527 int
528 xenbus_scanf(struct xenbus_transaction *t,
529 		 const char *dir, const char *node, const char *fmt, ...)
530 {
531 	va_list ap;
532 	int ret;
533 	char *val;
534 
535 	ret = xenbus_read(t, dir, node, NULL, &val);
536 	if (ret)
537 		return ret;
538 
539 	va_start(ap, fmt);
540 	//ret = vsscanf(val, fmt, ap);
541 	ret = ENXIO;
542 	printf("xb_scanf format %s in %s\n", fmt, val);
543 	va_end(ap);
544 	free(val, M_DEVBUF);
545 	return ret;
546 }
547 
548 /* Single printf and write: returns -errno or 0. */
549 int
550 xenbus_printf(struct xenbus_transaction *t,
551 		  const char *dir, const char *node, const char *fmt, ...)
552 {
553 	va_list ap;
554 	int ret;
555 #define PRINTF_BUFFER_SIZE 4096
556 	char *printf_buffer;
557 
558 	printf_buffer = malloc(PRINTF_BUFFER_SIZE, M_DEVBUF, M_NOWAIT);
559 	if (printf_buffer == NULL)
560 		return ENOMEM;
561 
562 	va_start(ap, fmt);
563 	ret = vsnprintf(printf_buffer, PRINTF_BUFFER_SIZE, fmt, ap);
564 	va_end(ap);
565 
566 	KASSERT(ret < PRINTF_BUFFER_SIZE);
567 	ret = xenbus_write(t, dir, node, printf_buffer);
568 
569 	free(printf_buffer, M_DEVBUF);
570 
571 	return ret;
572 }
573 
574 /* Takes tuples of names, scanf-style args, and void **, NULL terminated. */
575 int
576 xenbus_gather(struct xenbus_transaction *t, const char *dir, ...)
577 {
578 	va_list ap;
579 	const char *name;
580 	int ret = 0;
581 
582 	va_start(ap, 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 *);
586 		char *p;
587 
588 		ret = xenbus_read(t, dir, name, NULL, &p);
589 		if (ret)
590 			break;
591 		if (fmt) {
592 			// XXX if (sscanf(p, fmt, result) == 0)
593 				ret = -EINVAL;
594 			free(p, M_DEVBUF);
595 		} else
596 			*(char **)result = p;
597 	}
598 	va_end(ap);
599 	return ret;
600 }
601 
602 static int
603 xs_watch(const char *path, const char *token)
604 {
605 	struct iovec iov[2];
606 
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;
612 
613 	return xs_talkv(NULL, XS_WATCH, iov, 2, NULL, NULL);
614 }
615 
616 static int
617 xs_unwatch(const char *path, const char *token)
618 {
619 	struct iovec iov[2];
620 
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;
626 
627 	return xs_talkv(NULL, XS_UNWATCH, iov, 2, NULL, NULL);
628 }
629 
630 static struct xenbus_watch *
631 find_watch(const char *token)
632 {
633 	struct xenbus_watch *i, *cmp;
634 
635 	cmp = (void *)strtoul(token, NULL, 16);
636 
637 	SLIST_FOREACH(i, &watches, watch_next) {
638 		if (i == cmp)
639 			return i;
640 	}
641 
642 	return NULL;
643 }
644 
645 /* Register callback to watch this node. */
646 int
647 register_xenbus_watch(struct xenbus_watch *watch)
648 {
649 	/* Pointer in ascii is the token. */
650 	char token[sizeof(watch) * 2 + 1];
651 	int err;
652 	int s;
653 
654 	snprintf(token, sizeof(token), "%lX", (long)watch);
655 
656 	s = spltty();
657 
658 	simple_lock(&watches_lock);
659 	KASSERT(find_watch(token) == 0);
660 	SLIST_INSERT_HEAD(&watches, watch, watch_next);
661 	simple_unlock(&watches_lock);
662 
663 	err = xs_watch(watch->node, token);
664 
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);
670 	}
671 
672 	splx(s);
673 
674 	return err;
675 }
676 
677 void
678 unregister_xenbus_watch(struct xenbus_watch *watch)
679 {
680 	struct xs_stored_msg *msg, *next_msg;
681 	char token[sizeof(watch) * 2 + 1];
682 	int err, s;
683 
684 	snprintf(token, sizeof(token), "%lX", (long)watch);
685 
686 	s = spltty();
687 
688 	simple_lock(&watches_lock);
689 	KASSERT(find_watch(token));
690 	SLIST_REMOVE(&watches, watch, xenbus_watch, watch_next);
691 	simple_unlock(&watches_lock);
692 
693 	err = xs_unwatch(watch->node, token);
694 	if (err)
695 		printf(
696 		       "XENBUS Failed to release watch %s: %i\n",
697 		       watch->node, err);
698 
699 	splx(s);
700 
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)
706 			continue;
707 		SIMPLEQ_REMOVE(&watch_events, msg, xs_stored_msg, msg_next);
708 		free(msg->u.watch.vec, M_DEVBUF);
709 		free(msg, M_DEVBUF);
710 	}
711 	simple_unlock(&watch_events_lock);
712 
713 }
714 
715 void
716 xs_suspend(void)
717 {
718 	xs_state.suspend_spl = spltty();
719 }
720 
721 void
722 xs_resume(void)
723 {
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);
730 	}
731 
732 	splx(xs_state.suspend_spl);
733 }
734 
735 static void
736 xenwatch_thread(void *unused)
737 {
738 	struct xs_stored_msg *msg;
739 	int s;
740 
741 	for (;;) {
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);
746 
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");
751 
752 			msg->u.watch.handle->xbw_callback(
753 				msg->u.watch.handle,
754 				(const char **)msg->u.watch.vec,
755 				msg->u.watch.vec_size);
756 			free(msg->u.watch.vec, M_DEVBUF);
757 			free(msg, M_DEVBUF);
758 		}
759 
760 		splx(s);
761 	}
762 }
763 
764 static int
765 process_msg(void)
766 {
767 	struct xs_stored_msg *msg;
768 	char *body;
769 	int err, s;
770 
771 	msg = malloc(sizeof(*msg), M_DEVBUF, M_NOWAIT);
772 	if (msg == NULL)
773 		return ENOMEM;
774 
775 	err = xb_read(&msg->hdr, sizeof(msg->hdr));
776 	DPRINTK("xb_read hdr %d", err);
777 	if (err) {
778 		free(msg, M_DEVBUF);
779 		return err;
780 	}
781 
782 	body = malloc(msg->hdr.len + 1, M_DEVBUF, M_NOWAIT);
783 	if (body == NULL) {
784 		free(msg, M_DEVBUF);
785 		return ENOMEM;
786 	}
787 
788 	err = xb_read(body, msg->hdr.len);
789 	DPRINTK("xb_read body %d", err);
790 	if (err) {
791 		free(body, M_DEVBUF);
792 		free(msg, M_DEVBUF);
793 		return err;
794 	}
795 	body[msg->hdr.len] = '\0';
796 
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) {
802 			free(msg, M_DEVBUF);
803 			return ENOMEM;
804 		}
805 
806 		simple_lock(&watches_lock);
807 		s = spltty();
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);
815 		} else {
816 			free(msg->u.watch.vec, M_DEVBUF);
817 			free(msg, M_DEVBUF);
818 		}
819 		splx(s);
820 		simple_unlock(&watches_lock);
821 	} else {
822 		DPRINTK("process_msg: type %d body %s", msg->hdr.type, body);
823 
824 		msg->u.reply.body = body;
825 		simple_lock(&xs_state.reply_lock);
826 		s = spltty();
827 		SIMPLEQ_INSERT_TAIL(&xs_state.reply_list, msg, msg_next);
828 		splx(s);
829 		simple_unlock(&xs_state.reply_lock);
830 		wakeup(&xs_state.reply_list);
831 	}
832 
833 	return 0;
834 }
835 
836 static void
837 xenbus_thread(void *unused)
838 {
839 	int err;
840 
841 	for (;;) {
842 		err = process_msg();
843 		if (err)
844 			printk("XENBUS error %d while reading message\n", err);
845 	}
846 }
847 
848 int
849 xs_init(device_t dev)
850 {
851 	int err;
852 
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);
856 
857 	err = kthread_create(PRI_NONE, 0, NULL, xenwatch_thread,
858 	    NULL, NULL, "xenwatch");
859 	if (err) {
860 		aprint_error_dev(dev, "kthread_create(xenwatch): %d\n", err);
861 		return err;
862 	}
863 
864 	err = kthread_create(PRI_NONE, 0, NULL, xenbus_thread,
865 	    NULL, NULL, "xenbus");
866 	if (err) {
867 		aprint_error_dev(dev, "kthread_create(xenbus): %d\n", err);
868 		return err;
869 	}
870 
871 	return 0;
872 }
873 
874 /*
875  * Local variables:
876  *  c-file-style: "linux"
877  *  indent-tabs-mode: t
878  *  c-indent-level: 8
879  *  c-basic-offset: 8
880  *  tab-width: 8
881  * End:
882  */
883