1205869Sjfv/*
2205869Sjfv * xenstore_dev.c
3228387Sjfv *
4205869Sjfv * Driver giving user-space access to the kernel's connection to the
5205869Sjfv * XenStore service.
6205869Sjfv *
7205869Sjfv * Copyright (c) 2005, Christian Limpach
8205869Sjfv * Copyright (c) 2005, Rusty Russell, IBM Corporation
9205869Sjfv *
10205869Sjfv * This file may be distributed separately from the Linux kernel, or
11205869Sjfv * incorporated into other software packages, subject to the following license:
12205869Sjfv *
13205869Sjfv * Permission is hereby granted, free of charge, to any person obtaining a copy
14205869Sjfv * of this source file (the "Software"), to deal in the Software without
15205869Sjfv * restriction, including without limitation the rights to use, copy, modify,
16205869Sjfv * merge, publish, distribute, sublicense, and/or sell copies of the Software,
17205869Sjfv * and to permit persons to whom the Software is furnished to do so, subject to
18205869Sjfv * the following conditions:
19205869Sjfv *
20205869Sjfv * The above copyright notice and this permission notice shall be included in
21205869Sjfv * all copies or substantial portions of the Software.
22205869Sjfv *
23205869Sjfv * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24205869Sjfv * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25205869Sjfv * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26205869Sjfv * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27205869Sjfv * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28205869Sjfv * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
29205869Sjfv * IN THE SOFTWARE.
30205869Sjfv */
31205869Sjfv
32205869Sjfv#include <sys/types.h>
33205869Sjfv#include <sys/cdefs.h>
34205869Sjfv#include <sys/errno.h>
35205869Sjfv#include <sys/uio.h>
36205869Sjfv#include <sys/param.h>
37205869Sjfv#include <sys/systm.h>
38205869Sjfv#include <sys/proc.h>
39205869Sjfv#include <sys/kernel.h>
40205869Sjfv#include <sys/malloc.h>
41205869Sjfv#include <sys/conf.h>
42205869Sjfv#include <sys/module.h>
43205869Sjfv#include <sys/selinfo.h>
44205869Sjfv#include <sys/sysctl.h>
45205869Sjfv#include <sys/poll.h>
46205869Sjfv
47205869Sjfv#include <xen/xen-os.h>
48205869Sjfv
49205869Sjfv#include <xen/hypervisor.h>
50205869Sjfv#include <xen/xenstore/xenstorevar.h>
51205869Sjfv#include <xen/xenstore/xenstore_internal.h>
52205869Sjfv
53205869Sjfvstatic unsigned int max_pending_watches = 1000;
54205869Sjfv
55205869Sjfvstruct xs_dev_transaction {
56205869Sjfv	LIST_ENTRY(xs_dev_transaction) list;
57205869Sjfv	struct xs_transaction handle;
58205869Sjfv};
59205869Sjfv
60205869Sjfvstruct xs_dev_watch {
61205869Sjfv	LIST_ENTRY(xs_dev_watch) list;
62205869Sjfv	struct xs_watch watch;
63205869Sjfv	char *token;
64205869Sjfv	struct xs_dev_data *user;
65205869Sjfv};
66205869Sjfv
67205869Sjfvstruct xs_dev_data {
68205869Sjfv	/* In-progress transaction. */
69205869Sjfv	LIST_HEAD(, xs_dev_transaction) transactions;
70205869Sjfv
71205869Sjfv	/* Active watches. */
72205869Sjfv	LIST_HEAD(, xs_dev_watch) watches;
73205869Sjfv
74205869Sjfv	/* Partial request. */
75205869Sjfv	unsigned int len;
76205869Sjfv	union {
77205869Sjfv		struct xsd_sockmsg msg;
78205869Sjfv		char buffer[PAGE_SIZE];
79205869Sjfv	} u;
80205869Sjfv
81205869Sjfv	/* Response queue. */
82205869Sjfv#define MASK_READ_IDX(idx) ((idx)&(PAGE_SIZE-1))
83205869Sjfv	char read_buffer[PAGE_SIZE];
84205869Sjfv	unsigned int read_cons, read_prod;
85205869Sjfv
86205869Sjfv	/* Serializes writes to the read buffer. */
87205869Sjfv	struct mtx lock;
88205869Sjfv
89205869Sjfv	/* Polling structure (for reads only ATM). */
90205869Sjfv	struct selinfo ev_rsel;
91205869Sjfv};
92205869Sjfv
93205869Sjfvstatic void
94205869Sjfvxs_queue_reply(struct xs_dev_data *u, const char *data, unsigned int len)
95205869Sjfv{
96205869Sjfv	unsigned int i;
97205869Sjfv
98205869Sjfv	for (i = 0; i < len; i++, u->read_prod++)
99205869Sjfv		u->read_buffer[MASK_READ_IDX(u->read_prod)] = data[i];
100205869Sjfv
101205869Sjfv	KASSERT((u->read_prod - u->read_cons) <= sizeof(u->read_buffer),
102205869Sjfv	    ("xenstore reply too big"));
103205869Sjfv
104205869Sjfv	wakeup(u);
105205869Sjfv	selwakeup(&u->ev_rsel);
106205869Sjfv}
107205869Sjfv
108205869Sjfvstatic const char *
109205869Sjfvxs_dev_error_to_string(int error)
110205869Sjfv{
111205869Sjfv	unsigned int i;
112205869Sjfv
113205869Sjfv	for (i = 0; i < nitems(xsd_errors); i++)
114205869Sjfv		if (xsd_errors[i].errnum == error)
115205869Sjfv			return (xsd_errors[i].errstring);
116205869Sjfv
117205869Sjfv	return (NULL);
118205869Sjfv}
119205869Sjfv
120205869Sjfvstatic void
121205869Sjfvxs_dev_return_error(struct xs_dev_data *u, int error, int req_id, int tx_id)
122205869Sjfv{
123205869Sjfv	struct xsd_sockmsg msg;
124205869Sjfv	const char *payload;
125205869Sjfv
126205869Sjfv	msg.type = XS_ERROR;
127205869Sjfv	msg.req_id = req_id;
128205869Sjfv	msg.tx_id = tx_id;
129205869Sjfv	payload = NULL;
130205869Sjfv
131205869Sjfv	payload = xs_dev_error_to_string(error);
132205869Sjfv	if (payload == NULL)
133205869Sjfv		payload = xs_dev_error_to_string(EINVAL);
134205869Sjfv	KASSERT(payload != NULL, ("Unable to find string for EINVAL errno"));
135205869Sjfv
136205869Sjfv	msg.len = strlen(payload) + 1;
137205869Sjfv
138205869Sjfv	mtx_lock(&u->lock);
139205869Sjfv	xs_queue_reply(u, (char *)&msg, sizeof(msg));
140205869Sjfv	xs_queue_reply(u, payload, msg.len);
141205869Sjfv	mtx_unlock(&u->lock);
142205869Sjfv}
143205869Sjfv
144205869Sjfvstatic int
145205869Sjfvxs_dev_watch_message_parse_string(const char **p, const char *end,
146205869Sjfv    const char **string_r)
147205869Sjfv{
148205869Sjfv	const char *nul;
149205869Sjfv
150205869Sjfv	nul = memchr(*p, 0, end - *p);
151205869Sjfv	if (!nul)
152205869Sjfv		return (EINVAL);
153205869Sjfv
154205869Sjfv	*string_r = *p;
155205869Sjfv	*p = nul+1;
156205869Sjfv
157205869Sjfv	return (0);
158205869Sjfv}
159205869Sjfv
160205869Sjfvstatic int
161205869Sjfvxs_dev_watch_message_parse(const struct xsd_sockmsg *msg, const char **path_r,
162205869Sjfv    const char **token_r)
163205869Sjfv{
164205869Sjfv	const char *p, *end;
165205869Sjfv	int error;
166205869Sjfv
167205869Sjfv	p = (const char *)msg + sizeof(*msg);
168205869Sjfv	end = p + msg->len;
169205869Sjfv	KASSERT(p <= end, ("payload overflow"));
170205869Sjfv
171205869Sjfv	error = xs_dev_watch_message_parse_string(&p, end, path_r);
172205869Sjfv	if (error)
173205869Sjfv		return (error);
174205869Sjfv	error = xs_dev_watch_message_parse_string(&p, end, token_r);
175205869Sjfv	if (error)
176205869Sjfv		return (error);
177205869Sjfv
178205869Sjfv	return (0);
179205869Sjfv}
180205869Sjfv
181205869Sjfvstatic struct xs_dev_watch *
182205869Sjfvxs_dev_find_watch(struct xs_dev_data *u, const char *token)
183205869Sjfv{
184205869Sjfv	struct xs_dev_watch *watch;
185205869Sjfv
186205869Sjfv	LIST_FOREACH(watch, &u->watches, list)
187205869Sjfv		if (strcmp(watch->token, token) == 0)
188205869Sjfv			return (watch);
189205869Sjfv
190205869Sjfv	return (NULL);
191205869Sjfv}
192205869Sjfv
193205869Sjfvstatic void
194205869Sjfvxs_dev_watch_cb(struct xs_watch *watch, const char **vec, unsigned int len)
195205869Sjfv{
196205869Sjfv	struct xs_dev_watch *dwatch;
197205869Sjfv	struct xsd_sockmsg msg;
198205869Sjfv	char *payload;
199205869Sjfv
200205869Sjfv	dwatch = (struct xs_dev_watch *)watch->callback_data;
201205869Sjfv	msg.type = XS_WATCH_EVENT;
202205869Sjfv	msg.req_id = msg.tx_id = 0;
203205869Sjfv	msg.len = strlen(vec[XS_WATCH_PATH]) + strlen(dwatch->token) + 2;
204205869Sjfv
205205869Sjfv	payload = malloc(msg.len, M_XENSTORE, M_WAITOK);
206205869Sjfv	strcpy(payload, vec[XS_WATCH_PATH]);
207205869Sjfv	strcpy(&payload[strlen(vec[XS_WATCH_PATH]) + 1], dwatch->token);
208205869Sjfv	mtx_lock(&dwatch->user->lock);
209205869Sjfv	xs_queue_reply(dwatch->user, (char *)&msg, sizeof(msg));
210205869Sjfv	xs_queue_reply(dwatch->user, payload, msg.len);
211205869Sjfv	mtx_unlock(&dwatch->user->lock);
212205869Sjfv	free(payload, M_XENSTORE);
213205869Sjfv}
214205869Sjfv
215205869Sjfvstatic struct xs_dev_transaction *
216205869Sjfvxs_dev_find_transaction(struct xs_dev_data *u, uint32_t tx_id)
217205869Sjfv{
218205869Sjfv	struct xs_dev_transaction *trans;
219205869Sjfv
220228387Sjfv	LIST_FOREACH(trans, &u->transactions, list)
221219753Sjfv		if (trans->handle.id == tx_id)
222219753Sjfv			return (trans);
223219753Sjfv
224205869Sjfv	return (NULL);
225205869Sjfv}
226205869Sjfv
227205869Sjfvstatic int
228205869Sjfvxs_dev_read(struct cdev *dev, struct uio *uio, int ioflag)
229205869Sjfv{
230205869Sjfv	int error;
231205869Sjfv	struct xs_dev_data *u;
232205869Sjfv
233205869Sjfv	error = devfs_get_cdevpriv((void **)&u);
234205869Sjfv	if (error != 0)
235205869Sjfv		return (error);
236205869Sjfv
237205869Sjfv	while (u->read_prod == u->read_cons) {
238205869Sjfv		error = tsleep(u, PCATCH, "xsdread", hz/10);
239205869Sjfv		if (error && error != EWOULDBLOCK)
240205869Sjfv			return (error);
241205869Sjfv	}
242205869Sjfv
243205869Sjfv	while (uio->uio_resid > 0) {
244205869Sjfv		if (u->read_cons == u->read_prod)
245205869Sjfv			break;
246205869Sjfv		error = uiomove(&u->read_buffer[MASK_READ_IDX(u->read_cons)],
247205869Sjfv		    1, uio);
248205869Sjfv		if (error)
249205869Sjfv			return (error);
250205869Sjfv		u->read_cons++;
251205869Sjfv	}
252205869Sjfv	return (0);
253205869Sjfv}
254205869Sjfv
255205869Sjfvstatic int
256205869Sjfvxs_dev_write(struct cdev *dev, struct uio *uio, int ioflag)
257205869Sjfv{
258205869Sjfv	int error;
259205869Sjfv	const char *wpath, *wtoken;
260205869Sjfv	struct xs_dev_data *u;
261205869Sjfv	struct xs_dev_transaction *trans;
262205869Sjfv	struct xs_dev_watch *watch;
263205869Sjfv	void *reply;
264205869Sjfv	static const char *ok = "OK";
265205869Sjfv	int len = uio->uio_resid;
266205869Sjfv
267205869Sjfv	error = devfs_get_cdevpriv((void **)&u);
268205869Sjfv	if (error != 0)
269205869Sjfv		return (error);
270205869Sjfv
271205869Sjfv	if ((len + u->len) > sizeof(u->u.buffer))
272205869Sjfv		return (EINVAL);
273205869Sjfv
274205869Sjfv	error = uiomove(u->u.buffer + u->len, len, uio);
275205869Sjfv	if (error)
276205869Sjfv		return (error);
277205869Sjfv
278205869Sjfv	u->len += len;
279205869Sjfv	if (u->len < (sizeof(u->u.msg) + u->u.msg.len))
280205869Sjfv		return (0);
281205869Sjfv
282205869Sjfv	switch (u->u.msg.type) {
283205869Sjfv	case XS_TRANSACTION_START:
284205869Sjfv	case XS_TRANSACTION_END:
285205869Sjfv	case XS_DIRECTORY:
286205869Sjfv	case XS_READ:
287205869Sjfv	case XS_GET_PERMS:
288205869Sjfv	case XS_RELEASE:
289205869Sjfv	case XS_GET_DOMAIN_PATH:
290205869Sjfv	case XS_WRITE:
291205869Sjfv	case XS_MKDIR:
292205869Sjfv	case XS_RM:
293205869Sjfv	case XS_SET_PERMS:
294205869Sjfv		/* Check that this transaction id is not hijacked. */
295205869Sjfv		if (u->u.msg.tx_id != 0 &&
296205869Sjfv		    xs_dev_find_transaction(u, u->u.msg.tx_id) == NULL) {
297205869Sjfv			error = EINVAL;
298205869Sjfv			break;
299205869Sjfv		}
300206001Smarius		error = xs_dev_request_and_reply(&u->u.msg, &reply);
301205869Sjfv		if (!error) {
302205869Sjfv			if (u->u.msg.type == XS_TRANSACTION_START) {
303205869Sjfv				trans = malloc(sizeof(*trans), M_XENSTORE,
304205869Sjfv				    M_WAITOK);
305205869Sjfv				trans->handle.id = strtoul(reply, NULL, 0);
306205869Sjfv				LIST_INSERT_HEAD(&u->transactions, trans, list);
307205869Sjfv			} else if (u->u.msg.type == XS_TRANSACTION_END) {
308205869Sjfv				trans = xs_dev_find_transaction(u,
309205869Sjfv				    u->u.msg.tx_id);
310205869Sjfv				KASSERT(trans != NULL,
311205869Sjfv				    ("Unable to find transaction"));
312205869Sjfv				LIST_REMOVE(trans, list);
313205869Sjfv				free(trans, M_XENSTORE);
314205869Sjfv			}
315205869Sjfv			mtx_lock(&u->lock);
316205869Sjfv			xs_queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg));
317205869Sjfv			xs_queue_reply(u, (char *)reply, u->u.msg.len);
318205869Sjfv			mtx_unlock(&u->lock);
319205869Sjfv			free(reply, M_XENSTORE);
320205869Sjfv		}
321205869Sjfv		break;
322205869Sjfv	case XS_WATCH:
323205869Sjfv		u->u.msg.tx_id = 0;
324205869Sjfv		error = xs_dev_watch_message_parse(&u->u.msg, &wpath, &wtoken);
325205869Sjfv		if (error)
326205869Sjfv			break;
327205869Sjfv		if (xs_dev_find_watch(u, wtoken) != NULL) {
328205869Sjfv			error = EINVAL;
329205869Sjfv			break;
330205869Sjfv		}
331205869Sjfv
332205869Sjfv		watch = malloc(sizeof(*watch), M_XENSTORE, M_WAITOK);
333205869Sjfv		watch->watch.node = strdup(wpath, M_XENSTORE);
334205869Sjfv		watch->watch.callback = xs_dev_watch_cb;
335205869Sjfv		watch->watch.callback_data = (uintptr_t)watch;
336205869Sjfv		watch->watch.max_pending = max_pending_watches;
337205869Sjfv		watch->token = strdup(wtoken, M_XENSTORE);
338205869Sjfv		watch->user = u;
339205869Sjfv
340205869Sjfv		error = xs_register_watch(&watch->watch);
341205869Sjfv		if (error != 0) {
342205869Sjfv			free(watch->token, M_XENSTORE);
343205869Sjfv			free(watch->watch.node, M_XENSTORE);
344211913Syongari			free(watch, M_XENSTORE);
345211913Syongari			break;
346214646Sjfv		}
347214646Sjfv
348214646Sjfv		LIST_INSERT_HEAD(&u->watches, watch, list);
349214646Sjfv		u->u.msg.len = sizeof(ok);
350214646Sjfv		mtx_lock(&u->lock);
351214646Sjfv		xs_queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg));
352214646Sjfv		xs_queue_reply(u, ok, sizeof(ok));
353214646Sjfv		mtx_unlock(&u->lock);
354214646Sjfv		break;
355214646Sjfv	case XS_UNWATCH:
356205869Sjfv		u->u.msg.tx_id = 0;
357205869Sjfv		error = xs_dev_watch_message_parse(&u->u.msg, &wpath, &wtoken);
358205869Sjfv		if (error)
359205869Sjfv			break;
360214646Sjfv		watch = xs_dev_find_watch(u, wtoken);
361214646Sjfv		if (watch == NULL) {
362205869Sjfv			error = EINVAL;
363205869Sjfv			break;
364205869Sjfv		}
365205869Sjfv
366250414Sluigi		LIST_REMOVE(watch, list);
367205869Sjfv		xs_unregister_watch(&watch->watch);
368205869Sjfv		free(watch->watch.node, M_XENSTORE);
369205869Sjfv		free(watch->token, M_XENSTORE);
370205869Sjfv		free(watch, M_XENSTORE);
371205869Sjfv		u->u.msg.len = sizeof(ok);
372205869Sjfv		mtx_lock(&u->lock);
373205869Sjfv		xs_queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg));
374205869Sjfv		xs_queue_reply(u, ok, sizeof(ok));
375205869Sjfv		mtx_unlock(&u->lock);
376205869Sjfv		break;
377205869Sjfv	default:
378205869Sjfv		error = EINVAL;
379205869Sjfv		break;
380205869Sjfv	}
381205869Sjfv
382205869Sjfv	if (error != 0)
383205869Sjfv		xs_dev_return_error(u, error, u->u.msg.req_id, u->u.msg.tx_id);
384205869Sjfv
385205869Sjfv	/* Reset the write buffer. */
386205869Sjfv	u->len = 0;
387205869Sjfv
388205869Sjfv	return (0);
389205869Sjfv}
390205869Sjfv
391205869Sjfvstatic int
392205869Sjfvxs_dev_poll(struct cdev *dev, int events, struct thread *td)
393205869Sjfv{
394205869Sjfv	struct xs_dev_data *u;
395205869Sjfv	int error, mask;
396205869Sjfv
397205869Sjfv	error = devfs_get_cdevpriv((void **)&u);
398205869Sjfv	if (error != 0)
399205869Sjfv		return (POLLERR);
400205869Sjfv
401205869Sjfv	/* we can always write */
402205869Sjfv	mask = events & (POLLOUT | POLLWRNORM);
403205869Sjfv
404205869Sjfv	if (events & (POLLIN | POLLRDNORM)) {
405205869Sjfv		if (u->read_cons != u->read_prod) {
406205869Sjfv			mask |= events & (POLLIN | POLLRDNORM);
407205869Sjfv		} else {
408205869Sjfv			/* Record that someone is waiting */
409205869Sjfv			selrecord(td, &u->ev_rsel);
410205869Sjfv		}
411205869Sjfv	}
412205869Sjfv
413205869Sjfv	return (mask);
414205869Sjfv}
415205869Sjfv
416205869Sjfvstatic void
417205869Sjfvxs_dev_dtor(void *arg)
418205869Sjfv{
419205869Sjfv	struct xs_dev_data *u = arg;
420205869Sjfv	struct xs_dev_transaction *trans, *tmpt;
421205869Sjfv	struct xs_dev_watch *watch, *tmpw;
422205869Sjfv
423205869Sjfv	seldrain(&u->ev_rsel);
424214646Sjfv
425214646Sjfv	LIST_FOREACH_SAFE(trans, &u->transactions, list, tmpt) {
426214646Sjfv		xs_transaction_end(trans->handle, 1);
427205869Sjfv		LIST_REMOVE(trans, list);
428205869Sjfv		free(trans, M_XENSTORE);
429205869Sjfv	}
430205869Sjfv
431205869Sjfv	LIST_FOREACH_SAFE(watch, &u->watches, list, tmpw) {
432205869Sjfv		LIST_REMOVE(watch, list);
433205869Sjfv		xs_unregister_watch(&watch->watch);
434205869Sjfv		free(watch->watch.node, M_XENSTORE);
435205869Sjfv		free(watch->token, M_XENSTORE);
436205869Sjfv		free(watch, M_XENSTORE);
437205869Sjfv	}
438205869Sjfv	mtx_destroy(&u->lock);
439205869Sjfv
440205869Sjfv	free(u, M_XENSTORE);
441205869Sjfv}
442205869Sjfv
443205869Sjfvstatic int
444205869Sjfvxs_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
445205869Sjfv{
446205869Sjfv	struct xs_dev_data *u;
447205869Sjfv	int error;
448205869Sjfv
449205869Sjfv	u = malloc(sizeof(*u), M_XENSTORE, M_WAITOK|M_ZERO);
450205869Sjfv	mtx_init(&u->lock, "xsdev_lock", NULL, MTX_DEF);
451205869Sjfv	LIST_INIT(&u->transactions);
452205869Sjfv	LIST_INIT(&u->watches);
453205869Sjfv	error = devfs_set_cdevpriv(u, xs_dev_dtor);
454205869Sjfv	if (error != 0)
455205869Sjfv		free(u, M_XENSTORE);
456205869Sjfv
457205869Sjfv	return (error);
458205869Sjfv}
459205869Sjfv
460205869Sjfvstatic struct cdevsw xs_dev_cdevsw = {
461205869Sjfv	.d_version = D_VERSION,
462205869Sjfv	.d_read = xs_dev_read,
463205869Sjfv	.d_write = xs_dev_write,
464205869Sjfv	.d_open = xs_dev_open,
465205869Sjfv	.d_poll = xs_dev_poll,
466205869Sjfv	.d_name = "xs_dev",
467205869Sjfv};
468205869Sjfv
469205869Sjfv/*------------------ Private Device Attachment Functions  --------------------*/
470205869Sjfv/**
471205869Sjfv * \brief Identify instances of this device type in the system.
472205869Sjfv *
473205869Sjfv * \param driver  The driver performing this identify action.
474205869Sjfv * \param parent  The NewBus parent device for any devices this method adds.
475205869Sjfv */
476205869Sjfvstatic void
477205869Sjfvxs_dev_identify(driver_t *driver, device_t parent)
478205869Sjfv{
479205869Sjfv	/*
480205869Sjfv	 * A single device instance for our driver is always present
481205869Sjfv	 * in a system operating under Xen.
482205869Sjfv	 */
483205869Sjfv	BUS_ADD_CHILD(parent, 0, driver->name, 0);
484205869Sjfv}
485205869Sjfv
486205869Sjfv/**
487205869Sjfv * \brief Probe for the existence of the Xenstore device
488205869Sjfv *
489205869Sjfv * \param dev  NewBus device_t for this instance.
490205869Sjfv *
491205869Sjfv * \return  Always returns 0 indicating success.
492205869Sjfv */
493205869Sjfvstatic int
494205869Sjfvxs_dev_probe(device_t dev)
495205869Sjfv{
496205869Sjfv
497205869Sjfv	device_set_desc(dev, "Xenstore user-space device");
498	return (0);
499}
500
501/**
502 * \brief Attach the Xenstore device.
503 *
504 * \param dev  NewBus device_t for this instance.
505 *
506 * \return  On success, 0. Otherwise an errno value indicating the
507 *          type of failure.
508 */
509static int
510xs_dev_attach(device_t dev)
511{
512	struct cdev *xs_cdev;
513	struct sysctl_ctx_list *sysctl_ctx;
514	struct sysctl_oid *sysctl_tree;
515
516	sysctl_ctx = device_get_sysctl_ctx(dev);
517	sysctl_tree = device_get_sysctl_tree(dev);
518	if (sysctl_ctx == NULL || sysctl_tree == NULL)
519	    return (EINVAL);
520
521	SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
522	    "max_pending_watch_events", CTLFLAG_RW, &max_pending_watches, 0,
523	    "maximum amount of pending watch events to be delivered");
524
525	xs_cdev = make_dev_credf(MAKEDEV_ETERNAL, &xs_dev_cdevsw, 0, NULL,
526	    UID_ROOT, GID_WHEEL, 0400, "xen/xenstore");
527	if (xs_cdev == NULL)
528		return (EINVAL);
529
530	return (0);
531}
532
533/*-------------------- Private Device Attachment Data  -----------------------*/
534static device_method_t xs_dev_methods[] = {
535	/* Device interface */
536	DEVMETHOD(device_identify,	xs_dev_identify),
537	DEVMETHOD(device_probe,         xs_dev_probe),
538	DEVMETHOD(device_attach,        xs_dev_attach),
539
540	DEVMETHOD_END
541};
542
543DEFINE_CLASS_0(xs_dev, xs_dev_driver, xs_dev_methods, 0);
544
545DRIVER_MODULE(xs_dev, xenstore, xs_dev_driver, NULL, NULL);
546