xenstore_dev.c revision 272318
1/*
2 * xenstore_dev.c
3 *
4 * Driver giving user-space access to the kernel's connection to the
5 * XenStore service.
6 *
7 * Copyright (c) 2005, Christian Limpach
8 * Copyright (c) 2005, Rusty Russell, IBM Corporation
9 *
10 * This file may be distributed separately from the Linux kernel, or
11 * incorporated into other software packages, subject to the following license:
12 *
13 * Permission is hereby granted, free of charge, to any person obtaining a copy
14 * of this source file (the "Software"), to deal in the Software without
15 * restriction, including without limitation the rights to use, copy, modify,
16 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
17 * and to permit persons to whom the Software is furnished to do so, subject to
18 * the following conditions:
19 *
20 * The above copyright notice and this permission notice shall be included in
21 * all copies or substantial portions of the Software.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
29 * IN THE SOFTWARE.
30 */
31
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: head/sys/dev/xen/xenstore/xenstore_dev.c 272318 2014-09-30 17:31:04Z royger $");
35
36#include <sys/types.h>
37#include <sys/cdefs.h>
38#include <sys/errno.h>
39#include <sys/uio.h>
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/proc.h>
43#include <sys/kernel.h>
44#include <sys/malloc.h>
45#include <sys/conf.h>
46#include <sys/module.h>
47
48#include <xen/xen-os.h>
49
50#include <xen/hypervisor.h>
51#include <xen/xenstore/xenstorevar.h>
52#include <xen/xenstore/xenstore_internal.h>
53
54struct xs_dev_transaction {
55	LIST_ENTRY(xs_dev_transaction) list;
56	struct xs_transaction handle;
57};
58
59struct xs_dev_data {
60	/* In-progress transaction. */
61	LIST_HEAD(xdd_list_head, xs_dev_transaction) transactions;
62
63	/* Partial request. */
64	unsigned int len;
65	union {
66		struct xsd_sockmsg msg;
67		char buffer[PAGE_SIZE];
68	} u;
69
70	/* Response queue. */
71#define MASK_READ_IDX(idx) ((idx)&(PAGE_SIZE-1))
72	char read_buffer[PAGE_SIZE];
73	unsigned int read_cons, read_prod;
74};
75
76static int
77xs_dev_read(struct cdev *dev, struct uio *uio, int ioflag)
78{
79	int error;
80	struct xs_dev_data *u = dev->si_drv1;
81
82	while (u->read_prod == u->read_cons) {
83		error = tsleep(u, PCATCH, "xsdread", hz/10);
84		if (error && error != EWOULDBLOCK)
85			return (error);
86	}
87
88	while (uio->uio_resid > 0) {
89		if (u->read_cons == u->read_prod)
90			break;
91		error = uiomove(&u->read_buffer[MASK_READ_IDX(u->read_cons)],
92		    1, uio);
93		if (error)
94			return (error);
95		u->read_cons++;
96	}
97	return (0);
98}
99
100static void
101xs_queue_reply(struct xs_dev_data *u, char *data, unsigned int len)
102{
103	int i;
104
105	for (i = 0; i < len; i++, u->read_prod++)
106		u->read_buffer[MASK_READ_IDX(u->read_prod)] = data[i];
107
108	KASSERT((u->read_prod - u->read_cons) <= sizeof(u->read_buffer),
109	    ("xenstore reply too big"));
110
111	wakeup(u);
112}
113
114static int
115xs_dev_write(struct cdev *dev, struct uio *uio, int ioflag)
116{
117	int error;
118	struct xs_dev_data *u = dev->si_drv1;
119	struct xs_dev_transaction *trans;
120	void *reply;
121	int len = uio->uio_resid;
122
123	if ((len + u->len) > sizeof(u->u.buffer))
124		return (EINVAL);
125
126	error = uiomove(u->u.buffer + u->len, len, uio);
127	if (error)
128		return (error);
129
130	u->len += len;
131	if (u->len < (sizeof(u->u.msg) + u->u.msg.len))
132		return (0);
133
134	switch (u->u.msg.type) {
135	case XS_TRANSACTION_START:
136	case XS_TRANSACTION_END:
137	case XS_DIRECTORY:
138	case XS_READ:
139	case XS_GET_PERMS:
140	case XS_RELEASE:
141	case XS_GET_DOMAIN_PATH:
142	case XS_WRITE:
143	case XS_MKDIR:
144	case XS_RM:
145	case XS_SET_PERMS:
146		error = xs_dev_request_and_reply(&u->u.msg, &reply);
147		if (!error) {
148			if (u->u.msg.type == XS_TRANSACTION_START) {
149				trans = malloc(sizeof(*trans), M_XENSTORE,
150				    M_WAITOK);
151				trans->handle.id = strtoul(reply, NULL, 0);
152				LIST_INSERT_HEAD(&u->transactions, trans, list);
153			} else if (u->u.msg.type == XS_TRANSACTION_END) {
154				LIST_FOREACH(trans, &u->transactions, list)
155					if (trans->handle.id == u->u.msg.tx_id)
156						break;
157#if 0 /* XXX does this mean the list is empty? */
158				BUG_ON(&trans->list == &u->transactions);
159#endif
160				LIST_REMOVE(trans, list);
161				free(trans, M_XENSTORE);
162			}
163			xs_queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg));
164			xs_queue_reply(u, (char *)reply, u->u.msg.len);
165			free(reply, M_XENSTORE);
166		}
167		break;
168
169	default:
170		error = EINVAL;
171		break;
172	}
173
174	if (error == 0)
175		u->len = 0;
176
177	return (error);
178}
179
180static int
181xs_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
182{
183	struct xs_dev_data *u;
184
185#if 0 /* XXX figure out if equiv needed */
186	nonseekable_open(inode, filp);
187#endif
188	u = malloc(sizeof(*u), M_XENSTORE, M_WAITOK|M_ZERO);
189	LIST_INIT(&u->transactions);
190        dev->si_drv1 = u;
191
192	return (0);
193}
194
195static int
196xs_dev_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
197{
198	struct xs_dev_data *u = dev->si_drv1;
199	struct xs_dev_transaction *trans, *tmp;
200
201	LIST_FOREACH_SAFE(trans, &u->transactions, list, tmp) {
202		xs_transaction_end(trans->handle, 1);
203		LIST_REMOVE(trans, list);
204		free(trans, M_XENSTORE);
205	}
206
207	free(u, M_XENSTORE);
208	return (0);
209}
210
211static struct cdevsw xs_dev_cdevsw = {
212	.d_version = D_VERSION,
213	.d_read = xs_dev_read,
214	.d_write = xs_dev_write,
215	.d_open = xs_dev_open,
216	.d_close = xs_dev_close,
217	.d_name = "xs_dev",
218};
219
220/*------------------ Private Device Attachment Functions  --------------------*/
221/**
222 * \brief Identify instances of this device type in the system.
223 *
224 * \param driver  The driver performing this identify action.
225 * \param parent  The NewBus parent device for any devices this method adds.
226 */
227static void
228xs_dev_identify(driver_t *driver __unused, device_t parent)
229{
230	/*
231	 * A single device instance for our driver is always present
232	 * in a system operating under Xen.
233	 */
234	BUS_ADD_CHILD(parent, 0, driver->name, 0);
235}
236
237/**
238 * \brief Probe for the existance of the Xenstore device
239 *
240 * \param dev  NewBus device_t for this instance.
241 *
242 * \return  Always returns 0 indicating success.
243 */
244static int
245xs_dev_probe(device_t dev)
246{
247
248	device_set_desc(dev, "Xenstore user-space device");
249	return (0);
250}
251
252/**
253 * \brief Attach the Xenstore device.
254 *
255 * \param dev  NewBus device_t for this instance.
256 *
257 * \return  On success, 0. Otherwise an errno value indicating the
258 *          type of failure.
259 */
260static int
261xs_dev_attach(device_t dev)
262{
263	struct cdev *xs_cdev;
264
265	xs_cdev = make_dev(&xs_dev_cdevsw, 0, UID_ROOT, GID_WHEEL, 0400,
266	    "xen/xenstore");
267	if (xs_cdev == NULL)
268		return (EINVAL);
269
270	return (0);
271}
272
273/*-------------------- Private Device Attachment Data  -----------------------*/
274static device_method_t xs_dev_methods[] = {
275	/* Device interface */
276	DEVMETHOD(device_identify,	xs_dev_identify),
277	DEVMETHOD(device_probe,         xs_dev_probe),
278	DEVMETHOD(device_attach,        xs_dev_attach),
279
280	DEVMETHOD_END
281};
282
283DEFINE_CLASS_0(xs_dev, xs_dev_driver, xs_dev_methods, 0);
284devclass_t xs_dev_devclass;
285
286DRIVER_MODULE(xs_dev, xenstore, xs_dev_driver, xs_dev_devclass,
287    NULL, NULL);
288