xenstore_dev.c revision 278844
174870Sru/*
274870Sru * xenstore_dev.c
311819Sjulian *
4119071Sobrien * Driver giving user-space access to the kernel's connection to the
511819Sjulian * XenStore service.
674870Sru *
711819Sjulian * Copyright (c) 2005, Christian Limpach
811819Sjulian * Copyright (c) 2005, Rusty Russell, IBM Corporation
9201381Sed *
10201381Sed * This file may be distributed separately from the Linux kernel, or
1111819Sjulian * 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 278844 2015-02-16 09:53:43Z 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;
81
82	error = devfs_get_cdevpriv((void **)&u);
83	if (error != 0)
84		return (error);
85
86	while (u->read_prod == u->read_cons) {
87		error = tsleep(u, PCATCH, "xsdread", hz/10);
88		if (error && error != EWOULDBLOCK)
89			return (error);
90	}
91
92	while (uio->uio_resid > 0) {
93		if (u->read_cons == u->read_prod)
94			break;
95		error = uiomove(&u->read_buffer[MASK_READ_IDX(u->read_cons)],
96		    1, uio);
97		if (error)
98			return (error);
99		u->read_cons++;
100	}
101	return (0);
102}
103
104static void
105xs_queue_reply(struct xs_dev_data *u, char *data, unsigned int len)
106{
107	int i;
108
109	for (i = 0; i < len; i++, u->read_prod++)
110		u->read_buffer[MASK_READ_IDX(u->read_prod)] = data[i];
111
112	KASSERT((u->read_prod - u->read_cons) <= sizeof(u->read_buffer),
113	    ("xenstore reply too big"));
114
115	wakeup(u);
116}
117
118static int
119xs_dev_write(struct cdev *dev, struct uio *uio, int ioflag)
120{
121	int error;
122	struct xs_dev_data *u;
123	struct xs_dev_transaction *trans;
124	void *reply;
125	int len = uio->uio_resid;
126
127	error = devfs_get_cdevpriv((void **)&u);
128	if (error != 0)
129		return (error);
130
131	if ((len + u->len) > sizeof(u->u.buffer))
132		return (EINVAL);
133
134	error = uiomove(u->u.buffer + u->len, len, uio);
135	if (error)
136		return (error);
137
138	u->len += len;
139	if (u->len < (sizeof(u->u.msg) + u->u.msg.len))
140		return (0);
141
142	switch (u->u.msg.type) {
143	case XS_TRANSACTION_START:
144	case XS_TRANSACTION_END:
145	case XS_DIRECTORY:
146	case XS_READ:
147	case XS_GET_PERMS:
148	case XS_RELEASE:
149	case XS_GET_DOMAIN_PATH:
150	case XS_WRITE:
151	case XS_MKDIR:
152	case XS_RM:
153	case XS_SET_PERMS:
154		error = xs_dev_request_and_reply(&u->u.msg, &reply);
155		if (!error) {
156			if (u->u.msg.type == XS_TRANSACTION_START) {
157				trans = malloc(sizeof(*trans), M_XENSTORE,
158				    M_WAITOK);
159				trans->handle.id = strtoul(reply, NULL, 0);
160				LIST_INSERT_HEAD(&u->transactions, trans, list);
161			} else if (u->u.msg.type == XS_TRANSACTION_END) {
162				LIST_FOREACH(trans, &u->transactions, list)
163					if (trans->handle.id == u->u.msg.tx_id)
164						break;
165#if 0 /* XXX does this mean the list is empty? */
166				BUG_ON(&trans->list == &u->transactions);
167#endif
168				LIST_REMOVE(trans, list);
169				free(trans, M_XENSTORE);
170			}
171			xs_queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg));
172			xs_queue_reply(u, (char *)reply, u->u.msg.len);
173			free(reply, M_XENSTORE);
174		}
175		break;
176
177	default:
178		error = EINVAL;
179		break;
180	}
181
182	if (error == 0)
183		u->len = 0;
184
185	return (error);
186}
187
188static void
189xs_dev_dtor(void *arg)
190{
191	struct xs_dev_data *u = arg;
192	struct xs_dev_transaction *trans, *tmp;
193
194	LIST_FOREACH_SAFE(trans, &u->transactions, list, tmp) {
195		xs_transaction_end(trans->handle, 1);
196		LIST_REMOVE(trans, list);
197		free(trans, M_XENSTORE);
198	}
199
200	free(u, M_XENSTORE);
201}
202
203static int
204xs_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
205{
206	struct xs_dev_data *u;
207	int error;
208
209	u = malloc(sizeof(*u), M_XENSTORE, M_WAITOK|M_ZERO);
210	LIST_INIT(&u->transactions);
211	error = devfs_set_cdevpriv(u, xs_dev_dtor);
212	if (error != 0)
213		free(u, M_XENSTORE);
214
215	return (error);
216}
217
218static struct cdevsw xs_dev_cdevsw = {
219	.d_version = D_VERSION,
220	.d_read = xs_dev_read,
221	.d_write = xs_dev_write,
222	.d_open = xs_dev_open,
223	.d_name = "xs_dev",
224};
225
226/*------------------ Private Device Attachment Functions  --------------------*/
227/**
228 * \brief Identify instances of this device type in the system.
229 *
230 * \param driver  The driver performing this identify action.
231 * \param parent  The NewBus parent device for any devices this method adds.
232 */
233static void
234xs_dev_identify(driver_t *driver __unused, device_t parent)
235{
236	/*
237	 * A single device instance for our driver is always present
238	 * in a system operating under Xen.
239	 */
240	BUS_ADD_CHILD(parent, 0, driver->name, 0);
241}
242
243/**
244 * \brief Probe for the existance of the Xenstore device
245 *
246 * \param dev  NewBus device_t for this instance.
247 *
248 * \return  Always returns 0 indicating success.
249 */
250static int
251xs_dev_probe(device_t dev)
252{
253
254	device_set_desc(dev, "Xenstore user-space device");
255	return (0);
256}
257
258/**
259 * \brief Attach the Xenstore device.
260 *
261 * \param dev  NewBus device_t for this instance.
262 *
263 * \return  On success, 0. Otherwise an errno value indicating the
264 *          type of failure.
265 */
266static int
267xs_dev_attach(device_t dev)
268{
269	struct cdev *xs_cdev;
270
271	xs_cdev = make_dev_credf(MAKEDEV_ETERNAL, &xs_dev_cdevsw, 0, NULL,
272	    UID_ROOT, GID_WHEEL, 0400, "xen/xenstore");
273	if (xs_cdev == NULL)
274		return (EINVAL);
275
276	return (0);
277}
278
279/*-------------------- Private Device Attachment Data  -----------------------*/
280static device_method_t xs_dev_methods[] = {
281	/* Device interface */
282	DEVMETHOD(device_identify,	xs_dev_identify),
283	DEVMETHOD(device_probe,         xs_dev_probe),
284	DEVMETHOD(device_attach,        xs_dev_attach),
285
286	DEVMETHOD_END
287};
288
289DEFINE_CLASS_0(xs_dev, xs_dev_driver, xs_dev_methods, 0);
290devclass_t xs_dev_devclass;
291
292DRIVER_MODULE(xs_dev, xenstore, xs_dev_driver, xs_dev_devclass,
293    NULL, NULL);
294