xenstore_dev.c revision 214077
1181624Skmacy/*
2214077Sgibbs * xenstore_dev.c
3181624Skmacy *
4214077Sgibbs * Driver giving user-space access to the kernel's connection to the
5214077Sgibbs * XenStore service.
6181624Skmacy *
7181624Skmacy * Copyright (c) 2005, Christian Limpach
8181624Skmacy * Copyright (c) 2005, Rusty Russell, IBM Corporation
9181624Skmacy *
10181624Skmacy * This file may be distributed separately from the Linux kernel, or
11181624Skmacy * incorporated into other software packages, subject to the following license:
12181624Skmacy *
13181624Skmacy * Permission is hereby granted, free of charge, to any person obtaining a copy
14181624Skmacy * of this source file (the "Software"), to deal in the Software without
15181624Skmacy * restriction, including without limitation the rights to use, copy, modify,
16181624Skmacy * merge, publish, distribute, sublicense, and/or sell copies of the Software,
17181624Skmacy * and to permit persons to whom the Software is furnished to do so, subject to
18181624Skmacy * the following conditions:
19181624Skmacy *
20181624Skmacy * The above copyright notice and this permission notice shall be included in
21181624Skmacy * all copies or substantial portions of the Software.
22181624Skmacy *
23181624Skmacy * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24181624Skmacy * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25181624Skmacy * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26181624Skmacy * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27181624Skmacy * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28181624Skmacy * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
29181624Skmacy * IN THE SOFTWARE.
30181624Skmacy */
31181624Skmacy
32181624Skmacy
33181624Skmacy#include <sys/cdefs.h>
34181624Skmacy__FBSDID("$FreeBSD: head/sys/xen/xenstore/xenstore_dev.c 214077 2010-10-19 20:53:30Z gibbs $");
35181624Skmacy
36181624Skmacy#include <sys/types.h>
37181624Skmacy#include <sys/cdefs.h>
38181624Skmacy#include <sys/errno.h>
39181624Skmacy#include <sys/uio.h>
40181624Skmacy#include <sys/param.h>
41181624Skmacy#include <sys/systm.h>
42181624Skmacy#include <sys/proc.h>
43181624Skmacy#include <sys/kernel.h>
44181624Skmacy#include <sys/malloc.h>
45181624Skmacy#include <sys/conf.h>
46181624Skmacy
47181747Skmacy#include <machine/xen/xen-os.h>
48214077Sgibbs
49186557Skmacy#include <xen/hypervisor.h>
50214077Sgibbs#include <xen/xenstore/xenstorevar.h>
51214077Sgibbs#include <xen/xenstore/xenstore_internal.h>
52181624Skmacy
53214077Sgibbsstruct xs_dev_transaction {
54214077Sgibbs	LIST_ENTRY(xs_dev_transaction) list;
55214077Sgibbs	struct xs_transaction handle;
56181624Skmacy};
57181624Skmacy
58214077Sgibbsstruct xs_dev_data {
59181624Skmacy	/* In-progress transaction. */
60214077Sgibbs	LIST_HEAD(xdd_list_head, xs_dev_transaction) transactions;
61181624Skmacy
62181624Skmacy	/* Partial request. */
63181624Skmacy	unsigned int len;
64181624Skmacy	union {
65181624Skmacy		struct xsd_sockmsg msg;
66181624Skmacy		char buffer[PAGE_SIZE];
67181624Skmacy	} u;
68181624Skmacy
69181624Skmacy	/* Response queue. */
70181624Skmacy#define MASK_READ_IDX(idx) ((idx)&(PAGE_SIZE-1))
71181624Skmacy	char read_buffer[PAGE_SIZE];
72181624Skmacy	unsigned int read_cons, read_prod;
73181624Skmacy};
74186557Skmacy
75181624Skmacystatic int
76214077Sgibbsxs_dev_read(struct cdev *dev, struct uio *uio, int ioflag)
77181624Skmacy{
78186557Skmacy	int error;
79214077Sgibbs	struct xs_dev_data *u = dev->si_drv1;
80181624Skmacy
81186557Skmacy	while (u->read_prod == u->read_cons) {
82214077Sgibbs		error = tsleep(u, PCATCH, "xsdread", hz/10);
83186557Skmacy		if (error && error != EWOULDBLOCK)
84186557Skmacy			return (error);
85186557Skmacy	}
86181624Skmacy
87186557Skmacy	while (uio->uio_resid > 0) {
88181624Skmacy		if (u->read_cons == u->read_prod)
89181624Skmacy			break;
90186557Skmacy		error = uiomove(&u->read_buffer[MASK_READ_IDX(u->read_cons)],
91186557Skmacy		    1, uio);
92186557Skmacy		if (error)
93186557Skmacy			return (error);
94181624Skmacy		u->read_cons++;
95181624Skmacy	}
96186557Skmacy	return (0);
97181624Skmacy}
98181624Skmacy
99186557Skmacystatic void
100214077Sgibbsxs_queue_reply(struct xs_dev_data *u, char *data, unsigned int len)
101181624Skmacy{
102181624Skmacy	int i;
103181624Skmacy
104181624Skmacy	for (i = 0; i < len; i++, u->read_prod++)
105181624Skmacy		u->read_buffer[MASK_READ_IDX(u->read_prod)] = data[i];
106181624Skmacy
107186557Skmacy	KASSERT((u->read_prod - u->read_cons) <= sizeof(u->read_buffer),
108186557Skmacy	    ("xenstore reply too big"));
109181624Skmacy
110186557Skmacy	wakeup(u);
111181624Skmacy}
112181624Skmacy
113181624Skmacystatic int
114214077Sgibbsxs_dev_write(struct cdev *dev, struct uio *uio, int ioflag)
115181624Skmacy{
116186557Skmacy	int error;
117214077Sgibbs	struct xs_dev_data *u = dev->si_drv1;
118214077Sgibbs	struct xs_dev_transaction *trans;
119181624Skmacy	void *reply;
120186557Skmacy	int len = uio->uio_resid;
121181624Skmacy
122181624Skmacy	if ((len + u->len) > sizeof(u->u.buffer))
123186557Skmacy		return (EINVAL);
124181624Skmacy
125186557Skmacy	error = uiomove(u->u.buffer + u->len, len, uio);
126186557Skmacy	if (error)
127186557Skmacy		return (error);
128181624Skmacy
129181624Skmacy	u->len += len;
130181624Skmacy	if (u->len < (sizeof(u->u.msg) + u->u.msg.len))
131186557Skmacy		return (0);
132181624Skmacy
133181624Skmacy	switch (u->u.msg.type) {
134181624Skmacy	case XS_TRANSACTION_START:
135181624Skmacy	case XS_TRANSACTION_END:
136181624Skmacy	case XS_DIRECTORY:
137181624Skmacy	case XS_READ:
138181624Skmacy	case XS_GET_PERMS:
139181624Skmacy	case XS_RELEASE:
140181624Skmacy	case XS_GET_DOMAIN_PATH:
141181624Skmacy	case XS_WRITE:
142181624Skmacy	case XS_MKDIR:
143181624Skmacy	case XS_RM:
144181624Skmacy	case XS_SET_PERMS:
145214077Sgibbs		error = xs_dev_request_and_reply(&u->u.msg, &reply);
146186557Skmacy		if (!error) {
147181624Skmacy			if (u->u.msg.type == XS_TRANSACTION_START) {
148214077Sgibbs				trans = malloc(sizeof(*trans), M_XENSTORE,
149186557Skmacy				    M_WAITOK);
150186557Skmacy				trans->handle.id = strtoul(reply, NULL, 0);
151181624Skmacy				LIST_INSERT_HEAD(&u->transactions, trans, list);
152181624Skmacy			} else if (u->u.msg.type == XS_TRANSACTION_END) {
153186557Skmacy				LIST_FOREACH(trans, &u->transactions, list)
154186557Skmacy					if (trans->handle.id == u->u.msg.tx_id)
155181624Skmacy						break;
156181624Skmacy#if 0 /* XXX does this mean the list is empty? */
157181624Skmacy				BUG_ON(&trans->list == &u->transactions);
158181624Skmacy#endif
159181624Skmacy				LIST_REMOVE(trans, list);
160214077Sgibbs				free(trans, M_XENSTORE);
161181624Skmacy			}
162214077Sgibbs			xs_queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg));
163214077Sgibbs			xs_queue_reply(u, (char *)reply, u->u.msg.len);
164214077Sgibbs			free(reply, M_XENSTORE);
165181624Skmacy		}
166181624Skmacy		break;
167181624Skmacy
168181624Skmacy	default:
169186557Skmacy		error = EINVAL;
170181624Skmacy		break;
171181624Skmacy	}
172181624Skmacy
173186557Skmacy	if (error == 0)
174181624Skmacy		u->len = 0;
175181624Skmacy
176186557Skmacy	return (error);
177181624Skmacy}
178181624Skmacy
179186557Skmacystatic int
180214077Sgibbsxs_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
181181624Skmacy{
182214077Sgibbs	struct xs_dev_data *u;
183181624Skmacy
184181624Skmacy#if 0 /* XXX figure out if equiv needed */
185181624Skmacy	nonseekable_open(inode, filp);
186181624Skmacy#endif
187214077Sgibbs	u = malloc(sizeof(*u), M_XENSTORE, M_WAITOK|M_ZERO);
188181624Skmacy	LIST_INIT(&u->transactions);
189181624Skmacy        dev->si_drv1 = u;
190181624Skmacy
191186557Skmacy	return (0);
192181624Skmacy}
193181624Skmacy
194186557Skmacystatic int
195214077Sgibbsxs_dev_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
196181624Skmacy{
197214077Sgibbs	struct xs_dev_data *u = dev->si_drv1;
198214077Sgibbs	struct xs_dev_transaction *trans, *tmp;
199181624Skmacy
200181624Skmacy	LIST_FOREACH_SAFE(trans, &u->transactions, list, tmp) {
201214077Sgibbs		xs_transaction_end(trans->handle, 1);
202181624Skmacy		LIST_REMOVE(trans, list);
203214077Sgibbs		free(trans, M_XENSTORE);
204181624Skmacy	}
205181624Skmacy
206214077Sgibbs	free(u, M_XENSTORE);
207186557Skmacy	return (0);
208181624Skmacy}
209181624Skmacy
210214077Sgibbsstatic struct cdevsw xs_dev_cdevsw = {
211181624Skmacy	.d_version = D_VERSION,
212214077Sgibbs	.d_read = xs_dev_read,
213214077Sgibbs	.d_write = xs_dev_write,
214214077Sgibbs	.d_open = xs_dev_open,
215214077Sgibbs	.d_close = xs_dev_close,
216214077Sgibbs	.d_name = "xs_dev",
217181624Skmacy};
218181624Skmacy
219214077Sgibbsvoid
220214077Sgibbsxs_dev_init()
221181624Skmacy{
222214077Sgibbs	make_dev(&xs_dev_cdevsw, 0, UID_ROOT, GID_WHEEL, 0400,
223214077Sgibbs	    "xen/xenstore");
224181624Skmacy}
225