xref: /freebsd/sys/dev/xen/xenstore/xenstore.c (revision a6aedc5d49025f8bb5d2b675d3748aa402ffb879)
1*a6aedc5dSRoger Pau Monné /******************************************************************************
2*a6aedc5dSRoger Pau Monné  * xenstore.c
3*a6aedc5dSRoger Pau Monné  *
4*a6aedc5dSRoger Pau Monné  * Low-level kernel interface to the XenStore.
5*a6aedc5dSRoger Pau Monné  *
6*a6aedc5dSRoger Pau Monné  * Copyright (C) 2005 Rusty Russell, IBM Corporation
7*a6aedc5dSRoger Pau Monné  * Copyright (C) 2009,2010 Spectra Logic Corporation
8*a6aedc5dSRoger Pau Monné  *
9*a6aedc5dSRoger Pau Monné  * This file may be distributed separately from the Linux kernel, or
10*a6aedc5dSRoger Pau Monné  * incorporated into other software packages, subject to the following license:
11*a6aedc5dSRoger Pau Monné  *
12*a6aedc5dSRoger Pau Monné  * Permission is hereby granted, free of charge, to any person obtaining a copy
13*a6aedc5dSRoger Pau Monné  * of this source file (the "Software"), to deal in the Software without
14*a6aedc5dSRoger Pau Monné  * restriction, including without limitation the rights to use, copy, modify,
15*a6aedc5dSRoger Pau Monné  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
16*a6aedc5dSRoger Pau Monné  * and to permit persons to whom the Software is furnished to do so, subject to
17*a6aedc5dSRoger Pau Monné  * the following conditions:
18*a6aedc5dSRoger Pau Monné  *
19*a6aedc5dSRoger Pau Monné  * The above copyright notice and this permission notice shall be included in
20*a6aedc5dSRoger Pau Monné  * all copies or substantial portions of the Software.
21*a6aedc5dSRoger Pau Monné  *
22*a6aedc5dSRoger Pau Monné  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23*a6aedc5dSRoger Pau Monné  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24*a6aedc5dSRoger Pau Monné  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25*a6aedc5dSRoger Pau Monné  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26*a6aedc5dSRoger Pau Monné  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27*a6aedc5dSRoger Pau Monné  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
28*a6aedc5dSRoger Pau Monné  * IN THE SOFTWARE.
29*a6aedc5dSRoger Pau Monné  */
30*a6aedc5dSRoger Pau Monné 
31*a6aedc5dSRoger Pau Monné 
32*a6aedc5dSRoger Pau Monné #include <sys/cdefs.h>
33*a6aedc5dSRoger Pau Monné __FBSDID("$FreeBSD$");
34*a6aedc5dSRoger Pau Monné 
35*a6aedc5dSRoger Pau Monné #include <sys/param.h>
36*a6aedc5dSRoger Pau Monné #include <sys/bus.h>
37*a6aedc5dSRoger Pau Monné #include <sys/kernel.h>
38*a6aedc5dSRoger Pau Monné #include <sys/lock.h>
39*a6aedc5dSRoger Pau Monné #include <sys/module.h>
40*a6aedc5dSRoger Pau Monné #include <sys/mutex.h>
41*a6aedc5dSRoger Pau Monné #include <sys/sx.h>
42*a6aedc5dSRoger Pau Monné #include <sys/syslog.h>
43*a6aedc5dSRoger Pau Monné #include <sys/malloc.h>
44*a6aedc5dSRoger Pau Monné #include <sys/systm.h>
45*a6aedc5dSRoger Pau Monné #include <sys/proc.h>
46*a6aedc5dSRoger Pau Monné #include <sys/kthread.h>
47*a6aedc5dSRoger Pau Monné #include <sys/sbuf.h>
48*a6aedc5dSRoger Pau Monné #include <sys/sysctl.h>
49*a6aedc5dSRoger Pau Monné #include <sys/uio.h>
50*a6aedc5dSRoger Pau Monné #include <sys/unistd.h>
51*a6aedc5dSRoger Pau Monné 
52*a6aedc5dSRoger Pau Monné #include <machine/stdarg.h>
53*a6aedc5dSRoger Pau Monné 
54*a6aedc5dSRoger Pau Monné #include <xen/xen-os.h>
55*a6aedc5dSRoger Pau Monné #include <xen/hypervisor.h>
56*a6aedc5dSRoger Pau Monné #include <xen/xen_intr.h>
57*a6aedc5dSRoger Pau Monné 
58*a6aedc5dSRoger Pau Monné #include <xen/interface/hvm/params.h>
59*a6aedc5dSRoger Pau Monné #include <xen/hvm.h>
60*a6aedc5dSRoger Pau Monné 
61*a6aedc5dSRoger Pau Monné #include <xen/xenstore/xenstorevar.h>
62*a6aedc5dSRoger Pau Monné #include <xen/xenstore/xenstore_internal.h>
63*a6aedc5dSRoger Pau Monné 
64*a6aedc5dSRoger Pau Monné #include <vm/vm.h>
65*a6aedc5dSRoger Pau Monné #include <vm/pmap.h>
66*a6aedc5dSRoger Pau Monné 
67*a6aedc5dSRoger Pau Monné /**
68*a6aedc5dSRoger Pau Monné  * \file xenstore.c
69*a6aedc5dSRoger Pau Monné  * \brief XenStore interface
70*a6aedc5dSRoger Pau Monné  *
71*a6aedc5dSRoger Pau Monné  * The XenStore interface is a simple storage system that is a means of
72*a6aedc5dSRoger Pau Monné  * communicating state and configuration data between the Xen Domain 0
73*a6aedc5dSRoger Pau Monné  * and the various guest domains.  All configuration data other than
74*a6aedc5dSRoger Pau Monné  * a small amount of essential information required during the early
75*a6aedc5dSRoger Pau Monné  * boot process of launching a Xen aware guest, is managed using the
76*a6aedc5dSRoger Pau Monné  * XenStore.
77*a6aedc5dSRoger Pau Monné  *
78*a6aedc5dSRoger Pau Monné  * The XenStore is ASCII string based, and has a structure and semantics
79*a6aedc5dSRoger Pau Monné  * similar to a filesystem.  There are files and directories, the directories
80*a6aedc5dSRoger Pau Monné  * able to contain files or other directories.  The depth of the hierachy
81*a6aedc5dSRoger Pau Monné  * is only limited by the XenStore's maximum path length.
82*a6aedc5dSRoger Pau Monné  *
83*a6aedc5dSRoger Pau Monné  * The communication channel between the XenStore service and other
84*a6aedc5dSRoger Pau Monné  * domains is via two, guest specific, ring buffers in a shared memory
85*a6aedc5dSRoger Pau Monné  * area.  One ring buffer is used for communicating in each direction.
86*a6aedc5dSRoger Pau Monné  * The grant table references for this shared memory are given to the
87*a6aedc5dSRoger Pau Monné  * guest either via the xen_start_info structure for a fully para-
88*a6aedc5dSRoger Pau Monné  * virtualized guest, or via HVM hypercalls for a hardware virtualized
89*a6aedc5dSRoger Pau Monné  * guest.
90*a6aedc5dSRoger Pau Monné  *
91*a6aedc5dSRoger Pau Monné  * The XenStore communication relies on an event channel and thus
92*a6aedc5dSRoger Pau Monné  * interrupts.  For this reason, the attachment of the XenStore
93*a6aedc5dSRoger Pau Monné  * relies on an interrupt driven configuration hook to hold off
94*a6aedc5dSRoger Pau Monné  * boot processing until communication with the XenStore service
95*a6aedc5dSRoger Pau Monné  * can be established.
96*a6aedc5dSRoger Pau Monné  *
97*a6aedc5dSRoger Pau Monné  * Several Xen services depend on the XenStore, most notably the
98*a6aedc5dSRoger Pau Monné  * XenBus used to discover and manage Xen devices.  These services
99*a6aedc5dSRoger Pau Monné  * are implemented as NewBus child attachments to a bus exported
100*a6aedc5dSRoger Pau Monné  * by this XenStore driver.
101*a6aedc5dSRoger Pau Monné  */
102*a6aedc5dSRoger Pau Monné 
103*a6aedc5dSRoger Pau Monné static struct xs_watch *find_watch(const char *token);
104*a6aedc5dSRoger Pau Monné 
105*a6aedc5dSRoger Pau Monné MALLOC_DEFINE(M_XENSTORE, "xenstore", "XenStore data and results");
106*a6aedc5dSRoger Pau Monné 
107*a6aedc5dSRoger Pau Monné /**
108*a6aedc5dSRoger Pau Monné  * Pointer to shared memory communication structures allowing us
109*a6aedc5dSRoger Pau Monné  * to communicate with the XenStore service.
110*a6aedc5dSRoger Pau Monné  *
111*a6aedc5dSRoger Pau Monné  * When operating in full PV mode, this pointer is set early in kernel
112*a6aedc5dSRoger Pau Monné  * startup from within xen_machdep.c.  In HVM mode, we use hypercalls
113*a6aedc5dSRoger Pau Monné  * to get the guest frame number for the shared page and then map it
114*a6aedc5dSRoger Pau Monné  * into kva.  See xs_init() for details.
115*a6aedc5dSRoger Pau Monné  */
116*a6aedc5dSRoger Pau Monné struct xenstore_domain_interface *xen_store;
117*a6aedc5dSRoger Pau Monné 
118*a6aedc5dSRoger Pau Monné /*-------------------------- Private Data Structures ------------------------*/
119*a6aedc5dSRoger Pau Monné 
120*a6aedc5dSRoger Pau Monné /**
121*a6aedc5dSRoger Pau Monné  * Structure capturing messages received from the XenStore service.
122*a6aedc5dSRoger Pau Monné  */
123*a6aedc5dSRoger Pau Monné struct xs_stored_msg {
124*a6aedc5dSRoger Pau Monné 	TAILQ_ENTRY(xs_stored_msg) list;
125*a6aedc5dSRoger Pau Monné 
126*a6aedc5dSRoger Pau Monné 	struct xsd_sockmsg hdr;
127*a6aedc5dSRoger Pau Monné 
128*a6aedc5dSRoger Pau Monné 	union {
129*a6aedc5dSRoger Pau Monné 		/* Queued replies. */
130*a6aedc5dSRoger Pau Monné 		struct {
131*a6aedc5dSRoger Pau Monné 			char *body;
132*a6aedc5dSRoger Pau Monné 		} reply;
133*a6aedc5dSRoger Pau Monné 
134*a6aedc5dSRoger Pau Monné 		/* Queued watch events. */
135*a6aedc5dSRoger Pau Monné 		struct {
136*a6aedc5dSRoger Pau Monné 			struct xs_watch *handle;
137*a6aedc5dSRoger Pau Monné 			const char **vec;
138*a6aedc5dSRoger Pau Monné 			u_int vec_size;
139*a6aedc5dSRoger Pau Monné 		} watch;
140*a6aedc5dSRoger Pau Monné 	} u;
141*a6aedc5dSRoger Pau Monné };
142*a6aedc5dSRoger Pau Monné TAILQ_HEAD(xs_stored_msg_list, xs_stored_msg);
143*a6aedc5dSRoger Pau Monné 
144*a6aedc5dSRoger Pau Monné /**
145*a6aedc5dSRoger Pau Monné  * Container for all XenStore related state.
146*a6aedc5dSRoger Pau Monné  */
147*a6aedc5dSRoger Pau Monné struct xs_softc {
148*a6aedc5dSRoger Pau Monné 	/** Newbus device for the XenStore. */
149*a6aedc5dSRoger Pau Monné 	device_t xs_dev;
150*a6aedc5dSRoger Pau Monné 
151*a6aedc5dSRoger Pau Monné 	/**
152*a6aedc5dSRoger Pau Monné 	 * Lock serializing access to ring producer/consumer
153*a6aedc5dSRoger Pau Monné 	 * indexes.  Use of this lock guarantees that wakeups
154*a6aedc5dSRoger Pau Monné 	 * of blocking readers/writers are not missed due to
155*a6aedc5dSRoger Pau Monné 	 * races with the XenStore service.
156*a6aedc5dSRoger Pau Monné 	 */
157*a6aedc5dSRoger Pau Monné 	struct mtx ring_lock;
158*a6aedc5dSRoger Pau Monné 
159*a6aedc5dSRoger Pau Monné 	/*
160*a6aedc5dSRoger Pau Monné 	 * Mutex used to insure exclusive access to the outgoing
161*a6aedc5dSRoger Pau Monné 	 * communication ring.  We use a lock type that can be
162*a6aedc5dSRoger Pau Monné 	 * held while sleeping so that xs_write() can block waiting
163*a6aedc5dSRoger Pau Monné 	 * for space in the ring to free up, without allowing another
164*a6aedc5dSRoger Pau Monné 	 * writer to come in and corrupt a partial message write.
165*a6aedc5dSRoger Pau Monné 	 */
166*a6aedc5dSRoger Pau Monné 	struct sx request_mutex;
167*a6aedc5dSRoger Pau Monné 
168*a6aedc5dSRoger Pau Monné 	/**
169*a6aedc5dSRoger Pau Monné 	 * A list of replies to our requests.
170*a6aedc5dSRoger Pau Monné 	 *
171*a6aedc5dSRoger Pau Monné 	 * The reply list is filled by xs_rcv_thread().  It
172*a6aedc5dSRoger Pau Monné 	 * is consumed by the context that issued the request
173*a6aedc5dSRoger Pau Monné 	 * to which a reply is made.  The requester blocks in
174*a6aedc5dSRoger Pau Monné 	 * xs_read_reply().
175*a6aedc5dSRoger Pau Monné 	 *
176*a6aedc5dSRoger Pau Monné 	 * /note Only one requesting context can be active at a time.
177*a6aedc5dSRoger Pau Monné 	 *       This is guaranteed by the request_mutex and insures
178*a6aedc5dSRoger Pau Monné 	 *	 that the requester sees replies matching the order
179*a6aedc5dSRoger Pau Monné 	 *	 of its requests.
180*a6aedc5dSRoger Pau Monné 	 */
181*a6aedc5dSRoger Pau Monné 	struct xs_stored_msg_list reply_list;
182*a6aedc5dSRoger Pau Monné 
183*a6aedc5dSRoger Pau Monné 	/** Lock protecting the reply list. */
184*a6aedc5dSRoger Pau Monné 	struct mtx reply_lock;
185*a6aedc5dSRoger Pau Monné 
186*a6aedc5dSRoger Pau Monné 	/**
187*a6aedc5dSRoger Pau Monné 	 * List of registered watches.
188*a6aedc5dSRoger Pau Monné 	 */
189*a6aedc5dSRoger Pau Monné 	struct xs_watch_list  registered_watches;
190*a6aedc5dSRoger Pau Monné 
191*a6aedc5dSRoger Pau Monné 	/** Lock protecting the registered watches list. */
192*a6aedc5dSRoger Pau Monné 	struct mtx registered_watches_lock;
193*a6aedc5dSRoger Pau Monné 
194*a6aedc5dSRoger Pau Monné 	/**
195*a6aedc5dSRoger Pau Monné 	 * List of pending watch callback events.
196*a6aedc5dSRoger Pau Monné 	 */
197*a6aedc5dSRoger Pau Monné 	struct xs_stored_msg_list watch_events;
198*a6aedc5dSRoger Pau Monné 
199*a6aedc5dSRoger Pau Monné 	/** Lock protecting the watch calback list. */
200*a6aedc5dSRoger Pau Monné 	struct mtx watch_events_lock;
201*a6aedc5dSRoger Pau Monné 
202*a6aedc5dSRoger Pau Monné 	/**
203*a6aedc5dSRoger Pau Monné 	 * Sleepable lock used to prevent VM suspension while a
204*a6aedc5dSRoger Pau Monné 	 * xenstore transaction is outstanding.
205*a6aedc5dSRoger Pau Monné 	 *
206*a6aedc5dSRoger Pau Monné 	 * Each active transaction holds a shared lock on the
207*a6aedc5dSRoger Pau Monné 	 * suspend mutex.  Our suspend method blocks waiting
208*a6aedc5dSRoger Pau Monné 	 * to acquire an exclusive lock.  This guarantees that
209*a6aedc5dSRoger Pau Monné 	 * suspend processing will only proceed once all active
210*a6aedc5dSRoger Pau Monné 	 * transactions have been retired.
211*a6aedc5dSRoger Pau Monné 	 */
212*a6aedc5dSRoger Pau Monné 	struct sx suspend_mutex;
213*a6aedc5dSRoger Pau Monné 
214*a6aedc5dSRoger Pau Monné 	/**
215*a6aedc5dSRoger Pau Monné 	 * The processid of the xenwatch thread.
216*a6aedc5dSRoger Pau Monné 	 */
217*a6aedc5dSRoger Pau Monné 	pid_t xenwatch_pid;
218*a6aedc5dSRoger Pau Monné 
219*a6aedc5dSRoger Pau Monné 	/**
220*a6aedc5dSRoger Pau Monné 	 * Sleepable mutex used to gate the execution of XenStore
221*a6aedc5dSRoger Pau Monné 	 * watch event callbacks.
222*a6aedc5dSRoger Pau Monné 	 *
223*a6aedc5dSRoger Pau Monné 	 * xenwatch_thread holds an exclusive lock on this mutex
224*a6aedc5dSRoger Pau Monné 	 * while delivering event callbacks, and xenstore_unregister_watch()
225*a6aedc5dSRoger Pau Monné 	 * uses an exclusive lock of this mutex to guarantee that no
226*a6aedc5dSRoger Pau Monné 	 * callbacks of the just unregistered watch are pending
227*a6aedc5dSRoger Pau Monné 	 * before returning to its caller.
228*a6aedc5dSRoger Pau Monné 	 */
229*a6aedc5dSRoger Pau Monné 	struct sx xenwatch_mutex;
230*a6aedc5dSRoger Pau Monné 
231*a6aedc5dSRoger Pau Monné 	/**
232*a6aedc5dSRoger Pau Monné 	 * The HVM guest pseudo-physical frame number.  This is Xen's mapping
233*a6aedc5dSRoger Pau Monné 	 * of the true machine frame number into our "physical address space".
234*a6aedc5dSRoger Pau Monné 	 */
235*a6aedc5dSRoger Pau Monné 	unsigned long gpfn;
236*a6aedc5dSRoger Pau Monné 
237*a6aedc5dSRoger Pau Monné 	/**
238*a6aedc5dSRoger Pau Monné 	 * The event channel for communicating with the
239*a6aedc5dSRoger Pau Monné 	 * XenStore service.
240*a6aedc5dSRoger Pau Monné 	 */
241*a6aedc5dSRoger Pau Monné 	int evtchn;
242*a6aedc5dSRoger Pau Monné 
243*a6aedc5dSRoger Pau Monné 	/** Handle for XenStore interrupts. */
244*a6aedc5dSRoger Pau Monné 	xen_intr_handle_t xen_intr_handle;
245*a6aedc5dSRoger Pau Monné 
246*a6aedc5dSRoger Pau Monné 	/**
247*a6aedc5dSRoger Pau Monné 	 * Interrupt driven config hook allowing us to defer
248*a6aedc5dSRoger Pau Monné 	 * attaching children until interrupts (and thus communication
249*a6aedc5dSRoger Pau Monné 	 * with the XenStore service) are available.
250*a6aedc5dSRoger Pau Monné 	 */
251*a6aedc5dSRoger Pau Monné 	struct intr_config_hook xs_attachcb;
252*a6aedc5dSRoger Pau Monné };
253*a6aedc5dSRoger Pau Monné 
254*a6aedc5dSRoger Pau Monné /*-------------------------------- Global Data ------------------------------*/
255*a6aedc5dSRoger Pau Monné static struct xs_softc xs;
256*a6aedc5dSRoger Pau Monné 
257*a6aedc5dSRoger Pau Monné /*------------------------- Private Utility Functions -----------------------*/
258*a6aedc5dSRoger Pau Monné 
259*a6aedc5dSRoger Pau Monné /**
260*a6aedc5dSRoger Pau Monné  * Count and optionally record pointers to a number of NUL terminated
261*a6aedc5dSRoger Pau Monné  * strings in a buffer.
262*a6aedc5dSRoger Pau Monné  *
263*a6aedc5dSRoger Pau Monné  * \param strings  A pointer to a contiguous buffer of NUL terminated strings.
264*a6aedc5dSRoger Pau Monné  * \param dest	   An array to store pointers to each string found in strings.
265*a6aedc5dSRoger Pau Monné  * \param len	   The length of the buffer pointed to by strings.
266*a6aedc5dSRoger Pau Monné  *
267*a6aedc5dSRoger Pau Monné  * \return  A count of the number of strings found.
268*a6aedc5dSRoger Pau Monné  */
269*a6aedc5dSRoger Pau Monné static u_int
270*a6aedc5dSRoger Pau Monné extract_strings(const char *strings, const char **dest, u_int len)
271*a6aedc5dSRoger Pau Monné {
272*a6aedc5dSRoger Pau Monné 	u_int num;
273*a6aedc5dSRoger Pau Monné 	const char *p;
274*a6aedc5dSRoger Pau Monné 
275*a6aedc5dSRoger Pau Monné 	for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1) {
276*a6aedc5dSRoger Pau Monné 		if (dest != NULL)
277*a6aedc5dSRoger Pau Monné 			*dest++ = p;
278*a6aedc5dSRoger Pau Monné 		num++;
279*a6aedc5dSRoger Pau Monné 	}
280*a6aedc5dSRoger Pau Monné 
281*a6aedc5dSRoger Pau Monné 	return (num);
282*a6aedc5dSRoger Pau Monné }
283*a6aedc5dSRoger Pau Monné 
284*a6aedc5dSRoger Pau Monné /**
285*a6aedc5dSRoger Pau Monné  * Convert a contiguous buffer containing a series of NUL terminated
286*a6aedc5dSRoger Pau Monné  * strings into an array of pointers to strings.
287*a6aedc5dSRoger Pau Monné  *
288*a6aedc5dSRoger Pau Monné  * The returned pointer references the array of string pointers which
289*a6aedc5dSRoger Pau Monné  * is followed by the storage for the string data.  It is the client's
290*a6aedc5dSRoger Pau Monné  * responsibility to free this storage.
291*a6aedc5dSRoger Pau Monné  *
292*a6aedc5dSRoger Pau Monné  * The storage addressed by strings is free'd prior to split returning.
293*a6aedc5dSRoger Pau Monné  *
294*a6aedc5dSRoger Pau Monné  * \param strings  A pointer to a contiguous buffer of NUL terminated strings.
295*a6aedc5dSRoger Pau Monné  * \param len	   The length of the buffer pointed to by strings.
296*a6aedc5dSRoger Pau Monné  * \param num	   The number of strings found and returned in the strings
297*a6aedc5dSRoger Pau Monné  *                 array.
298*a6aedc5dSRoger Pau Monné  *
299*a6aedc5dSRoger Pau Monné  * \return  An array of pointers to the strings found in the input buffer.
300*a6aedc5dSRoger Pau Monné  */
301*a6aedc5dSRoger Pau Monné static const char **
302*a6aedc5dSRoger Pau Monné split(char *strings, u_int len, u_int *num)
303*a6aedc5dSRoger Pau Monné {
304*a6aedc5dSRoger Pau Monné 	const char **ret;
305*a6aedc5dSRoger Pau Monné 
306*a6aedc5dSRoger Pau Monné 	/* Protect against unterminated buffers. */
307*a6aedc5dSRoger Pau Monné 	if (len > 0)
308*a6aedc5dSRoger Pau Monné 		strings[len - 1] = '\0';
309*a6aedc5dSRoger Pau Monné 
310*a6aedc5dSRoger Pau Monné 	/* Count the strings. */
311*a6aedc5dSRoger Pau Monné 	*num = extract_strings(strings, /*dest*/NULL, len);
312*a6aedc5dSRoger Pau Monné 
313*a6aedc5dSRoger Pau Monné 	/* Transfer to one big alloc for easy freeing by the caller. */
314*a6aedc5dSRoger Pau Monné 	ret = malloc(*num * sizeof(char *) + len, M_XENSTORE, M_WAITOK);
315*a6aedc5dSRoger Pau Monné 	memcpy(&ret[*num], strings, len);
316*a6aedc5dSRoger Pau Monné 	free(strings, M_XENSTORE);
317*a6aedc5dSRoger Pau Monné 
318*a6aedc5dSRoger Pau Monné 	/* Extract pointers to newly allocated array. */
319*a6aedc5dSRoger Pau Monné 	strings = (char *)&ret[*num];
320*a6aedc5dSRoger Pau Monné 	(void)extract_strings(strings, /*dest*/ret, len);
321*a6aedc5dSRoger Pau Monné 
322*a6aedc5dSRoger Pau Monné 	return (ret);
323*a6aedc5dSRoger Pau Monné }
324*a6aedc5dSRoger Pau Monné 
325*a6aedc5dSRoger Pau Monné /*------------------------- Public Utility Functions -------------------------*/
326*a6aedc5dSRoger Pau Monné /*------- API comments for these methods can be found in xenstorevar.h -------*/
327*a6aedc5dSRoger Pau Monné struct sbuf *
328*a6aedc5dSRoger Pau Monné xs_join(const char *dir, const char *name)
329*a6aedc5dSRoger Pau Monné {
330*a6aedc5dSRoger Pau Monné 	struct sbuf *sb;
331*a6aedc5dSRoger Pau Monné 
332*a6aedc5dSRoger Pau Monné 	sb = sbuf_new_auto();
333*a6aedc5dSRoger Pau Monné 	sbuf_cat(sb, dir);
334*a6aedc5dSRoger Pau Monné 	if (name[0] != '\0') {
335*a6aedc5dSRoger Pau Monné 		sbuf_putc(sb, '/');
336*a6aedc5dSRoger Pau Monné 		sbuf_cat(sb, name);
337*a6aedc5dSRoger Pau Monné 	}
338*a6aedc5dSRoger Pau Monné 	sbuf_finish(sb);
339*a6aedc5dSRoger Pau Monné 
340*a6aedc5dSRoger Pau Monné 	return (sb);
341*a6aedc5dSRoger Pau Monné }
342*a6aedc5dSRoger Pau Monné 
343*a6aedc5dSRoger Pau Monné /*-------------------- Low Level Communication Management --------------------*/
344*a6aedc5dSRoger Pau Monné /**
345*a6aedc5dSRoger Pau Monné  * Interrupt handler for the XenStore event channel.
346*a6aedc5dSRoger Pau Monné  *
347*a6aedc5dSRoger Pau Monné  * XenStore reads and writes block on "xen_store" for buffer
348*a6aedc5dSRoger Pau Monné  * space.  Wakeup any blocking operations when the XenStore
349*a6aedc5dSRoger Pau Monné  * service has modified the queues.
350*a6aedc5dSRoger Pau Monné  */
351*a6aedc5dSRoger Pau Monné static void
352*a6aedc5dSRoger Pau Monné xs_intr(void * arg __unused /*__attribute__((unused))*/)
353*a6aedc5dSRoger Pau Monné {
354*a6aedc5dSRoger Pau Monné 
355*a6aedc5dSRoger Pau Monné 	/*
356*a6aedc5dSRoger Pau Monné 	 * Hold ring lock across wakeup so that clients
357*a6aedc5dSRoger Pau Monné 	 * cannot miss a wakeup.
358*a6aedc5dSRoger Pau Monné 	 */
359*a6aedc5dSRoger Pau Monné 	mtx_lock(&xs.ring_lock);
360*a6aedc5dSRoger Pau Monné 	wakeup(xen_store);
361*a6aedc5dSRoger Pau Monné 	mtx_unlock(&xs.ring_lock);
362*a6aedc5dSRoger Pau Monné }
363*a6aedc5dSRoger Pau Monné 
364*a6aedc5dSRoger Pau Monné /**
365*a6aedc5dSRoger Pau Monné  * Verify that the indexes for a ring are valid.
366*a6aedc5dSRoger Pau Monné  *
367*a6aedc5dSRoger Pau Monné  * The difference between the producer and consumer cannot
368*a6aedc5dSRoger Pau Monné  * exceed the size of the ring.
369*a6aedc5dSRoger Pau Monné  *
370*a6aedc5dSRoger Pau Monné  * \param cons  The consumer index for the ring to test.
371*a6aedc5dSRoger Pau Monné  * \param prod  The producer index for the ring to test.
372*a6aedc5dSRoger Pau Monné  *
373*a6aedc5dSRoger Pau Monné  * \retval 1  If indexes are in range.
374*a6aedc5dSRoger Pau Monné  * \retval 0  If the indexes are out of range.
375*a6aedc5dSRoger Pau Monné  */
376*a6aedc5dSRoger Pau Monné static int
377*a6aedc5dSRoger Pau Monné xs_check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)
378*a6aedc5dSRoger Pau Monné {
379*a6aedc5dSRoger Pau Monné 
380*a6aedc5dSRoger Pau Monné 	return ((prod - cons) <= XENSTORE_RING_SIZE);
381*a6aedc5dSRoger Pau Monné }
382*a6aedc5dSRoger Pau Monné 
383*a6aedc5dSRoger Pau Monné /**
384*a6aedc5dSRoger Pau Monné  * Return a pointer to, and the length of, the contiguous
385*a6aedc5dSRoger Pau Monné  * free region available for output in a ring buffer.
386*a6aedc5dSRoger Pau Monné  *
387*a6aedc5dSRoger Pau Monné  * \param cons  The consumer index for the ring.
388*a6aedc5dSRoger Pau Monné  * \param prod  The producer index for the ring.
389*a6aedc5dSRoger Pau Monné  * \param buf   The base address of the ring's storage.
390*a6aedc5dSRoger Pau Monné  * \param len   The amount of contiguous storage available.
391*a6aedc5dSRoger Pau Monné  *
392*a6aedc5dSRoger Pau Monné  * \return  A pointer to the start location of the free region.
393*a6aedc5dSRoger Pau Monné  */
394*a6aedc5dSRoger Pau Monné static void *
395*a6aedc5dSRoger Pau Monné xs_get_output_chunk(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod,
396*a6aedc5dSRoger Pau Monné     char *buf, uint32_t *len)
397*a6aedc5dSRoger Pau Monné {
398*a6aedc5dSRoger Pau Monné 
399*a6aedc5dSRoger Pau Monné 	*len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod);
400*a6aedc5dSRoger Pau Monné 	if ((XENSTORE_RING_SIZE - (prod - cons)) < *len)
401*a6aedc5dSRoger Pau Monné 		*len = XENSTORE_RING_SIZE - (prod - cons);
402*a6aedc5dSRoger Pau Monné 	return (buf + MASK_XENSTORE_IDX(prod));
403*a6aedc5dSRoger Pau Monné }
404*a6aedc5dSRoger Pau Monné 
405*a6aedc5dSRoger Pau Monné /**
406*a6aedc5dSRoger Pau Monné  * Return a pointer to, and the length of, the contiguous
407*a6aedc5dSRoger Pau Monné  * data available to read from a ring buffer.
408*a6aedc5dSRoger Pau Monné  *
409*a6aedc5dSRoger Pau Monné  * \param cons  The consumer index for the ring.
410*a6aedc5dSRoger Pau Monné  * \param prod  The producer index for the ring.
411*a6aedc5dSRoger Pau Monné  * \param buf   The base address of the ring's storage.
412*a6aedc5dSRoger Pau Monné  * \param len   The amount of contiguous data available to read.
413*a6aedc5dSRoger Pau Monné  *
414*a6aedc5dSRoger Pau Monné  * \return  A pointer to the start location of the available data.
415*a6aedc5dSRoger Pau Monné  */
416*a6aedc5dSRoger Pau Monné static const void *
417*a6aedc5dSRoger Pau Monné xs_get_input_chunk(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod,
418*a6aedc5dSRoger Pau Monné     const char *buf, uint32_t *len)
419*a6aedc5dSRoger Pau Monné {
420*a6aedc5dSRoger Pau Monné 
421*a6aedc5dSRoger Pau Monné 	*len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons);
422*a6aedc5dSRoger Pau Monné 	if ((prod - cons) < *len)
423*a6aedc5dSRoger Pau Monné 		*len = prod - cons;
424*a6aedc5dSRoger Pau Monné 	return (buf + MASK_XENSTORE_IDX(cons));
425*a6aedc5dSRoger Pau Monné }
426*a6aedc5dSRoger Pau Monné 
427*a6aedc5dSRoger Pau Monné /**
428*a6aedc5dSRoger Pau Monné  * Transmit data to the XenStore service.
429*a6aedc5dSRoger Pau Monné  *
430*a6aedc5dSRoger Pau Monné  * \param tdata  A pointer to the contiguous data to send.
431*a6aedc5dSRoger Pau Monné  * \param len    The amount of data to send.
432*a6aedc5dSRoger Pau Monné  *
433*a6aedc5dSRoger Pau Monné  * \return  On success 0, otherwise an errno value indicating the
434*a6aedc5dSRoger Pau Monné  *          cause of failure.
435*a6aedc5dSRoger Pau Monné  *
436*a6aedc5dSRoger Pau Monné  * \invariant  Called from thread context.
437*a6aedc5dSRoger Pau Monné  * \invariant  The buffer pointed to by tdata is at least len bytes
438*a6aedc5dSRoger Pau Monné  *             in length.
439*a6aedc5dSRoger Pau Monné  * \invariant  xs.request_mutex exclusively locked.
440*a6aedc5dSRoger Pau Monné  */
441*a6aedc5dSRoger Pau Monné static int
442*a6aedc5dSRoger Pau Monné xs_write_store(const void *tdata, unsigned len)
443*a6aedc5dSRoger Pau Monné {
444*a6aedc5dSRoger Pau Monné 	XENSTORE_RING_IDX cons, prod;
445*a6aedc5dSRoger Pau Monné 	const char *data = (const char *)tdata;
446*a6aedc5dSRoger Pau Monné 	int error;
447*a6aedc5dSRoger Pau Monné 
448*a6aedc5dSRoger Pau Monné 	sx_assert(&xs.request_mutex, SX_XLOCKED);
449*a6aedc5dSRoger Pau Monné 	while (len != 0) {
450*a6aedc5dSRoger Pau Monné 		void *dst;
451*a6aedc5dSRoger Pau Monné 		u_int avail;
452*a6aedc5dSRoger Pau Monné 
453*a6aedc5dSRoger Pau Monné 		/* Hold lock so we can't miss wakeups should we block. */
454*a6aedc5dSRoger Pau Monné 		mtx_lock(&xs.ring_lock);
455*a6aedc5dSRoger Pau Monné 		cons = xen_store->req_cons;
456*a6aedc5dSRoger Pau Monné 		prod = xen_store->req_prod;
457*a6aedc5dSRoger Pau Monné 		if ((prod - cons) == XENSTORE_RING_SIZE) {
458*a6aedc5dSRoger Pau Monné 			/*
459*a6aedc5dSRoger Pau Monné 			 * Output ring is full. Wait for a ring event.
460*a6aedc5dSRoger Pau Monné 			 *
461*a6aedc5dSRoger Pau Monné 			 * Note that the events from both queues
462*a6aedc5dSRoger Pau Monné 			 * are combined, so being woken does not
463*a6aedc5dSRoger Pau Monné 			 * guarantee that data exist in the read
464*a6aedc5dSRoger Pau Monné 			 * ring.
465*a6aedc5dSRoger Pau Monné 			 *
466*a6aedc5dSRoger Pau Monné 			 * To simplify error recovery and the retry,
467*a6aedc5dSRoger Pau Monné 			 * we specify PDROP so our lock is *not* held
468*a6aedc5dSRoger Pau Monné 			 * when msleep returns.
469*a6aedc5dSRoger Pau Monné 			 */
470*a6aedc5dSRoger Pau Monné 			error = msleep(xen_store, &xs.ring_lock, PCATCH|PDROP,
471*a6aedc5dSRoger Pau Monné 			     "xbwrite", /*timeout*/0);
472*a6aedc5dSRoger Pau Monné 			if (error && error != EWOULDBLOCK)
473*a6aedc5dSRoger Pau Monné 				return (error);
474*a6aedc5dSRoger Pau Monné 
475*a6aedc5dSRoger Pau Monné 			/* Try again. */
476*a6aedc5dSRoger Pau Monné 			continue;
477*a6aedc5dSRoger Pau Monné 		}
478*a6aedc5dSRoger Pau Monné 		mtx_unlock(&xs.ring_lock);
479*a6aedc5dSRoger Pau Monné 
480*a6aedc5dSRoger Pau Monné 		/* Verify queue sanity. */
481*a6aedc5dSRoger Pau Monné 		if (!xs_check_indexes(cons, prod)) {
482*a6aedc5dSRoger Pau Monné 			xen_store->req_cons = xen_store->req_prod = 0;
483*a6aedc5dSRoger Pau Monné 			return (EIO);
484*a6aedc5dSRoger Pau Monné 		}
485*a6aedc5dSRoger Pau Monné 
486*a6aedc5dSRoger Pau Monné 		dst = xs_get_output_chunk(cons, prod, xen_store->req, &avail);
487*a6aedc5dSRoger Pau Monné 		if (avail > len)
488*a6aedc5dSRoger Pau Monné 			avail = len;
489*a6aedc5dSRoger Pau Monné 
490*a6aedc5dSRoger Pau Monné 		memcpy(dst, data, avail);
491*a6aedc5dSRoger Pau Monné 		data += avail;
492*a6aedc5dSRoger Pau Monné 		len -= avail;
493*a6aedc5dSRoger Pau Monné 
494*a6aedc5dSRoger Pau Monné 		/*
495*a6aedc5dSRoger Pau Monné 		 * The store to the producer index, which indicates
496*a6aedc5dSRoger Pau Monné 		 * to the other side that new data has arrived, must
497*a6aedc5dSRoger Pau Monné 		 * be visible only after our copy of the data into the
498*a6aedc5dSRoger Pau Monné 		 * ring has completed.
499*a6aedc5dSRoger Pau Monné 		 */
500*a6aedc5dSRoger Pau Monné 		wmb();
501*a6aedc5dSRoger Pau Monné 		xen_store->req_prod += avail;
502*a6aedc5dSRoger Pau Monné 
503*a6aedc5dSRoger Pau Monné 		/*
504*a6aedc5dSRoger Pau Monné 		 * xen_intr_signal() implies mb(). The other side will see
505*a6aedc5dSRoger Pau Monné 		 * the change to req_prod at the time of the interrupt.
506*a6aedc5dSRoger Pau Monné 		 */
507*a6aedc5dSRoger Pau Monné 		xen_intr_signal(xs.xen_intr_handle);
508*a6aedc5dSRoger Pau Monné 	}
509*a6aedc5dSRoger Pau Monné 
510*a6aedc5dSRoger Pau Monné 	return (0);
511*a6aedc5dSRoger Pau Monné }
512*a6aedc5dSRoger Pau Monné 
513*a6aedc5dSRoger Pau Monné /**
514*a6aedc5dSRoger Pau Monné  * Receive data from the XenStore service.
515*a6aedc5dSRoger Pau Monné  *
516*a6aedc5dSRoger Pau Monné  * \param tdata  A pointer to the contiguous buffer to receive the data.
517*a6aedc5dSRoger Pau Monné  * \param len    The amount of data to receive.
518*a6aedc5dSRoger Pau Monné  *
519*a6aedc5dSRoger Pau Monné  * \return  On success 0, otherwise an errno value indicating the
520*a6aedc5dSRoger Pau Monné  *          cause of failure.
521*a6aedc5dSRoger Pau Monné  *
522*a6aedc5dSRoger Pau Monné  * \invariant  Called from thread context.
523*a6aedc5dSRoger Pau Monné  * \invariant  The buffer pointed to by tdata is at least len bytes
524*a6aedc5dSRoger Pau Monné  *             in length.
525*a6aedc5dSRoger Pau Monné  *
526*a6aedc5dSRoger Pau Monné  * \note xs_read does not perform any internal locking to guarantee
527*a6aedc5dSRoger Pau Monné  *       serial access to the incoming ring buffer.  However, there
528*a6aedc5dSRoger Pau Monné  *	 is only one context processing reads: xs_rcv_thread().
529*a6aedc5dSRoger Pau Monné  */
530*a6aedc5dSRoger Pau Monné static int
531*a6aedc5dSRoger Pau Monné xs_read_store(void *tdata, unsigned len)
532*a6aedc5dSRoger Pau Monné {
533*a6aedc5dSRoger Pau Monné 	XENSTORE_RING_IDX cons, prod;
534*a6aedc5dSRoger Pau Monné 	char *data = (char *)tdata;
535*a6aedc5dSRoger Pau Monné 	int error;
536*a6aedc5dSRoger Pau Monné 
537*a6aedc5dSRoger Pau Monné 	while (len != 0) {
538*a6aedc5dSRoger Pau Monné 		u_int avail;
539*a6aedc5dSRoger Pau Monné 		const char *src;
540*a6aedc5dSRoger Pau Monné 
541*a6aedc5dSRoger Pau Monné 		/* Hold lock so we can't miss wakeups should we block. */
542*a6aedc5dSRoger Pau Monné 		mtx_lock(&xs.ring_lock);
543*a6aedc5dSRoger Pau Monné 		cons = xen_store->rsp_cons;
544*a6aedc5dSRoger Pau Monné 		prod = xen_store->rsp_prod;
545*a6aedc5dSRoger Pau Monné 		if (cons == prod) {
546*a6aedc5dSRoger Pau Monné 			/*
547*a6aedc5dSRoger Pau Monné 			 * Nothing to read. Wait for a ring event.
548*a6aedc5dSRoger Pau Monné 			 *
549*a6aedc5dSRoger Pau Monné 			 * Note that the events from both queues
550*a6aedc5dSRoger Pau Monné 			 * are combined, so being woken does not
551*a6aedc5dSRoger Pau Monné 			 * guarantee that data exist in the read
552*a6aedc5dSRoger Pau Monné 			 * ring.
553*a6aedc5dSRoger Pau Monné 			 *
554*a6aedc5dSRoger Pau Monné 			 * To simplify error recovery and the retry,
555*a6aedc5dSRoger Pau Monné 			 * we specify PDROP so our lock is *not* held
556*a6aedc5dSRoger Pau Monné 			 * when msleep returns.
557*a6aedc5dSRoger Pau Monné 			 */
558*a6aedc5dSRoger Pau Monné 			error = msleep(xen_store, &xs.ring_lock, PCATCH|PDROP,
559*a6aedc5dSRoger Pau Monné 			    "xbread", /*timeout*/0);
560*a6aedc5dSRoger Pau Monné 			if (error && error != EWOULDBLOCK)
561*a6aedc5dSRoger Pau Monné 				return (error);
562*a6aedc5dSRoger Pau Monné 			continue;
563*a6aedc5dSRoger Pau Monné 		}
564*a6aedc5dSRoger Pau Monné 		mtx_unlock(&xs.ring_lock);
565*a6aedc5dSRoger Pau Monné 
566*a6aedc5dSRoger Pau Monné 		/* Verify queue sanity. */
567*a6aedc5dSRoger Pau Monné 		if (!xs_check_indexes(cons, prod)) {
568*a6aedc5dSRoger Pau Monné 			xen_store->rsp_cons = xen_store->rsp_prod = 0;
569*a6aedc5dSRoger Pau Monné 			return (EIO);
570*a6aedc5dSRoger Pau Monné 		}
571*a6aedc5dSRoger Pau Monné 
572*a6aedc5dSRoger Pau Monné 		src = xs_get_input_chunk(cons, prod, xen_store->rsp, &avail);
573*a6aedc5dSRoger Pau Monné 		if (avail > len)
574*a6aedc5dSRoger Pau Monné 			avail = len;
575*a6aedc5dSRoger Pau Monné 
576*a6aedc5dSRoger Pau Monné 		/*
577*a6aedc5dSRoger Pau Monné 		 * Insure the data we read is related to the indexes
578*a6aedc5dSRoger Pau Monné 		 * we read above.
579*a6aedc5dSRoger Pau Monné 		 */
580*a6aedc5dSRoger Pau Monné 		rmb();
581*a6aedc5dSRoger Pau Monné 
582*a6aedc5dSRoger Pau Monné 		memcpy(data, src, avail);
583*a6aedc5dSRoger Pau Monné 		data += avail;
584*a6aedc5dSRoger Pau Monné 		len -= avail;
585*a6aedc5dSRoger Pau Monné 
586*a6aedc5dSRoger Pau Monné 		/*
587*a6aedc5dSRoger Pau Monné 		 * Insure that the producer of this ring does not see
588*a6aedc5dSRoger Pau Monné 		 * the ring space as free until after we have copied it
589*a6aedc5dSRoger Pau Monné 		 * out.
590*a6aedc5dSRoger Pau Monné 		 */
591*a6aedc5dSRoger Pau Monné 		mb();
592*a6aedc5dSRoger Pau Monné 		xen_store->rsp_cons += avail;
593*a6aedc5dSRoger Pau Monné 
594*a6aedc5dSRoger Pau Monné 		/*
595*a6aedc5dSRoger Pau Monné 		 * xen_intr_signal() implies mb(). The producer will see
596*a6aedc5dSRoger Pau Monné 		 * the updated consumer index when the event is delivered.
597*a6aedc5dSRoger Pau Monné 		 */
598*a6aedc5dSRoger Pau Monné 		xen_intr_signal(xs.xen_intr_handle);
599*a6aedc5dSRoger Pau Monné 	}
600*a6aedc5dSRoger Pau Monné 
601*a6aedc5dSRoger Pau Monné 	return (0);
602*a6aedc5dSRoger Pau Monné }
603*a6aedc5dSRoger Pau Monné 
604*a6aedc5dSRoger Pau Monné /*----------------------- Received Message Processing ------------------------*/
605*a6aedc5dSRoger Pau Monné /**
606*a6aedc5dSRoger Pau Monné  * Block reading the next message from the XenStore service and
607*a6aedc5dSRoger Pau Monné  * process the result.
608*a6aedc5dSRoger Pau Monné  *
609*a6aedc5dSRoger Pau Monné  * \param type  The returned type of the XenStore message received.
610*a6aedc5dSRoger Pau Monné  *
611*a6aedc5dSRoger Pau Monné  * \return  0 on success.  Otherwise an errno value indicating the
612*a6aedc5dSRoger Pau Monné  *          type of failure encountered.
613*a6aedc5dSRoger Pau Monné  */
614*a6aedc5dSRoger Pau Monné static int
615*a6aedc5dSRoger Pau Monné xs_process_msg(enum xsd_sockmsg_type *type)
616*a6aedc5dSRoger Pau Monné {
617*a6aedc5dSRoger Pau Monné 	struct xs_stored_msg *msg;
618*a6aedc5dSRoger Pau Monné 	char *body;
619*a6aedc5dSRoger Pau Monné 	int error;
620*a6aedc5dSRoger Pau Monné 
621*a6aedc5dSRoger Pau Monné 	msg = malloc(sizeof(*msg), M_XENSTORE, M_WAITOK);
622*a6aedc5dSRoger Pau Monné 	error = xs_read_store(&msg->hdr, sizeof(msg->hdr));
623*a6aedc5dSRoger Pau Monné 	if (error) {
624*a6aedc5dSRoger Pau Monné 		free(msg, M_XENSTORE);
625*a6aedc5dSRoger Pau Monné 		return (error);
626*a6aedc5dSRoger Pau Monné 	}
627*a6aedc5dSRoger Pau Monné 
628*a6aedc5dSRoger Pau Monné 	body = malloc(msg->hdr.len + 1, M_XENSTORE, M_WAITOK);
629*a6aedc5dSRoger Pau Monné 	error = xs_read_store(body, msg->hdr.len);
630*a6aedc5dSRoger Pau Monné 	if (error) {
631*a6aedc5dSRoger Pau Monné 		free(body, M_XENSTORE);
632*a6aedc5dSRoger Pau Monné 		free(msg, M_XENSTORE);
633*a6aedc5dSRoger Pau Monné 		return (error);
634*a6aedc5dSRoger Pau Monné 	}
635*a6aedc5dSRoger Pau Monné 	body[msg->hdr.len] = '\0';
636*a6aedc5dSRoger Pau Monné 
637*a6aedc5dSRoger Pau Monné 	*type = msg->hdr.type;
638*a6aedc5dSRoger Pau Monné 	if (msg->hdr.type == XS_WATCH_EVENT) {
639*a6aedc5dSRoger Pau Monné 		msg->u.watch.vec = split(body, msg->hdr.len,
640*a6aedc5dSRoger Pau Monné 		    &msg->u.watch.vec_size);
641*a6aedc5dSRoger Pau Monné 
642*a6aedc5dSRoger Pau Monné 		mtx_lock(&xs.registered_watches_lock);
643*a6aedc5dSRoger Pau Monné 		msg->u.watch.handle = find_watch(
644*a6aedc5dSRoger Pau Monné 		    msg->u.watch.vec[XS_WATCH_TOKEN]);
645*a6aedc5dSRoger Pau Monné 		if (msg->u.watch.handle != NULL) {
646*a6aedc5dSRoger Pau Monné 			mtx_lock(&xs.watch_events_lock);
647*a6aedc5dSRoger Pau Monné 			TAILQ_INSERT_TAIL(&xs.watch_events, msg, list);
648*a6aedc5dSRoger Pau Monné 			wakeup(&xs.watch_events);
649*a6aedc5dSRoger Pau Monné 			mtx_unlock(&xs.watch_events_lock);
650*a6aedc5dSRoger Pau Monné 		} else {
651*a6aedc5dSRoger Pau Monné 			free(msg->u.watch.vec, M_XENSTORE);
652*a6aedc5dSRoger Pau Monné 			free(msg, M_XENSTORE);
653*a6aedc5dSRoger Pau Monné 		}
654*a6aedc5dSRoger Pau Monné 		mtx_unlock(&xs.registered_watches_lock);
655*a6aedc5dSRoger Pau Monné 	} else {
656*a6aedc5dSRoger Pau Monné 		msg->u.reply.body = body;
657*a6aedc5dSRoger Pau Monné 		mtx_lock(&xs.reply_lock);
658*a6aedc5dSRoger Pau Monné 		TAILQ_INSERT_TAIL(&xs.reply_list, msg, list);
659*a6aedc5dSRoger Pau Monné 		wakeup(&xs.reply_list);
660*a6aedc5dSRoger Pau Monné 		mtx_unlock(&xs.reply_lock);
661*a6aedc5dSRoger Pau Monné 	}
662*a6aedc5dSRoger Pau Monné 
663*a6aedc5dSRoger Pau Monné 	return (0);
664*a6aedc5dSRoger Pau Monné }
665*a6aedc5dSRoger Pau Monné 
666*a6aedc5dSRoger Pau Monné /**
667*a6aedc5dSRoger Pau Monné  * Thread body of the XenStore receive thread.
668*a6aedc5dSRoger Pau Monné  *
669*a6aedc5dSRoger Pau Monné  * This thread blocks waiting for data from the XenStore service
670*a6aedc5dSRoger Pau Monné  * and processes and received messages.
671*a6aedc5dSRoger Pau Monné  */
672*a6aedc5dSRoger Pau Monné static void
673*a6aedc5dSRoger Pau Monné xs_rcv_thread(void *arg __unused)
674*a6aedc5dSRoger Pau Monné {
675*a6aedc5dSRoger Pau Monné 	int error;
676*a6aedc5dSRoger Pau Monné 	enum xsd_sockmsg_type type;
677*a6aedc5dSRoger Pau Monné 
678*a6aedc5dSRoger Pau Monné 	for (;;) {
679*a6aedc5dSRoger Pau Monné 		error = xs_process_msg(&type);
680*a6aedc5dSRoger Pau Monné 		if (error)
681*a6aedc5dSRoger Pau Monné 			printf("XENSTORE error %d while reading message\n",
682*a6aedc5dSRoger Pau Monné 			    error);
683*a6aedc5dSRoger Pau Monné 	}
684*a6aedc5dSRoger Pau Monné }
685*a6aedc5dSRoger Pau Monné 
686*a6aedc5dSRoger Pau Monné /*---------------- XenStore Message Request/Reply Processing -----------------*/
687*a6aedc5dSRoger Pau Monné /**
688*a6aedc5dSRoger Pau Monné  * Filter invoked before transmitting any message to the XenStore service.
689*a6aedc5dSRoger Pau Monné  *
690*a6aedc5dSRoger Pau Monné  * The role of the filter may expand, but currently serves to manage
691*a6aedc5dSRoger Pau Monné  * the interactions of messages with transaction state.
692*a6aedc5dSRoger Pau Monné  *
693*a6aedc5dSRoger Pau Monné  * \param request_msg_type  The message type for the request.
694*a6aedc5dSRoger Pau Monné  */
695*a6aedc5dSRoger Pau Monné static inline void
696*a6aedc5dSRoger Pau Monné xs_request_filter(uint32_t request_msg_type)
697*a6aedc5dSRoger Pau Monné {
698*a6aedc5dSRoger Pau Monné 	if (request_msg_type == XS_TRANSACTION_START)
699*a6aedc5dSRoger Pau Monné 		sx_slock(&xs.suspend_mutex);
700*a6aedc5dSRoger Pau Monné }
701*a6aedc5dSRoger Pau Monné 
702*a6aedc5dSRoger Pau Monné /**
703*a6aedc5dSRoger Pau Monné  * Filter invoked after transmitting any message to the XenStore service.
704*a6aedc5dSRoger Pau Monné  *
705*a6aedc5dSRoger Pau Monné  * The role of the filter may expand, but currently serves to manage
706*a6aedc5dSRoger Pau Monné  * the interactions of messages with transaction state.
707*a6aedc5dSRoger Pau Monné  *
708*a6aedc5dSRoger Pau Monné  * \param request_msg_type     The message type for the original request.
709*a6aedc5dSRoger Pau Monné  * \param reply_msg_type       The message type for any received reply.
710*a6aedc5dSRoger Pau Monné  * \param request_reply_error  The error status from the attempt to send
711*a6aedc5dSRoger Pau Monné  *                             the request or retrieve the reply.
712*a6aedc5dSRoger Pau Monné  */
713*a6aedc5dSRoger Pau Monné static inline void
714*a6aedc5dSRoger Pau Monné xs_reply_filter(uint32_t request_msg_type,
715*a6aedc5dSRoger Pau Monné     uint32_t reply_msg_type, int request_reply_error)
716*a6aedc5dSRoger Pau Monné {
717*a6aedc5dSRoger Pau Monné 	/*
718*a6aedc5dSRoger Pau Monné 	 * The count of transactions drops if we attempted
719*a6aedc5dSRoger Pau Monné 	 * to end a transaction (even if that attempt fails
720*a6aedc5dSRoger Pau Monné 	 * in error), we receive a transaction end acknowledgement,
721*a6aedc5dSRoger Pau Monné 	 * or if our attempt to begin a transaction fails.
722*a6aedc5dSRoger Pau Monné 	 */
723*a6aedc5dSRoger Pau Monné 	if (request_msg_type == XS_TRANSACTION_END
724*a6aedc5dSRoger Pau Monné 	 || (request_reply_error == 0 && reply_msg_type == XS_TRANSACTION_END)
725*a6aedc5dSRoger Pau Monné 	 || (request_msg_type == XS_TRANSACTION_START
726*a6aedc5dSRoger Pau Monné 	  && (request_reply_error != 0 || reply_msg_type == XS_ERROR)))
727*a6aedc5dSRoger Pau Monné 		sx_sunlock(&xs.suspend_mutex);
728*a6aedc5dSRoger Pau Monné 
729*a6aedc5dSRoger Pau Monné }
730*a6aedc5dSRoger Pau Monné 
731*a6aedc5dSRoger Pau Monné #define xsd_error_count	(sizeof(xsd_errors) / sizeof(xsd_errors[0]))
732*a6aedc5dSRoger Pau Monné 
733*a6aedc5dSRoger Pau Monné /**
734*a6aedc5dSRoger Pau Monné  * Convert a XenStore error string into an errno number.
735*a6aedc5dSRoger Pau Monné  *
736*a6aedc5dSRoger Pau Monné  * \param errorstring  The error string to convert.
737*a6aedc5dSRoger Pau Monné  *
738*a6aedc5dSRoger Pau Monné  * \return  The errno best matching the input string.
739*a6aedc5dSRoger Pau Monné  *
740*a6aedc5dSRoger Pau Monné  * \note Unknown error strings are converted to EINVAL.
741*a6aedc5dSRoger Pau Monné  */
742*a6aedc5dSRoger Pau Monné static int
743*a6aedc5dSRoger Pau Monné xs_get_error(const char *errorstring)
744*a6aedc5dSRoger Pau Monné {
745*a6aedc5dSRoger Pau Monné 	u_int i;
746*a6aedc5dSRoger Pau Monné 
747*a6aedc5dSRoger Pau Monné 	for (i = 0; i < xsd_error_count; i++) {
748*a6aedc5dSRoger Pau Monné 		if (!strcmp(errorstring, xsd_errors[i].errstring))
749*a6aedc5dSRoger Pau Monné 			return (xsd_errors[i].errnum);
750*a6aedc5dSRoger Pau Monné 	}
751*a6aedc5dSRoger Pau Monné 	log(LOG_WARNING, "XENSTORE xen store gave: unknown error %s",
752*a6aedc5dSRoger Pau Monné 	    errorstring);
753*a6aedc5dSRoger Pau Monné 	return (EINVAL);
754*a6aedc5dSRoger Pau Monné }
755*a6aedc5dSRoger Pau Monné 
756*a6aedc5dSRoger Pau Monné /**
757*a6aedc5dSRoger Pau Monné  * Block waiting for a reply to a message request.
758*a6aedc5dSRoger Pau Monné  *
759*a6aedc5dSRoger Pau Monné  * \param type	  The returned type of the reply.
760*a6aedc5dSRoger Pau Monné  * \param len	  The returned body length of the reply.
761*a6aedc5dSRoger Pau Monné  * \param result  The returned body of the reply.
762*a6aedc5dSRoger Pau Monné  *
763*a6aedc5dSRoger Pau Monné  * \return  0 on success.  Otherwise an errno indicating the
764*a6aedc5dSRoger Pau Monné  *          cause of failure.
765*a6aedc5dSRoger Pau Monné  */
766*a6aedc5dSRoger Pau Monné static int
767*a6aedc5dSRoger Pau Monné xs_read_reply(enum xsd_sockmsg_type *type, u_int *len, void **result)
768*a6aedc5dSRoger Pau Monné {
769*a6aedc5dSRoger Pau Monné 	struct xs_stored_msg *msg;
770*a6aedc5dSRoger Pau Monné 	char *body;
771*a6aedc5dSRoger Pau Monné 	int error;
772*a6aedc5dSRoger Pau Monné 
773*a6aedc5dSRoger Pau Monné 	mtx_lock(&xs.reply_lock);
774*a6aedc5dSRoger Pau Monné 	while (TAILQ_EMPTY(&xs.reply_list)) {
775*a6aedc5dSRoger Pau Monné 		error = mtx_sleep(&xs.reply_list, &xs.reply_lock,
776*a6aedc5dSRoger Pau Monné 		    PCATCH, "xswait", hz/10);
777*a6aedc5dSRoger Pau Monné 		if (error && error != EWOULDBLOCK) {
778*a6aedc5dSRoger Pau Monné 			mtx_unlock(&xs.reply_lock);
779*a6aedc5dSRoger Pau Monné 			return (error);
780*a6aedc5dSRoger Pau Monné 		}
781*a6aedc5dSRoger Pau Monné 	}
782*a6aedc5dSRoger Pau Monné 	msg = TAILQ_FIRST(&xs.reply_list);
783*a6aedc5dSRoger Pau Monné 	TAILQ_REMOVE(&xs.reply_list, msg, list);
784*a6aedc5dSRoger Pau Monné 	mtx_unlock(&xs.reply_lock);
785*a6aedc5dSRoger Pau Monné 
786*a6aedc5dSRoger Pau Monné 	*type = msg->hdr.type;
787*a6aedc5dSRoger Pau Monné 	if (len)
788*a6aedc5dSRoger Pau Monné 		*len = msg->hdr.len;
789*a6aedc5dSRoger Pau Monné 	body = msg->u.reply.body;
790*a6aedc5dSRoger Pau Monné 
791*a6aedc5dSRoger Pau Monné 	free(msg, M_XENSTORE);
792*a6aedc5dSRoger Pau Monné 	*result = body;
793*a6aedc5dSRoger Pau Monné 	return (0);
794*a6aedc5dSRoger Pau Monné }
795*a6aedc5dSRoger Pau Monné 
796*a6aedc5dSRoger Pau Monné /**
797*a6aedc5dSRoger Pau Monné  * Pass-thru interface for XenStore access by userland processes
798*a6aedc5dSRoger Pau Monné  * via the XenStore device.
799*a6aedc5dSRoger Pau Monné  *
800*a6aedc5dSRoger Pau Monné  * Reply type and length data are returned by overwriting these
801*a6aedc5dSRoger Pau Monné  * fields in the passed in request message.
802*a6aedc5dSRoger Pau Monné  *
803*a6aedc5dSRoger Pau Monné  * \param msg	  A properly formatted message to transmit to
804*a6aedc5dSRoger Pau Monné  *		  the XenStore service.
805*a6aedc5dSRoger Pau Monné  * \param result  The returned body of the reply.
806*a6aedc5dSRoger Pau Monné  *
807*a6aedc5dSRoger Pau Monné  * \return  0 on success.  Otherwise an errno indicating the cause
808*a6aedc5dSRoger Pau Monné  *          of failure.
809*a6aedc5dSRoger Pau Monné  *
810*a6aedc5dSRoger Pau Monné  * \note The returned result is provided in malloced storage and thus
811*a6aedc5dSRoger Pau Monné  *       must be free'd by the caller with 'free(result, M_XENSTORE);
812*a6aedc5dSRoger Pau Monné  */
813*a6aedc5dSRoger Pau Monné int
814*a6aedc5dSRoger Pau Monné xs_dev_request_and_reply(struct xsd_sockmsg *msg, void **result)
815*a6aedc5dSRoger Pau Monné {
816*a6aedc5dSRoger Pau Monné 	uint32_t request_type;
817*a6aedc5dSRoger Pau Monné 	int error;
818*a6aedc5dSRoger Pau Monné 
819*a6aedc5dSRoger Pau Monné 	request_type = msg->type;
820*a6aedc5dSRoger Pau Monné 	xs_request_filter(request_type);
821*a6aedc5dSRoger Pau Monné 
822*a6aedc5dSRoger Pau Monné 	sx_xlock(&xs.request_mutex);
823*a6aedc5dSRoger Pau Monné 	if ((error = xs_write_store(msg, sizeof(*msg) + msg->len)) == 0)
824*a6aedc5dSRoger Pau Monné 		error = xs_read_reply(&msg->type, &msg->len, result);
825*a6aedc5dSRoger Pau Monné 	sx_xunlock(&xs.request_mutex);
826*a6aedc5dSRoger Pau Monné 
827*a6aedc5dSRoger Pau Monné 	xs_reply_filter(request_type, msg->type, error);
828*a6aedc5dSRoger Pau Monné 
829*a6aedc5dSRoger Pau Monné 	return (error);
830*a6aedc5dSRoger Pau Monné }
831*a6aedc5dSRoger Pau Monné 
832*a6aedc5dSRoger Pau Monné /**
833*a6aedc5dSRoger Pau Monné  * Send a message with an optionally muti-part body to the XenStore service.
834*a6aedc5dSRoger Pau Monné  *
835*a6aedc5dSRoger Pau Monné  * \param t              The transaction to use for this request.
836*a6aedc5dSRoger Pau Monné  * \param request_type   The type of message to send.
837*a6aedc5dSRoger Pau Monné  * \param iovec          Pointers to the body sections of the request.
838*a6aedc5dSRoger Pau Monné  * \param num_vecs       The number of body sections in the request.
839*a6aedc5dSRoger Pau Monné  * \param len            The returned length of the reply.
840*a6aedc5dSRoger Pau Monné  * \param result         The returned body of the reply.
841*a6aedc5dSRoger Pau Monné  *
842*a6aedc5dSRoger Pau Monné  * \return  0 on success.  Otherwise an errno indicating
843*a6aedc5dSRoger Pau Monné  *          the cause of failure.
844*a6aedc5dSRoger Pau Monné  *
845*a6aedc5dSRoger Pau Monné  * \note The returned result is provided in malloced storage and thus
846*a6aedc5dSRoger Pau Monné  *       must be free'd by the caller with 'free(*result, M_XENSTORE);
847*a6aedc5dSRoger Pau Monné  */
848*a6aedc5dSRoger Pau Monné static int
849*a6aedc5dSRoger Pau Monné xs_talkv(struct xs_transaction t, enum xsd_sockmsg_type request_type,
850*a6aedc5dSRoger Pau Monné     const struct iovec *iovec, u_int num_vecs, u_int *len, void **result)
851*a6aedc5dSRoger Pau Monné {
852*a6aedc5dSRoger Pau Monné 	struct xsd_sockmsg msg;
853*a6aedc5dSRoger Pau Monné 	void *ret = NULL;
854*a6aedc5dSRoger Pau Monné 	u_int i;
855*a6aedc5dSRoger Pau Monné 	int error;
856*a6aedc5dSRoger Pau Monné 
857*a6aedc5dSRoger Pau Monné 	msg.tx_id = t.id;
858*a6aedc5dSRoger Pau Monné 	msg.req_id = 0;
859*a6aedc5dSRoger Pau Monné 	msg.type = request_type;
860*a6aedc5dSRoger Pau Monné 	msg.len = 0;
861*a6aedc5dSRoger Pau Monné 	for (i = 0; i < num_vecs; i++)
862*a6aedc5dSRoger Pau Monné 		msg.len += iovec[i].iov_len;
863*a6aedc5dSRoger Pau Monné 
864*a6aedc5dSRoger Pau Monné 	xs_request_filter(request_type);
865*a6aedc5dSRoger Pau Monné 
866*a6aedc5dSRoger Pau Monné 	sx_xlock(&xs.request_mutex);
867*a6aedc5dSRoger Pau Monné 	error = xs_write_store(&msg, sizeof(msg));
868*a6aedc5dSRoger Pau Monné 	if (error) {
869*a6aedc5dSRoger Pau Monné 		printf("xs_talkv failed %d\n", error);
870*a6aedc5dSRoger Pau Monné 		goto error_lock_held;
871*a6aedc5dSRoger Pau Monné 	}
872*a6aedc5dSRoger Pau Monné 
873*a6aedc5dSRoger Pau Monné 	for (i = 0; i < num_vecs; i++) {
874*a6aedc5dSRoger Pau Monné 		error = xs_write_store(iovec[i].iov_base, iovec[i].iov_len);
875*a6aedc5dSRoger Pau Monné 		if (error) {
876*a6aedc5dSRoger Pau Monné 			printf("xs_talkv failed %d\n", error);
877*a6aedc5dSRoger Pau Monné 			goto error_lock_held;
878*a6aedc5dSRoger Pau Monné 		}
879*a6aedc5dSRoger Pau Monné 	}
880*a6aedc5dSRoger Pau Monné 
881*a6aedc5dSRoger Pau Monné 	error = xs_read_reply(&msg.type, len, &ret);
882*a6aedc5dSRoger Pau Monné 
883*a6aedc5dSRoger Pau Monné error_lock_held:
884*a6aedc5dSRoger Pau Monné 	sx_xunlock(&xs.request_mutex);
885*a6aedc5dSRoger Pau Monné 	xs_reply_filter(request_type, msg.type, error);
886*a6aedc5dSRoger Pau Monné 	if (error)
887*a6aedc5dSRoger Pau Monné 		return (error);
888*a6aedc5dSRoger Pau Monné 
889*a6aedc5dSRoger Pau Monné 	if (msg.type == XS_ERROR) {
890*a6aedc5dSRoger Pau Monné 		error = xs_get_error(ret);
891*a6aedc5dSRoger Pau Monné 		free(ret, M_XENSTORE);
892*a6aedc5dSRoger Pau Monné 		return (error);
893*a6aedc5dSRoger Pau Monné 	}
894*a6aedc5dSRoger Pau Monné 
895*a6aedc5dSRoger Pau Monné 	/* Reply is either error or an echo of our request message type. */
896*a6aedc5dSRoger Pau Monné 	KASSERT(msg.type == request_type, ("bad xenstore message type"));
897*a6aedc5dSRoger Pau Monné 
898*a6aedc5dSRoger Pau Monné 	if (result)
899*a6aedc5dSRoger Pau Monné 		*result = ret;
900*a6aedc5dSRoger Pau Monné 	else
901*a6aedc5dSRoger Pau Monné 		free(ret, M_XENSTORE);
902*a6aedc5dSRoger Pau Monné 
903*a6aedc5dSRoger Pau Monné 	return (0);
904*a6aedc5dSRoger Pau Monné }
905*a6aedc5dSRoger Pau Monné 
906*a6aedc5dSRoger Pau Monné /**
907*a6aedc5dSRoger Pau Monné  * Wrapper for xs_talkv allowing easy transmission of a message with
908*a6aedc5dSRoger Pau Monné  * a single, contiguous, message body.
909*a6aedc5dSRoger Pau Monné  *
910*a6aedc5dSRoger Pau Monné  * \param t              The transaction to use for this request.
911*a6aedc5dSRoger Pau Monné  * \param request_type   The type of message to send.
912*a6aedc5dSRoger Pau Monné  * \param body           The body of the request.
913*a6aedc5dSRoger Pau Monné  * \param len            The returned length of the reply.
914*a6aedc5dSRoger Pau Monné  * \param result         The returned body of the reply.
915*a6aedc5dSRoger Pau Monné  *
916*a6aedc5dSRoger Pau Monné  * \return  0 on success.  Otherwise an errno indicating
917*a6aedc5dSRoger Pau Monné  *          the cause of failure.
918*a6aedc5dSRoger Pau Monné  *
919*a6aedc5dSRoger Pau Monné  * \note The returned result is provided in malloced storage and thus
920*a6aedc5dSRoger Pau Monné  *       must be free'd by the caller with 'free(*result, M_XENSTORE);
921*a6aedc5dSRoger Pau Monné  */
922*a6aedc5dSRoger Pau Monné static int
923*a6aedc5dSRoger Pau Monné xs_single(struct xs_transaction t, enum xsd_sockmsg_type request_type,
924*a6aedc5dSRoger Pau Monné     const char *body, u_int *len, void **result)
925*a6aedc5dSRoger Pau Monné {
926*a6aedc5dSRoger Pau Monné 	struct iovec iovec;
927*a6aedc5dSRoger Pau Monné 
928*a6aedc5dSRoger Pau Monné 	iovec.iov_base = (void *)(uintptr_t)body;
929*a6aedc5dSRoger Pau Monné 	iovec.iov_len = strlen(body) + 1;
930*a6aedc5dSRoger Pau Monné 
931*a6aedc5dSRoger Pau Monné 	return (xs_talkv(t, request_type, &iovec, 1, len, result));
932*a6aedc5dSRoger Pau Monné }
933*a6aedc5dSRoger Pau Monné 
934*a6aedc5dSRoger Pau Monné /*------------------------- XenStore Watch Support ---------------------------*/
935*a6aedc5dSRoger Pau Monné /**
936*a6aedc5dSRoger Pau Monné  * Transmit a watch request to the XenStore service.
937*a6aedc5dSRoger Pau Monné  *
938*a6aedc5dSRoger Pau Monné  * \param path    The path in the XenStore to watch.
939*a6aedc5dSRoger Pau Monné  * \param tocken  A unique identifier for this watch.
940*a6aedc5dSRoger Pau Monné  *
941*a6aedc5dSRoger Pau Monné  * \return  0 on success.  Otherwise an errno indicating the
942*a6aedc5dSRoger Pau Monné  *          cause of failure.
943*a6aedc5dSRoger Pau Monné  */
944*a6aedc5dSRoger Pau Monné static int
945*a6aedc5dSRoger Pau Monné xs_watch(const char *path, const char *token)
946*a6aedc5dSRoger Pau Monné {
947*a6aedc5dSRoger Pau Monné 	struct iovec iov[2];
948*a6aedc5dSRoger Pau Monné 
949*a6aedc5dSRoger Pau Monné 	iov[0].iov_base = (void *)(uintptr_t) path;
950*a6aedc5dSRoger Pau Monné 	iov[0].iov_len = strlen(path) + 1;
951*a6aedc5dSRoger Pau Monné 	iov[1].iov_base = (void *)(uintptr_t) token;
952*a6aedc5dSRoger Pau Monné 	iov[1].iov_len = strlen(token) + 1;
953*a6aedc5dSRoger Pau Monné 
954*a6aedc5dSRoger Pau Monné 	return (xs_talkv(XST_NIL, XS_WATCH, iov, 2, NULL, NULL));
955*a6aedc5dSRoger Pau Monné }
956*a6aedc5dSRoger Pau Monné 
957*a6aedc5dSRoger Pau Monné /**
958*a6aedc5dSRoger Pau Monné  * Transmit an uwatch request to the XenStore service.
959*a6aedc5dSRoger Pau Monné  *
960*a6aedc5dSRoger Pau Monné  * \param path    The path in the XenStore to watch.
961*a6aedc5dSRoger Pau Monné  * \param tocken  A unique identifier for this watch.
962*a6aedc5dSRoger Pau Monné  *
963*a6aedc5dSRoger Pau Monné  * \return  0 on success.  Otherwise an errno indicating the
964*a6aedc5dSRoger Pau Monné  *          cause of failure.
965*a6aedc5dSRoger Pau Monné  */
966*a6aedc5dSRoger Pau Monné static int
967*a6aedc5dSRoger Pau Monné xs_unwatch(const char *path, const char *token)
968*a6aedc5dSRoger Pau Monné {
969*a6aedc5dSRoger Pau Monné 	struct iovec iov[2];
970*a6aedc5dSRoger Pau Monné 
971*a6aedc5dSRoger Pau Monné 	iov[0].iov_base = (void *)(uintptr_t) path;
972*a6aedc5dSRoger Pau Monné 	iov[0].iov_len = strlen(path) + 1;
973*a6aedc5dSRoger Pau Monné 	iov[1].iov_base = (void *)(uintptr_t) token;
974*a6aedc5dSRoger Pau Monné 	iov[1].iov_len = strlen(token) + 1;
975*a6aedc5dSRoger Pau Monné 
976*a6aedc5dSRoger Pau Monné 	return (xs_talkv(XST_NIL, XS_UNWATCH, iov, 2, NULL, NULL));
977*a6aedc5dSRoger Pau Monné }
978*a6aedc5dSRoger Pau Monné 
979*a6aedc5dSRoger Pau Monné /**
980*a6aedc5dSRoger Pau Monné  * Convert from watch token (unique identifier) to the associated
981*a6aedc5dSRoger Pau Monné  * internal tracking structure for this watch.
982*a6aedc5dSRoger Pau Monné  *
983*a6aedc5dSRoger Pau Monné  * \param tocken  The unique identifier for the watch to find.
984*a6aedc5dSRoger Pau Monné  *
985*a6aedc5dSRoger Pau Monné  * \return  A pointer to the found watch structure or NULL.
986*a6aedc5dSRoger Pau Monné  */
987*a6aedc5dSRoger Pau Monné static struct xs_watch *
988*a6aedc5dSRoger Pau Monné find_watch(const char *token)
989*a6aedc5dSRoger Pau Monné {
990*a6aedc5dSRoger Pau Monné 	struct xs_watch *i, *cmp;
991*a6aedc5dSRoger Pau Monné 
992*a6aedc5dSRoger Pau Monné 	cmp = (void *)strtoul(token, NULL, 16);
993*a6aedc5dSRoger Pau Monné 
994*a6aedc5dSRoger Pau Monné 	LIST_FOREACH(i, &xs.registered_watches, list)
995*a6aedc5dSRoger Pau Monné 		if (i == cmp)
996*a6aedc5dSRoger Pau Monné 			return (i);
997*a6aedc5dSRoger Pau Monné 
998*a6aedc5dSRoger Pau Monné 	return (NULL);
999*a6aedc5dSRoger Pau Monné }
1000*a6aedc5dSRoger Pau Monné 
1001*a6aedc5dSRoger Pau Monné /**
1002*a6aedc5dSRoger Pau Monné  * Thread body of the XenStore watch event dispatch thread.
1003*a6aedc5dSRoger Pau Monné  */
1004*a6aedc5dSRoger Pau Monné static void
1005*a6aedc5dSRoger Pau Monné xenwatch_thread(void *unused)
1006*a6aedc5dSRoger Pau Monné {
1007*a6aedc5dSRoger Pau Monné 	struct xs_stored_msg *msg;
1008*a6aedc5dSRoger Pau Monné 
1009*a6aedc5dSRoger Pau Monné 	for (;;) {
1010*a6aedc5dSRoger Pau Monné 
1011*a6aedc5dSRoger Pau Monné 		mtx_lock(&xs.watch_events_lock);
1012*a6aedc5dSRoger Pau Monné 		while (TAILQ_EMPTY(&xs.watch_events))
1013*a6aedc5dSRoger Pau Monné 			mtx_sleep(&xs.watch_events,
1014*a6aedc5dSRoger Pau Monné 			    &xs.watch_events_lock,
1015*a6aedc5dSRoger Pau Monné 			    PWAIT | PCATCH, "waitev", hz/10);
1016*a6aedc5dSRoger Pau Monné 
1017*a6aedc5dSRoger Pau Monné 		mtx_unlock(&xs.watch_events_lock);
1018*a6aedc5dSRoger Pau Monné 		sx_xlock(&xs.xenwatch_mutex);
1019*a6aedc5dSRoger Pau Monné 
1020*a6aedc5dSRoger Pau Monné 		mtx_lock(&xs.watch_events_lock);
1021*a6aedc5dSRoger Pau Monné 		msg = TAILQ_FIRST(&xs.watch_events);
1022*a6aedc5dSRoger Pau Monné 		if (msg)
1023*a6aedc5dSRoger Pau Monné 			TAILQ_REMOVE(&xs.watch_events, msg, list);
1024*a6aedc5dSRoger Pau Monné 		mtx_unlock(&xs.watch_events_lock);
1025*a6aedc5dSRoger Pau Monné 
1026*a6aedc5dSRoger Pau Monné 		if (msg != NULL) {
1027*a6aedc5dSRoger Pau Monné 			/*
1028*a6aedc5dSRoger Pau Monné 			 * XXX There are messages coming in with a NULL
1029*a6aedc5dSRoger Pau Monné 			 * XXX callback.  This deserves further investigation;
1030*a6aedc5dSRoger Pau Monné 			 * XXX the workaround here simply prevents the kernel
1031*a6aedc5dSRoger Pau Monné 			 * XXX from panic'ing on startup.
1032*a6aedc5dSRoger Pau Monné 			 */
1033*a6aedc5dSRoger Pau Monné 			if (msg->u.watch.handle->callback != NULL)
1034*a6aedc5dSRoger Pau Monné 				msg->u.watch.handle->callback(
1035*a6aedc5dSRoger Pau Monné 					msg->u.watch.handle,
1036*a6aedc5dSRoger Pau Monné 					(const char **)msg->u.watch.vec,
1037*a6aedc5dSRoger Pau Monné 					msg->u.watch.vec_size);
1038*a6aedc5dSRoger Pau Monné 			free(msg->u.watch.vec, M_XENSTORE);
1039*a6aedc5dSRoger Pau Monné 			free(msg, M_XENSTORE);
1040*a6aedc5dSRoger Pau Monné 		}
1041*a6aedc5dSRoger Pau Monné 
1042*a6aedc5dSRoger Pau Monné 		sx_xunlock(&xs.xenwatch_mutex);
1043*a6aedc5dSRoger Pau Monné 	}
1044*a6aedc5dSRoger Pau Monné }
1045*a6aedc5dSRoger Pau Monné 
1046*a6aedc5dSRoger Pau Monné /*----------- XenStore Configuration, Initialization, and Control ------------*/
1047*a6aedc5dSRoger Pau Monné /**
1048*a6aedc5dSRoger Pau Monné  * Setup communication channels with the XenStore service.
1049*a6aedc5dSRoger Pau Monné  *
1050*a6aedc5dSRoger Pau Monné  * \return  On success, 0. Otherwise an errno value indicating the
1051*a6aedc5dSRoger Pau Monné  *          type of failure.
1052*a6aedc5dSRoger Pau Monné  */
1053*a6aedc5dSRoger Pau Monné static int
1054*a6aedc5dSRoger Pau Monné xs_init_comms(void)
1055*a6aedc5dSRoger Pau Monné {
1056*a6aedc5dSRoger Pau Monné 	int error;
1057*a6aedc5dSRoger Pau Monné 
1058*a6aedc5dSRoger Pau Monné 	if (xen_store->rsp_prod != xen_store->rsp_cons) {
1059*a6aedc5dSRoger Pau Monné 		log(LOG_WARNING, "XENSTORE response ring is not quiescent "
1060*a6aedc5dSRoger Pau Monné 		    "(%08x:%08x): fixing up\n",
1061*a6aedc5dSRoger Pau Monné 		    xen_store->rsp_cons, xen_store->rsp_prod);
1062*a6aedc5dSRoger Pau Monné 		xen_store->rsp_cons = xen_store->rsp_prod;
1063*a6aedc5dSRoger Pau Monné 	}
1064*a6aedc5dSRoger Pau Monné 
1065*a6aedc5dSRoger Pau Monné 	xen_intr_unbind(&xs.xen_intr_handle);
1066*a6aedc5dSRoger Pau Monné 
1067*a6aedc5dSRoger Pau Monné 	error = xen_intr_bind_local_port(xs.xs_dev, xs.evtchn,
1068*a6aedc5dSRoger Pau Monné 	    /*filter*/NULL, xs_intr, /*arg*/NULL, INTR_TYPE_NET|INTR_MPSAFE,
1069*a6aedc5dSRoger Pau Monné 	    &xs.xen_intr_handle);
1070*a6aedc5dSRoger Pau Monné 	if (error) {
1071*a6aedc5dSRoger Pau Monné 		log(LOG_WARNING, "XENSTORE request irq failed %i\n", error);
1072*a6aedc5dSRoger Pau Monné 		return (error);
1073*a6aedc5dSRoger Pau Monné 	}
1074*a6aedc5dSRoger Pau Monné 
1075*a6aedc5dSRoger Pau Monné 	return (0);
1076*a6aedc5dSRoger Pau Monné }
1077*a6aedc5dSRoger Pau Monné 
1078*a6aedc5dSRoger Pau Monné /*------------------ Private Device Attachment Functions  --------------------*/
1079*a6aedc5dSRoger Pau Monné static void
1080*a6aedc5dSRoger Pau Monné xs_identify(driver_t *driver, device_t parent)
1081*a6aedc5dSRoger Pau Monné {
1082*a6aedc5dSRoger Pau Monné 
1083*a6aedc5dSRoger Pau Monné 	BUS_ADD_CHILD(parent, 0, "xenstore", 0);
1084*a6aedc5dSRoger Pau Monné }
1085*a6aedc5dSRoger Pau Monné 
1086*a6aedc5dSRoger Pau Monné /**
1087*a6aedc5dSRoger Pau Monné  * Probe for the existance of the XenStore.
1088*a6aedc5dSRoger Pau Monné  *
1089*a6aedc5dSRoger Pau Monné  * \param dev
1090*a6aedc5dSRoger Pau Monné  */
1091*a6aedc5dSRoger Pau Monné static int
1092*a6aedc5dSRoger Pau Monné xs_probe(device_t dev)
1093*a6aedc5dSRoger Pau Monné {
1094*a6aedc5dSRoger Pau Monné 	/*
1095*a6aedc5dSRoger Pau Monné 	 * We are either operating within a PV kernel or being probed
1096*a6aedc5dSRoger Pau Monné 	 * as the child of the successfully attached xenpci device.
1097*a6aedc5dSRoger Pau Monné 	 * Thus we are in a Xen environment and there will be a XenStore.
1098*a6aedc5dSRoger Pau Monné 	 * Unconditionally return success.
1099*a6aedc5dSRoger Pau Monné 	 */
1100*a6aedc5dSRoger Pau Monné 	device_set_desc(dev, "XenStore");
1101*a6aedc5dSRoger Pau Monné 	return (0);
1102*a6aedc5dSRoger Pau Monné }
1103*a6aedc5dSRoger Pau Monné 
1104*a6aedc5dSRoger Pau Monné static void
1105*a6aedc5dSRoger Pau Monné xs_attach_deferred(void *arg)
1106*a6aedc5dSRoger Pau Monné {
1107*a6aedc5dSRoger Pau Monné 	xs_dev_init();
1108*a6aedc5dSRoger Pau Monné 
1109*a6aedc5dSRoger Pau Monné 	bus_generic_probe(xs.xs_dev);
1110*a6aedc5dSRoger Pau Monné 	bus_generic_attach(xs.xs_dev);
1111*a6aedc5dSRoger Pau Monné 
1112*a6aedc5dSRoger Pau Monné 	config_intrhook_disestablish(&xs.xs_attachcb);
1113*a6aedc5dSRoger Pau Monné }
1114*a6aedc5dSRoger Pau Monné 
1115*a6aedc5dSRoger Pau Monné /**
1116*a6aedc5dSRoger Pau Monné  * Attach to the XenStore.
1117*a6aedc5dSRoger Pau Monné  *
1118*a6aedc5dSRoger Pau Monné  * This routine also prepares for the probe/attach of drivers that rely
1119*a6aedc5dSRoger Pau Monné  * on the XenStore.
1120*a6aedc5dSRoger Pau Monné  */
1121*a6aedc5dSRoger Pau Monné static int
1122*a6aedc5dSRoger Pau Monné xs_attach(device_t dev)
1123*a6aedc5dSRoger Pau Monné {
1124*a6aedc5dSRoger Pau Monné 	int error;
1125*a6aedc5dSRoger Pau Monné 
1126*a6aedc5dSRoger Pau Monné 	/* Allow us to get device_t from softc and vice-versa. */
1127*a6aedc5dSRoger Pau Monné 	xs.xs_dev = dev;
1128*a6aedc5dSRoger Pau Monné 	device_set_softc(dev, &xs);
1129*a6aedc5dSRoger Pau Monné 
1130*a6aedc5dSRoger Pau Monné 	/* Initialize the interface to xenstore. */
1131*a6aedc5dSRoger Pau Monné 	struct proc *p;
1132*a6aedc5dSRoger Pau Monné 
1133*a6aedc5dSRoger Pau Monné 	if (xen_hvm_domain()) {
1134*a6aedc5dSRoger Pau Monné 		xs.evtchn = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN);
1135*a6aedc5dSRoger Pau Monné 		xs.gpfn = hvm_get_parameter(HVM_PARAM_STORE_PFN);
1136*a6aedc5dSRoger Pau Monné 		xen_store = pmap_mapdev(xs.gpfn * PAGE_SIZE, PAGE_SIZE);
1137*a6aedc5dSRoger Pau Monné 	} else if (xen_pv_domain()) {
1138*a6aedc5dSRoger Pau Monné 		xs.evtchn = HYPERVISOR_start_info->store_evtchn;
1139*a6aedc5dSRoger Pau Monné 	} else {
1140*a6aedc5dSRoger Pau Monné 		panic("Unknown domain type, cannot initialize xenstore.");
1141*a6aedc5dSRoger Pau Monné 	}
1142*a6aedc5dSRoger Pau Monné 
1143*a6aedc5dSRoger Pau Monné 	TAILQ_INIT(&xs.reply_list);
1144*a6aedc5dSRoger Pau Monné 	TAILQ_INIT(&xs.watch_events);
1145*a6aedc5dSRoger Pau Monné 
1146*a6aedc5dSRoger Pau Monné 	mtx_init(&xs.ring_lock, "ring lock", NULL, MTX_DEF);
1147*a6aedc5dSRoger Pau Monné 	mtx_init(&xs.reply_lock, "reply lock", NULL, MTX_DEF);
1148*a6aedc5dSRoger Pau Monné 	sx_init(&xs.xenwatch_mutex, "xenwatch");
1149*a6aedc5dSRoger Pau Monné 	sx_init(&xs.request_mutex, "xenstore request");
1150*a6aedc5dSRoger Pau Monné 	sx_init(&xs.suspend_mutex, "xenstore suspend");
1151*a6aedc5dSRoger Pau Monné 	mtx_init(&xs.registered_watches_lock, "watches", NULL, MTX_DEF);
1152*a6aedc5dSRoger Pau Monné 	mtx_init(&xs.watch_events_lock, "watch events", NULL, MTX_DEF);
1153*a6aedc5dSRoger Pau Monné 
1154*a6aedc5dSRoger Pau Monné 	/* Initialize the shared memory rings to talk to xenstored */
1155*a6aedc5dSRoger Pau Monné 	error = xs_init_comms();
1156*a6aedc5dSRoger Pau Monné 	if (error)
1157*a6aedc5dSRoger Pau Monné 		return (error);
1158*a6aedc5dSRoger Pau Monné 
1159*a6aedc5dSRoger Pau Monné 	error = kproc_create(xenwatch_thread, NULL, &p, RFHIGHPID,
1160*a6aedc5dSRoger Pau Monné 	    0, "xenwatch");
1161*a6aedc5dSRoger Pau Monné 	if (error)
1162*a6aedc5dSRoger Pau Monné 		return (error);
1163*a6aedc5dSRoger Pau Monné 	xs.xenwatch_pid = p->p_pid;
1164*a6aedc5dSRoger Pau Monné 
1165*a6aedc5dSRoger Pau Monné 	error = kproc_create(xs_rcv_thread, NULL, NULL,
1166*a6aedc5dSRoger Pau Monné 	    RFHIGHPID, 0, "xenstore_rcv");
1167*a6aedc5dSRoger Pau Monné 
1168*a6aedc5dSRoger Pau Monné 	xs.xs_attachcb.ich_func = xs_attach_deferred;
1169*a6aedc5dSRoger Pau Monné 	xs.xs_attachcb.ich_arg = NULL;
1170*a6aedc5dSRoger Pau Monné 	config_intrhook_establish(&xs.xs_attachcb);
1171*a6aedc5dSRoger Pau Monné 
1172*a6aedc5dSRoger Pau Monné 	return (error);
1173*a6aedc5dSRoger Pau Monné }
1174*a6aedc5dSRoger Pau Monné 
1175*a6aedc5dSRoger Pau Monné /**
1176*a6aedc5dSRoger Pau Monné  * Prepare for suspension of this VM by halting XenStore access after
1177*a6aedc5dSRoger Pau Monné  * all transactions and individual requests have completed.
1178*a6aedc5dSRoger Pau Monné  */
1179*a6aedc5dSRoger Pau Monné static int
1180*a6aedc5dSRoger Pau Monné xs_suspend(device_t dev)
1181*a6aedc5dSRoger Pau Monné {
1182*a6aedc5dSRoger Pau Monné 	int error;
1183*a6aedc5dSRoger Pau Monné 
1184*a6aedc5dSRoger Pau Monné 	/* Suspend child Xen devices. */
1185*a6aedc5dSRoger Pau Monné 	error = bus_generic_suspend(dev);
1186*a6aedc5dSRoger Pau Monné 	if (error != 0)
1187*a6aedc5dSRoger Pau Monné 		return (error);
1188*a6aedc5dSRoger Pau Monné 
1189*a6aedc5dSRoger Pau Monné 	sx_xlock(&xs.suspend_mutex);
1190*a6aedc5dSRoger Pau Monné 	sx_xlock(&xs.request_mutex);
1191*a6aedc5dSRoger Pau Monné 
1192*a6aedc5dSRoger Pau Monné 	return (0);
1193*a6aedc5dSRoger Pau Monné }
1194*a6aedc5dSRoger Pau Monné 
1195*a6aedc5dSRoger Pau Monné /**
1196*a6aedc5dSRoger Pau Monné  * Resume XenStore operations after this VM is resumed.
1197*a6aedc5dSRoger Pau Monné  */
1198*a6aedc5dSRoger Pau Monné static int
1199*a6aedc5dSRoger Pau Monné xs_resume(device_t dev __unused)
1200*a6aedc5dSRoger Pau Monné {
1201*a6aedc5dSRoger Pau Monné 	struct xs_watch *watch;
1202*a6aedc5dSRoger Pau Monné 	char token[sizeof(watch) * 2 + 1];
1203*a6aedc5dSRoger Pau Monné 
1204*a6aedc5dSRoger Pau Monné 	xs_init_comms();
1205*a6aedc5dSRoger Pau Monné 
1206*a6aedc5dSRoger Pau Monné 	sx_xunlock(&xs.request_mutex);
1207*a6aedc5dSRoger Pau Monné 
1208*a6aedc5dSRoger Pau Monné 	/*
1209*a6aedc5dSRoger Pau Monné 	 * No need for registered_watches_lock: the suspend_mutex
1210*a6aedc5dSRoger Pau Monné 	 * is sufficient.
1211*a6aedc5dSRoger Pau Monné 	 */
1212*a6aedc5dSRoger Pau Monné 	LIST_FOREACH(watch, &xs.registered_watches, list) {
1213*a6aedc5dSRoger Pau Monné 		sprintf(token, "%lX", (long)watch);
1214*a6aedc5dSRoger Pau Monné 		xs_watch(watch->node, token);
1215*a6aedc5dSRoger Pau Monné 	}
1216*a6aedc5dSRoger Pau Monné 
1217*a6aedc5dSRoger Pau Monné 	sx_xunlock(&xs.suspend_mutex);
1218*a6aedc5dSRoger Pau Monné 
1219*a6aedc5dSRoger Pau Monné 	/* Resume child Xen devices. */
1220*a6aedc5dSRoger Pau Monné 	bus_generic_resume(dev);
1221*a6aedc5dSRoger Pau Monné 
1222*a6aedc5dSRoger Pau Monné 	return (0);
1223*a6aedc5dSRoger Pau Monné }
1224*a6aedc5dSRoger Pau Monné 
1225*a6aedc5dSRoger Pau Monné /*-------------------- Private Device Attachment Data  -----------------------*/
1226*a6aedc5dSRoger Pau Monné static device_method_t xenstore_methods[] = {
1227*a6aedc5dSRoger Pau Monné 	/* Device interface */
1228*a6aedc5dSRoger Pau Monné 	DEVMETHOD(device_identify,	xs_identify),
1229*a6aedc5dSRoger Pau Monné 	DEVMETHOD(device_probe,         xs_probe),
1230*a6aedc5dSRoger Pau Monné 	DEVMETHOD(device_attach,        xs_attach),
1231*a6aedc5dSRoger Pau Monné 	DEVMETHOD(device_detach,        bus_generic_detach),
1232*a6aedc5dSRoger Pau Monné 	DEVMETHOD(device_shutdown,      bus_generic_shutdown),
1233*a6aedc5dSRoger Pau Monné 	DEVMETHOD(device_suspend,       xs_suspend),
1234*a6aedc5dSRoger Pau Monné 	DEVMETHOD(device_resume,        xs_resume),
1235*a6aedc5dSRoger Pau Monné 
1236*a6aedc5dSRoger Pau Monné 	/* Bus interface */
1237*a6aedc5dSRoger Pau Monné 	DEVMETHOD(bus_add_child,        bus_generic_add_child),
1238*a6aedc5dSRoger Pau Monné 	DEVMETHOD(bus_alloc_resource,   bus_generic_alloc_resource),
1239*a6aedc5dSRoger Pau Monné 	DEVMETHOD(bus_release_resource, bus_generic_release_resource),
1240*a6aedc5dSRoger Pau Monné 	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
1241*a6aedc5dSRoger Pau Monné 	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
1242*a6aedc5dSRoger Pau Monné 
1243*a6aedc5dSRoger Pau Monné 	DEVMETHOD_END
1244*a6aedc5dSRoger Pau Monné };
1245*a6aedc5dSRoger Pau Monné 
1246*a6aedc5dSRoger Pau Monné DEFINE_CLASS_0(xenstore, xenstore_driver, xenstore_methods, 0);
1247*a6aedc5dSRoger Pau Monné static devclass_t xenstore_devclass;
1248*a6aedc5dSRoger Pau Monné 
1249*a6aedc5dSRoger Pau Monné DRIVER_MODULE(xenstore, xenpv, xenstore_driver, xenstore_devclass, 0, 0);
1250*a6aedc5dSRoger Pau Monné 
1251*a6aedc5dSRoger Pau Monné /*------------------------------- Sysctl Data --------------------------------*/
1252*a6aedc5dSRoger Pau Monné /* XXX Shouldn't the node be somewhere else? */
1253*a6aedc5dSRoger Pau Monné SYSCTL_NODE(_dev, OID_AUTO, xen, CTLFLAG_RD, NULL, "Xen");
1254*a6aedc5dSRoger Pau Monné SYSCTL_INT(_dev_xen, OID_AUTO, xsd_port, CTLFLAG_RD, &xs.evtchn, 0, "");
1255*a6aedc5dSRoger Pau Monné SYSCTL_ULONG(_dev_xen, OID_AUTO, xsd_kva, CTLFLAG_RD, (u_long *) &xen_store, 0, "");
1256*a6aedc5dSRoger Pau Monné 
1257*a6aedc5dSRoger Pau Monné /*-------------------------------- Public API --------------------------------*/
1258*a6aedc5dSRoger Pau Monné /*------- API comments for these methods can be found in xenstorevar.h -------*/
1259*a6aedc5dSRoger Pau Monné int
1260*a6aedc5dSRoger Pau Monné xs_directory(struct xs_transaction t, const char *dir, const char *node,
1261*a6aedc5dSRoger Pau Monné     u_int *num, const char ***result)
1262*a6aedc5dSRoger Pau Monné {
1263*a6aedc5dSRoger Pau Monné 	struct sbuf *path;
1264*a6aedc5dSRoger Pau Monné 	char *strings;
1265*a6aedc5dSRoger Pau Monné 	u_int len = 0;
1266*a6aedc5dSRoger Pau Monné 	int error;
1267*a6aedc5dSRoger Pau Monné 
1268*a6aedc5dSRoger Pau Monné 	path = xs_join(dir, node);
1269*a6aedc5dSRoger Pau Monné 	error = xs_single(t, XS_DIRECTORY, sbuf_data(path), &len,
1270*a6aedc5dSRoger Pau Monné 	    (void **)&strings);
1271*a6aedc5dSRoger Pau Monné 	sbuf_delete(path);
1272*a6aedc5dSRoger Pau Monné 	if (error)
1273*a6aedc5dSRoger Pau Monné 		return (error);
1274*a6aedc5dSRoger Pau Monné 
1275*a6aedc5dSRoger Pau Monné 	*result = split(strings, len, num);
1276*a6aedc5dSRoger Pau Monné 
1277*a6aedc5dSRoger Pau Monné 	return (0);
1278*a6aedc5dSRoger Pau Monné }
1279*a6aedc5dSRoger Pau Monné 
1280*a6aedc5dSRoger Pau Monné int
1281*a6aedc5dSRoger Pau Monné xs_exists(struct xs_transaction t, const char *dir, const char *node)
1282*a6aedc5dSRoger Pau Monné {
1283*a6aedc5dSRoger Pau Monné 	const char **d;
1284*a6aedc5dSRoger Pau Monné 	int error, dir_n;
1285*a6aedc5dSRoger Pau Monné 
1286*a6aedc5dSRoger Pau Monné 	error = xs_directory(t, dir, node, &dir_n, &d);
1287*a6aedc5dSRoger Pau Monné 	if (error)
1288*a6aedc5dSRoger Pau Monné 		return (0);
1289*a6aedc5dSRoger Pau Monné 	free(d, M_XENSTORE);
1290*a6aedc5dSRoger Pau Monné 	return (1);
1291*a6aedc5dSRoger Pau Monné }
1292*a6aedc5dSRoger Pau Monné 
1293*a6aedc5dSRoger Pau Monné int
1294*a6aedc5dSRoger Pau Monné xs_read(struct xs_transaction t, const char *dir, const char *node,
1295*a6aedc5dSRoger Pau Monné     u_int *len, void **result)
1296*a6aedc5dSRoger Pau Monné {
1297*a6aedc5dSRoger Pau Monné 	struct sbuf *path;
1298*a6aedc5dSRoger Pau Monné 	void *ret;
1299*a6aedc5dSRoger Pau Monné 	int error;
1300*a6aedc5dSRoger Pau Monné 
1301*a6aedc5dSRoger Pau Monné 	path = xs_join(dir, node);
1302*a6aedc5dSRoger Pau Monné 	error = xs_single(t, XS_READ, sbuf_data(path), len, &ret);
1303*a6aedc5dSRoger Pau Monné 	sbuf_delete(path);
1304*a6aedc5dSRoger Pau Monné 	if (error)
1305*a6aedc5dSRoger Pau Monné 		return (error);
1306*a6aedc5dSRoger Pau Monné 	*result = ret;
1307*a6aedc5dSRoger Pau Monné 	return (0);
1308*a6aedc5dSRoger Pau Monné }
1309*a6aedc5dSRoger Pau Monné 
1310*a6aedc5dSRoger Pau Monné int
1311*a6aedc5dSRoger Pau Monné xs_write(struct xs_transaction t, const char *dir, const char *node,
1312*a6aedc5dSRoger Pau Monné     const char *string)
1313*a6aedc5dSRoger Pau Monné {
1314*a6aedc5dSRoger Pau Monné 	struct sbuf *path;
1315*a6aedc5dSRoger Pau Monné 	struct iovec iovec[2];
1316*a6aedc5dSRoger Pau Monné 	int error;
1317*a6aedc5dSRoger Pau Monné 
1318*a6aedc5dSRoger Pau Monné 	path = xs_join(dir, node);
1319*a6aedc5dSRoger Pau Monné 
1320*a6aedc5dSRoger Pau Monné 	iovec[0].iov_base = (void *)(uintptr_t) sbuf_data(path);
1321*a6aedc5dSRoger Pau Monné 	iovec[0].iov_len = sbuf_len(path) + 1;
1322*a6aedc5dSRoger Pau Monné 	iovec[1].iov_base = (void *)(uintptr_t) string;
1323*a6aedc5dSRoger Pau Monné 	iovec[1].iov_len = strlen(string);
1324*a6aedc5dSRoger Pau Monné 
1325*a6aedc5dSRoger Pau Monné 	error = xs_talkv(t, XS_WRITE, iovec, 2, NULL, NULL);
1326*a6aedc5dSRoger Pau Monné 	sbuf_delete(path);
1327*a6aedc5dSRoger Pau Monné 
1328*a6aedc5dSRoger Pau Monné 	return (error);
1329*a6aedc5dSRoger Pau Monné }
1330*a6aedc5dSRoger Pau Monné 
1331*a6aedc5dSRoger Pau Monné int
1332*a6aedc5dSRoger Pau Monné xs_mkdir(struct xs_transaction t, const char *dir, const char *node)
1333*a6aedc5dSRoger Pau Monné {
1334*a6aedc5dSRoger Pau Monné 	struct sbuf *path;
1335*a6aedc5dSRoger Pau Monné 	int ret;
1336*a6aedc5dSRoger Pau Monné 
1337*a6aedc5dSRoger Pau Monné 	path = xs_join(dir, node);
1338*a6aedc5dSRoger Pau Monné 	ret = xs_single(t, XS_MKDIR, sbuf_data(path), NULL, NULL);
1339*a6aedc5dSRoger Pau Monné 	sbuf_delete(path);
1340*a6aedc5dSRoger Pau Monné 
1341*a6aedc5dSRoger Pau Monné 	return (ret);
1342*a6aedc5dSRoger Pau Monné }
1343*a6aedc5dSRoger Pau Monné 
1344*a6aedc5dSRoger Pau Monné int
1345*a6aedc5dSRoger Pau Monné xs_rm(struct xs_transaction t, const char *dir, const char *node)
1346*a6aedc5dSRoger Pau Monné {
1347*a6aedc5dSRoger Pau Monné 	struct sbuf *path;
1348*a6aedc5dSRoger Pau Monné 	int ret;
1349*a6aedc5dSRoger Pau Monné 
1350*a6aedc5dSRoger Pau Monné 	path = xs_join(dir, node);
1351*a6aedc5dSRoger Pau Monné 	ret = xs_single(t, XS_RM, sbuf_data(path), NULL, NULL);
1352*a6aedc5dSRoger Pau Monné 	sbuf_delete(path);
1353*a6aedc5dSRoger Pau Monné 
1354*a6aedc5dSRoger Pau Monné 	return (ret);
1355*a6aedc5dSRoger Pau Monné }
1356*a6aedc5dSRoger Pau Monné 
1357*a6aedc5dSRoger Pau Monné int
1358*a6aedc5dSRoger Pau Monné xs_rm_tree(struct xs_transaction xbt, const char *base, const char *node)
1359*a6aedc5dSRoger Pau Monné {
1360*a6aedc5dSRoger Pau Monné 	struct xs_transaction local_xbt;
1361*a6aedc5dSRoger Pau Monné 	struct sbuf *root_path_sbuf;
1362*a6aedc5dSRoger Pau Monné 	struct sbuf *cur_path_sbuf;
1363*a6aedc5dSRoger Pau Monné 	char *root_path;
1364*a6aedc5dSRoger Pau Monné 	char *cur_path;
1365*a6aedc5dSRoger Pau Monné 	const char **dir;
1366*a6aedc5dSRoger Pau Monné 	int error;
1367*a6aedc5dSRoger Pau Monné 	int empty;
1368*a6aedc5dSRoger Pau Monné 
1369*a6aedc5dSRoger Pau Monné retry:
1370*a6aedc5dSRoger Pau Monné 	root_path_sbuf = xs_join(base, node);
1371*a6aedc5dSRoger Pau Monné 	cur_path_sbuf  = xs_join(base, node);
1372*a6aedc5dSRoger Pau Monné 	root_path      = sbuf_data(root_path_sbuf);
1373*a6aedc5dSRoger Pau Monné 	cur_path       = sbuf_data(cur_path_sbuf);
1374*a6aedc5dSRoger Pau Monné 	dir            = NULL;
1375*a6aedc5dSRoger Pau Monné 	local_xbt.id   = 0;
1376*a6aedc5dSRoger Pau Monné 
1377*a6aedc5dSRoger Pau Monné 	if (xbt.id == 0) {
1378*a6aedc5dSRoger Pau Monné 		error = xs_transaction_start(&local_xbt);
1379*a6aedc5dSRoger Pau Monné 		if (error != 0)
1380*a6aedc5dSRoger Pau Monné 			goto out;
1381*a6aedc5dSRoger Pau Monné 		xbt = local_xbt;
1382*a6aedc5dSRoger Pau Monné 	}
1383*a6aedc5dSRoger Pau Monné 
1384*a6aedc5dSRoger Pau Monné 	empty = 0;
1385*a6aedc5dSRoger Pau Monné 	while (1) {
1386*a6aedc5dSRoger Pau Monné 		u_int count;
1387*a6aedc5dSRoger Pau Monné 		u_int i;
1388*a6aedc5dSRoger Pau Monné 
1389*a6aedc5dSRoger Pau Monné 		error = xs_directory(xbt, cur_path, "", &count, &dir);
1390*a6aedc5dSRoger Pau Monné 		if (error)
1391*a6aedc5dSRoger Pau Monné 			goto out;
1392*a6aedc5dSRoger Pau Monné 
1393*a6aedc5dSRoger Pau Monné 		for (i = 0; i < count; i++) {
1394*a6aedc5dSRoger Pau Monné 			error = xs_rm(xbt, cur_path, dir[i]);
1395*a6aedc5dSRoger Pau Monné 			if (error == ENOTEMPTY) {
1396*a6aedc5dSRoger Pau Monné 				struct sbuf *push_dir;
1397*a6aedc5dSRoger Pau Monné 
1398*a6aedc5dSRoger Pau Monné 				/*
1399*a6aedc5dSRoger Pau Monné 				 * Descend to clear out this sub directory.
1400*a6aedc5dSRoger Pau Monné 				 * We'll return to cur_dir once push_dir
1401*a6aedc5dSRoger Pau Monné 				 * is empty.
1402*a6aedc5dSRoger Pau Monné 				 */
1403*a6aedc5dSRoger Pau Monné 				push_dir = xs_join(cur_path, dir[i]);
1404*a6aedc5dSRoger Pau Monné 				sbuf_delete(cur_path_sbuf);
1405*a6aedc5dSRoger Pau Monné 				cur_path_sbuf = push_dir;
1406*a6aedc5dSRoger Pau Monné 				cur_path = sbuf_data(cur_path_sbuf);
1407*a6aedc5dSRoger Pau Monné 				break;
1408*a6aedc5dSRoger Pau Monné 			} else if (error != 0) {
1409*a6aedc5dSRoger Pau Monné 				goto out;
1410*a6aedc5dSRoger Pau Monné 			}
1411*a6aedc5dSRoger Pau Monné 		}
1412*a6aedc5dSRoger Pau Monné 
1413*a6aedc5dSRoger Pau Monné 		free(dir, M_XENSTORE);
1414*a6aedc5dSRoger Pau Monné 		dir = NULL;
1415*a6aedc5dSRoger Pau Monné 
1416*a6aedc5dSRoger Pau Monné 		if (i == count) {
1417*a6aedc5dSRoger Pau Monné 			char *last_slash;
1418*a6aedc5dSRoger Pau Monné 
1419*a6aedc5dSRoger Pau Monné 			/* Directory is empty.  It is now safe to remove. */
1420*a6aedc5dSRoger Pau Monné 			error = xs_rm(xbt, cur_path, "");
1421*a6aedc5dSRoger Pau Monné 			if (error != 0)
1422*a6aedc5dSRoger Pau Monné 				goto out;
1423*a6aedc5dSRoger Pau Monné 
1424*a6aedc5dSRoger Pau Monné 			if (!strcmp(cur_path, root_path))
1425*a6aedc5dSRoger Pau Monné 				break;
1426*a6aedc5dSRoger Pau Monné 
1427*a6aedc5dSRoger Pau Monné 			/* Return to processing the parent directory. */
1428*a6aedc5dSRoger Pau Monné 			last_slash = strrchr(cur_path, '/');
1429*a6aedc5dSRoger Pau Monné 			KASSERT(last_slash != NULL,
1430*a6aedc5dSRoger Pau Monné 				("xs_rm_tree: mangled path %s", cur_path));
1431*a6aedc5dSRoger Pau Monné 			*last_slash = '\0';
1432*a6aedc5dSRoger Pau Monné 		}
1433*a6aedc5dSRoger Pau Monné 	}
1434*a6aedc5dSRoger Pau Monné 
1435*a6aedc5dSRoger Pau Monné out:
1436*a6aedc5dSRoger Pau Monné 	sbuf_delete(cur_path_sbuf);
1437*a6aedc5dSRoger Pau Monné 	sbuf_delete(root_path_sbuf);
1438*a6aedc5dSRoger Pau Monné 	if (dir != NULL)
1439*a6aedc5dSRoger Pau Monné 		free(dir, M_XENSTORE);
1440*a6aedc5dSRoger Pau Monné 
1441*a6aedc5dSRoger Pau Monné 	if (local_xbt.id != 0) {
1442*a6aedc5dSRoger Pau Monné 		int terror;
1443*a6aedc5dSRoger Pau Monné 
1444*a6aedc5dSRoger Pau Monné 		terror = xs_transaction_end(local_xbt, /*abort*/error != 0);
1445*a6aedc5dSRoger Pau Monné 		xbt.id = 0;
1446*a6aedc5dSRoger Pau Monné 		if (terror == EAGAIN && error == 0)
1447*a6aedc5dSRoger Pau Monné 			goto retry;
1448*a6aedc5dSRoger Pau Monné 	}
1449*a6aedc5dSRoger Pau Monné 	return (error);
1450*a6aedc5dSRoger Pau Monné }
1451*a6aedc5dSRoger Pau Monné 
1452*a6aedc5dSRoger Pau Monné int
1453*a6aedc5dSRoger Pau Monné xs_transaction_start(struct xs_transaction *t)
1454*a6aedc5dSRoger Pau Monné {
1455*a6aedc5dSRoger Pau Monné 	char *id_str;
1456*a6aedc5dSRoger Pau Monné 	int error;
1457*a6aedc5dSRoger Pau Monné 
1458*a6aedc5dSRoger Pau Monné 	error = xs_single(XST_NIL, XS_TRANSACTION_START, "", NULL,
1459*a6aedc5dSRoger Pau Monné 	    (void **)&id_str);
1460*a6aedc5dSRoger Pau Monné 	if (error == 0) {
1461*a6aedc5dSRoger Pau Monné 		t->id = strtoul(id_str, NULL, 0);
1462*a6aedc5dSRoger Pau Monné 		free(id_str, M_XENSTORE);
1463*a6aedc5dSRoger Pau Monné 	}
1464*a6aedc5dSRoger Pau Monné 	return (error);
1465*a6aedc5dSRoger Pau Monné }
1466*a6aedc5dSRoger Pau Monné 
1467*a6aedc5dSRoger Pau Monné int
1468*a6aedc5dSRoger Pau Monné xs_transaction_end(struct xs_transaction t, int abort)
1469*a6aedc5dSRoger Pau Monné {
1470*a6aedc5dSRoger Pau Monné 	char abortstr[2];
1471*a6aedc5dSRoger Pau Monné 
1472*a6aedc5dSRoger Pau Monné 	if (abort)
1473*a6aedc5dSRoger Pau Monné 		strcpy(abortstr, "F");
1474*a6aedc5dSRoger Pau Monné 	else
1475*a6aedc5dSRoger Pau Monné 		strcpy(abortstr, "T");
1476*a6aedc5dSRoger Pau Monné 
1477*a6aedc5dSRoger Pau Monné 	return (xs_single(t, XS_TRANSACTION_END, abortstr, NULL, NULL));
1478*a6aedc5dSRoger Pau Monné }
1479*a6aedc5dSRoger Pau Monné 
1480*a6aedc5dSRoger Pau Monné int
1481*a6aedc5dSRoger Pau Monné xs_scanf(struct xs_transaction t, const char *dir, const char *node,
1482*a6aedc5dSRoger Pau Monné      int *scancountp, const char *fmt, ...)
1483*a6aedc5dSRoger Pau Monné {
1484*a6aedc5dSRoger Pau Monné 	va_list ap;
1485*a6aedc5dSRoger Pau Monné 	int error, ns;
1486*a6aedc5dSRoger Pau Monné 	char *val;
1487*a6aedc5dSRoger Pau Monné 
1488*a6aedc5dSRoger Pau Monné 	error = xs_read(t, dir, node, NULL, (void **) &val);
1489*a6aedc5dSRoger Pau Monné 	if (error)
1490*a6aedc5dSRoger Pau Monné 		return (error);
1491*a6aedc5dSRoger Pau Monné 
1492*a6aedc5dSRoger Pau Monné 	va_start(ap, fmt);
1493*a6aedc5dSRoger Pau Monné 	ns = vsscanf(val, fmt, ap);
1494*a6aedc5dSRoger Pau Monné 	va_end(ap);
1495*a6aedc5dSRoger Pau Monné 	free(val, M_XENSTORE);
1496*a6aedc5dSRoger Pau Monné 	/* Distinctive errno. */
1497*a6aedc5dSRoger Pau Monné 	if (ns == 0)
1498*a6aedc5dSRoger Pau Monné 		return (ERANGE);
1499*a6aedc5dSRoger Pau Monné 	if (scancountp)
1500*a6aedc5dSRoger Pau Monné 		*scancountp = ns;
1501*a6aedc5dSRoger Pau Monné 	return (0);
1502*a6aedc5dSRoger Pau Monné }
1503*a6aedc5dSRoger Pau Monné 
1504*a6aedc5dSRoger Pau Monné int
1505*a6aedc5dSRoger Pau Monné xs_vprintf(struct xs_transaction t,
1506*a6aedc5dSRoger Pau Monné     const char *dir, const char *node, const char *fmt, va_list ap)
1507*a6aedc5dSRoger Pau Monné {
1508*a6aedc5dSRoger Pau Monné 	struct sbuf *sb;
1509*a6aedc5dSRoger Pau Monné 	int error;
1510*a6aedc5dSRoger Pau Monné 
1511*a6aedc5dSRoger Pau Monné 	sb = sbuf_new_auto();
1512*a6aedc5dSRoger Pau Monné 	sbuf_vprintf(sb, fmt, ap);
1513*a6aedc5dSRoger Pau Monné 	sbuf_finish(sb);
1514*a6aedc5dSRoger Pau Monné 	error = xs_write(t, dir, node, sbuf_data(sb));
1515*a6aedc5dSRoger Pau Monné 	sbuf_delete(sb);
1516*a6aedc5dSRoger Pau Monné 
1517*a6aedc5dSRoger Pau Monné 	return (error);
1518*a6aedc5dSRoger Pau Monné }
1519*a6aedc5dSRoger Pau Monné 
1520*a6aedc5dSRoger Pau Monné int
1521*a6aedc5dSRoger Pau Monné xs_printf(struct xs_transaction t, const char *dir, const char *node,
1522*a6aedc5dSRoger Pau Monné      const char *fmt, ...)
1523*a6aedc5dSRoger Pau Monné {
1524*a6aedc5dSRoger Pau Monné 	va_list ap;
1525*a6aedc5dSRoger Pau Monné 	int error;
1526*a6aedc5dSRoger Pau Monné 
1527*a6aedc5dSRoger Pau Monné 	va_start(ap, fmt);
1528*a6aedc5dSRoger Pau Monné 	error = xs_vprintf(t, dir, node, fmt, ap);
1529*a6aedc5dSRoger Pau Monné 	va_end(ap);
1530*a6aedc5dSRoger Pau Monné 
1531*a6aedc5dSRoger Pau Monné 	return (error);
1532*a6aedc5dSRoger Pau Monné }
1533*a6aedc5dSRoger Pau Monné 
1534*a6aedc5dSRoger Pau Monné int
1535*a6aedc5dSRoger Pau Monné xs_gather(struct xs_transaction t, const char *dir, ...)
1536*a6aedc5dSRoger Pau Monné {
1537*a6aedc5dSRoger Pau Monné 	va_list ap;
1538*a6aedc5dSRoger Pau Monné 	const char *name;
1539*a6aedc5dSRoger Pau Monné 	int error;
1540*a6aedc5dSRoger Pau Monné 
1541*a6aedc5dSRoger Pau Monné 	va_start(ap, dir);
1542*a6aedc5dSRoger Pau Monné 	error = 0;
1543*a6aedc5dSRoger Pau Monné 	while (error == 0 && (name = va_arg(ap, char *)) != NULL) {
1544*a6aedc5dSRoger Pau Monné 		const char *fmt = va_arg(ap, char *);
1545*a6aedc5dSRoger Pau Monné 		void *result = va_arg(ap, void *);
1546*a6aedc5dSRoger Pau Monné 		char *p;
1547*a6aedc5dSRoger Pau Monné 
1548*a6aedc5dSRoger Pau Monné 		error = xs_read(t, dir, name, NULL, (void **) &p);
1549*a6aedc5dSRoger Pau Monné 		if (error)
1550*a6aedc5dSRoger Pau Monné 			break;
1551*a6aedc5dSRoger Pau Monné 
1552*a6aedc5dSRoger Pau Monné 		if (fmt) {
1553*a6aedc5dSRoger Pau Monné 			if (sscanf(p, fmt, result) == 0)
1554*a6aedc5dSRoger Pau Monné 				error = EINVAL;
1555*a6aedc5dSRoger Pau Monné 			free(p, M_XENSTORE);
1556*a6aedc5dSRoger Pau Monné 		} else
1557*a6aedc5dSRoger Pau Monné 			*(char **)result = p;
1558*a6aedc5dSRoger Pau Monné 	}
1559*a6aedc5dSRoger Pau Monné 	va_end(ap);
1560*a6aedc5dSRoger Pau Monné 
1561*a6aedc5dSRoger Pau Monné 	return (error);
1562*a6aedc5dSRoger Pau Monné }
1563*a6aedc5dSRoger Pau Monné 
1564*a6aedc5dSRoger Pau Monné int
1565*a6aedc5dSRoger Pau Monné xs_register_watch(struct xs_watch *watch)
1566*a6aedc5dSRoger Pau Monné {
1567*a6aedc5dSRoger Pau Monné 	/* Pointer in ascii is the token. */
1568*a6aedc5dSRoger Pau Monné 	char token[sizeof(watch) * 2 + 1];
1569*a6aedc5dSRoger Pau Monné 	int error;
1570*a6aedc5dSRoger Pau Monné 
1571*a6aedc5dSRoger Pau Monné 	sprintf(token, "%lX", (long)watch);
1572*a6aedc5dSRoger Pau Monné 
1573*a6aedc5dSRoger Pau Monné 	sx_slock(&xs.suspend_mutex);
1574*a6aedc5dSRoger Pau Monné 
1575*a6aedc5dSRoger Pau Monné 	mtx_lock(&xs.registered_watches_lock);
1576*a6aedc5dSRoger Pau Monné 	KASSERT(find_watch(token) == NULL, ("watch already registered"));
1577*a6aedc5dSRoger Pau Monné 	LIST_INSERT_HEAD(&xs.registered_watches, watch, list);
1578*a6aedc5dSRoger Pau Monné 	mtx_unlock(&xs.registered_watches_lock);
1579*a6aedc5dSRoger Pau Monné 
1580*a6aedc5dSRoger Pau Monné 	error = xs_watch(watch->node, token);
1581*a6aedc5dSRoger Pau Monné 
1582*a6aedc5dSRoger Pau Monné 	/* Ignore errors due to multiple registration. */
1583*a6aedc5dSRoger Pau Monné 	if (error == EEXIST)
1584*a6aedc5dSRoger Pau Monné 		error = 0;
1585*a6aedc5dSRoger Pau Monné 
1586*a6aedc5dSRoger Pau Monné 	if (error != 0) {
1587*a6aedc5dSRoger Pau Monné 		mtx_lock(&xs.registered_watches_lock);
1588*a6aedc5dSRoger Pau Monné 		LIST_REMOVE(watch, list);
1589*a6aedc5dSRoger Pau Monné 		mtx_unlock(&xs.registered_watches_lock);
1590*a6aedc5dSRoger Pau Monné 	}
1591*a6aedc5dSRoger Pau Monné 
1592*a6aedc5dSRoger Pau Monné 	sx_sunlock(&xs.suspend_mutex);
1593*a6aedc5dSRoger Pau Monné 
1594*a6aedc5dSRoger Pau Monné 	return (error);
1595*a6aedc5dSRoger Pau Monné }
1596*a6aedc5dSRoger Pau Monné 
1597*a6aedc5dSRoger Pau Monné void
1598*a6aedc5dSRoger Pau Monné xs_unregister_watch(struct xs_watch *watch)
1599*a6aedc5dSRoger Pau Monné {
1600*a6aedc5dSRoger Pau Monné 	struct xs_stored_msg *msg, *tmp;
1601*a6aedc5dSRoger Pau Monné 	char token[sizeof(watch) * 2 + 1];
1602*a6aedc5dSRoger Pau Monné 	int error;
1603*a6aedc5dSRoger Pau Monné 
1604*a6aedc5dSRoger Pau Monné 	sprintf(token, "%lX", (long)watch);
1605*a6aedc5dSRoger Pau Monné 
1606*a6aedc5dSRoger Pau Monné 	sx_slock(&xs.suspend_mutex);
1607*a6aedc5dSRoger Pau Monné 
1608*a6aedc5dSRoger Pau Monné 	mtx_lock(&xs.registered_watches_lock);
1609*a6aedc5dSRoger Pau Monné 	if (find_watch(token) == NULL) {
1610*a6aedc5dSRoger Pau Monné 		mtx_unlock(&xs.registered_watches_lock);
1611*a6aedc5dSRoger Pau Monné 		sx_sunlock(&xs.suspend_mutex);
1612*a6aedc5dSRoger Pau Monné 		return;
1613*a6aedc5dSRoger Pau Monné 	}
1614*a6aedc5dSRoger Pau Monné 	LIST_REMOVE(watch, list);
1615*a6aedc5dSRoger Pau Monné 	mtx_unlock(&xs.registered_watches_lock);
1616*a6aedc5dSRoger Pau Monné 
1617*a6aedc5dSRoger Pau Monné 	error = xs_unwatch(watch->node, token);
1618*a6aedc5dSRoger Pau Monné 	if (error)
1619*a6aedc5dSRoger Pau Monné 		log(LOG_WARNING, "XENSTORE Failed to release watch %s: %i\n",
1620*a6aedc5dSRoger Pau Monné 		    watch->node, error);
1621*a6aedc5dSRoger Pau Monné 
1622*a6aedc5dSRoger Pau Monné 	sx_sunlock(&xs.suspend_mutex);
1623*a6aedc5dSRoger Pau Monné 
1624*a6aedc5dSRoger Pau Monné 	/* Cancel pending watch events. */
1625*a6aedc5dSRoger Pau Monné 	mtx_lock(&xs.watch_events_lock);
1626*a6aedc5dSRoger Pau Monné 	TAILQ_FOREACH_SAFE(msg, &xs.watch_events, list, tmp) {
1627*a6aedc5dSRoger Pau Monné 		if (msg->u.watch.handle != watch)
1628*a6aedc5dSRoger Pau Monné 			continue;
1629*a6aedc5dSRoger Pau Monné 		TAILQ_REMOVE(&xs.watch_events, msg, list);
1630*a6aedc5dSRoger Pau Monné 		free(msg->u.watch.vec, M_XENSTORE);
1631*a6aedc5dSRoger Pau Monné 		free(msg, M_XENSTORE);
1632*a6aedc5dSRoger Pau Monné 	}
1633*a6aedc5dSRoger Pau Monné 	mtx_unlock(&xs.watch_events_lock);
1634*a6aedc5dSRoger Pau Monné 
1635*a6aedc5dSRoger Pau Monné 	/* Flush any currently-executing callback, unless we are it. :-) */
1636*a6aedc5dSRoger Pau Monné 	if (curproc->p_pid != xs.xenwatch_pid) {
1637*a6aedc5dSRoger Pau Monné 		sx_xlock(&xs.xenwatch_mutex);
1638*a6aedc5dSRoger Pau Monné 		sx_xunlock(&xs.xenwatch_mutex);
1639*a6aedc5dSRoger Pau Monné 	}
1640*a6aedc5dSRoger Pau Monné }
1641