xenbus_dev.c revision 1.17 1 1.17 jdolecek /* $NetBSD: xenbus_dev.c,v 1.17 2020/04/07 16:10:48 jdolecek Exp $ */
2 1.1 bouyer /*
3 1.1 bouyer * xenbus_dev.c
4 1.1 bouyer *
5 1.1 bouyer * Driver giving user-space access to the kernel's xenbus connection
6 1.1 bouyer * to xenstore.
7 1.1 bouyer *
8 1.1 bouyer * Copyright (c) 2005, Christian Limpach
9 1.1 bouyer * Copyright (c) 2005, Rusty Russell, IBM Corporation
10 1.1 bouyer *
11 1.1 bouyer * This file may be distributed separately from the Linux kernel, or
12 1.1 bouyer * incorporated into other software packages, subject to the following license:
13 1.1 bouyer *
14 1.1 bouyer * Permission is hereby granted, free of charge, to any person obtaining a copy
15 1.1 bouyer * of this source file (the "Software"), to deal in the Software without
16 1.1 bouyer * restriction, including without limitation the rights to use, copy, modify,
17 1.1 bouyer * merge, publish, distribute, sublicense, and/or sell copies of the Software,
18 1.1 bouyer * and to permit persons to whom the Software is furnished to do so, subject to
19 1.1 bouyer * the following conditions:
20 1.1 bouyer *
21 1.1 bouyer * The above copyright notice and this permission notice shall be included in
22 1.1 bouyer * all copies or substantial portions of the Software.
23 1.1 bouyer *
24 1.1 bouyer * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 1.1 bouyer * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 1.1 bouyer * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 1.1 bouyer * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 1.1 bouyer * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 1.1 bouyer * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30 1.1 bouyer * IN THE SOFTWARE.
31 1.1 bouyer */
32 1.1 bouyer
33 1.2 bouyer #include <sys/cdefs.h>
34 1.17 jdolecek __KERNEL_RCSID(0, "$NetBSD: xenbus_dev.c,v 1.17 2020/04/07 16:10:48 jdolecek Exp $");
35 1.1 bouyer
36 1.2 bouyer #include "opt_xen.h"
37 1.2 bouyer
38 1.2 bouyer #include <sys/types.h>
39 1.2 bouyer #include <sys/null.h>
40 1.2 bouyer #include <sys/errno.h>
41 1.2 bouyer #include <sys/param.h>
42 1.2 bouyer #include <sys/proc.h>
43 1.2 bouyer #include <sys/systm.h>
44 1.2 bouyer #include <sys/dirent.h>
45 1.2 bouyer #include <sys/stat.h>
46 1.2 bouyer #include <sys/tree.h>
47 1.2 bouyer #include <sys/vnode.h>
48 1.2 bouyer #include <miscfs/specfs/specdev.h>
49 1.2 bouyer #include <miscfs/kernfs/kernfs.h>
50 1.2 bouyer
51 1.6 bouyer #include <xen/kernfs_machdep.h>
52 1.6 bouyer
53 1.6 bouyer #include <xen/hypervisor.h>
54 1.6 bouyer #include <xen/xenbus.h>
55 1.1 bouyer #include "xenbus_comms.h"
56 1.1 bouyer
57 1.2 bouyer static int xenbus_dev_read(void *);
58 1.2 bouyer static int xenbus_dev_write(void *);
59 1.2 bouyer static int xenbus_dev_open(void *);
60 1.2 bouyer static int xenbus_dev_close(void *);
61 1.3 bouyer static int xsd_port_read(void *);
62 1.1 bouyer
63 1.2 bouyer #define DIR_MODE (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
64 1.2 bouyer #define PRIVCMD_MODE (S_IRUSR | S_IWUSR)
65 1.2 bouyer static const struct kernfs_fileop xenbus_fileops[] = {
66 1.2 bouyer { .kf_fileop = KERNFS_FILEOP_OPEN, .kf_vop = xenbus_dev_open },
67 1.2 bouyer { .kf_fileop = KERNFS_FILEOP_CLOSE, .kf_vop = xenbus_dev_close },
68 1.2 bouyer { .kf_fileop = KERNFS_FILEOP_READ, .kf_vop = xenbus_dev_read },
69 1.2 bouyer { .kf_fileop = KERNFS_FILEOP_WRITE, .kf_vop = xenbus_dev_write },
70 1.2 bouyer };
71 1.2 bouyer
72 1.3 bouyer #define XSD_MODE (S_IRUSR)
73 1.3 bouyer static const struct kernfs_fileop xsd_port_fileops[] = {
74 1.3 bouyer { .kf_fileop = KERNFS_FILEOP_READ, .kf_vop = xsd_port_read },
75 1.3 bouyer };
76 1.2 bouyer
77 1.11 bouyer static kmutex_t xenbus_dev_open_mtx;
78 1.11 bouyer
79 1.2 bouyer void
80 1.8 cegger xenbus_kernfs_init(void)
81 1.2 bouyer {
82 1.2 bouyer kernfs_entry_t *dkt;
83 1.2 bouyer kfstype kfst;
84 1.2 bouyer
85 1.2 bouyer kfst = KERNFS_ALLOCTYPE(xenbus_fileops);
86 1.15 jdolecek KERNFS_ALLOCENTRY(dkt, KM_SLEEP);
87 1.2 bouyer KERNFS_INITENTRY(dkt, DT_REG, "xenbus", NULL, kfst, VREG,
88 1.2 bouyer PRIVCMD_MODE);
89 1.2 bouyer kernfs_addentry(kernxen_pkt, dkt);
90 1.3 bouyer
91 1.9 jym if (xendomain_is_dom0()) {
92 1.9 jym kfst = KERNFS_ALLOCTYPE(xsd_port_fileops);
93 1.15 jdolecek KERNFS_ALLOCENTRY(dkt, KM_SLEEP);
94 1.9 jym KERNFS_INITENTRY(dkt, DT_REG, "xsd_port", NULL,
95 1.9 jym kfst, VREG, XSD_MODE);
96 1.9 jym kernfs_addentry(kernxen_pkt, dkt);
97 1.9 jym }
98 1.11 bouyer mutex_init(&xenbus_dev_open_mtx, MUTEX_DEFAULT, IPL_NONE);
99 1.2 bouyer }
100 1.2 bouyer
101 1.11 bouyer /*
102 1.11 bouyer * several process may open /kern/xen/xenbus in parallel.
103 1.11 bouyer * In a transaction one or more write is followed by one or more read.
104 1.11 bouyer * Unfortunably we don't get a file descriptor identifier down there,
105 1.11 bouyer * which we could use to link a read() to a transaction started in a write().
106 1.11 bouyer * To work around this we keep a list of lwp that opended the xenbus file.
107 1.11 bouyer * This assumes that a single lwp won't open /kern/xen/xenbus more
108 1.11 bouyer * than once, and that a transaction started by one lwp won't be ended
109 1.11 bouyer * by another.
110 1.11 bouyer * because of this, we also assume that we always got the data before
111 1.11 bouyer * the read() syscall.
112 1.11 bouyer */
113 1.11 bouyer
114 1.11 bouyer struct xenbus_dev_transaction {
115 1.11 bouyer SLIST_ENTRY(xenbus_dev_transaction) trans_next;
116 1.11 bouyer struct xenbus_transaction *handle;
117 1.11 bouyer };
118 1.11 bouyer
119 1.11 bouyer struct xenbus_dev_lwp {
120 1.11 bouyer SLIST_ENTRY(xenbus_dev_lwp) lwp_next;
121 1.11 bouyer SLIST_HEAD(, xenbus_dev_transaction) transactions;
122 1.11 bouyer lwp_t *lwp;
123 1.11 bouyer /* Response queue. */
124 1.2 bouyer #define BUFFER_SIZE (PAGE_SIZE)
125 1.2 bouyer #define MASK_READ_IDX(idx) ((idx)&(BUFFER_SIZE-1))
126 1.11 bouyer char read_buffer[BUFFER_SIZE];
127 1.11 bouyer unsigned int read_cons, read_prod;
128 1.1 bouyer /* Partial request. */
129 1.1 bouyer unsigned int len;
130 1.1 bouyer union {
131 1.1 bouyer struct xsd_sockmsg msg;
132 1.2 bouyer char buffer[BUFFER_SIZE];
133 1.1 bouyer } u;
134 1.11 bouyer kmutex_t mtx;
135 1.11 bouyer };
136 1.1 bouyer
137 1.11 bouyer struct xenbus_dev_data {
138 1.11 bouyer /* lwps which opended this device */
139 1.11 bouyer SLIST_HEAD(, xenbus_dev_lwp) lwps;
140 1.11 bouyer kmutex_t mtx;
141 1.1 bouyer };
142 1.1 bouyer
143 1.11 bouyer
144 1.2 bouyer static int
145 1.2 bouyer xenbus_dev_read(void *v)
146 1.1 bouyer {
147 1.2 bouyer struct vop_read_args /* {
148 1.2 bouyer struct vnode *a_vp;
149 1.2 bouyer struct uio *a_uio;
150 1.2 bouyer int a_ioflag;
151 1.2 bouyer struct ucred *a_cred;
152 1.2 bouyer } */ *ap = v;
153 1.2 bouyer struct kernfs_node *kfs = VTOKERN(ap->a_vp);
154 1.2 bouyer struct uio *uio = ap->a_uio;
155 1.12 bouyer struct xenbus_dev_data *u;
156 1.11 bouyer struct xenbus_dev_lwp *xlwp;
157 1.2 bouyer int err;
158 1.2 bouyer off_t offset;
159 1.2 bouyer
160 1.12 bouyer mutex_enter(&xenbus_dev_open_mtx);
161 1.12 bouyer u = kfs->kfs_v;
162 1.12 bouyer if (u == NULL) {
163 1.12 bouyer mutex_exit(&xenbus_dev_open_mtx);
164 1.12 bouyer return EBADF;
165 1.12 bouyer }
166 1.11 bouyer mutex_enter(&u->mtx);
167 1.12 bouyer mutex_exit(&xenbus_dev_open_mtx);
168 1.11 bouyer SLIST_FOREACH(xlwp, &u->lwps, lwp_next) {
169 1.11 bouyer if (xlwp->lwp == curlwp) {
170 1.11 bouyer break;
171 1.11 bouyer }
172 1.11 bouyer }
173 1.11 bouyer if (xlwp == NULL) {
174 1.11 bouyer mutex_exit(&u->mtx);
175 1.11 bouyer return EBADF;
176 1.11 bouyer }
177 1.11 bouyer mutex_enter(&xlwp->mtx);
178 1.11 bouyer mutex_exit(&u->mtx);
179 1.11 bouyer
180 1.11 bouyer if (xlwp->read_prod == xlwp->read_cons) {
181 1.11 bouyer err = EWOULDBLOCK;
182 1.11 bouyer goto end;
183 1.2 bouyer }
184 1.11 bouyer
185 1.5 bouyer offset = uio->uio_offset;
186 1.11 bouyer if (xlwp->read_cons > xlwp->read_prod) {
187 1.11 bouyer err = uiomove(
188 1.11 bouyer &xlwp->read_buffer[MASK_READ_IDX(xlwp->read_cons)],
189 1.11 bouyer 0U - xlwp->read_cons, uio);
190 1.2 bouyer if (err)
191 1.2 bouyer goto end;
192 1.11 bouyer xlwp->read_cons += (uio->uio_offset - offset);
193 1.2 bouyer offset = uio->uio_offset;
194 1.1 bouyer }
195 1.11 bouyer err = uiomove(&xlwp->read_buffer[MASK_READ_IDX(xlwp->read_cons)],
196 1.11 bouyer xlwp->read_prod - xlwp->read_cons, uio);
197 1.2 bouyer if (err == 0)
198 1.11 bouyer xlwp->read_cons += (uio->uio_offset - offset);
199 1.1 bouyer
200 1.2 bouyer end:
201 1.11 bouyer mutex_exit(&xlwp->mtx);
202 1.2 bouyer return err;
203 1.1 bouyer }
204 1.1 bouyer
205 1.2 bouyer static void
206 1.11 bouyer queue_reply(struct xenbus_dev_lwp *xlwp,
207 1.1 bouyer char *data, unsigned int len)
208 1.1 bouyer {
209 1.1 bouyer int i;
210 1.11 bouyer KASSERT(mutex_owned(&xlwp->mtx));
211 1.11 bouyer for (i = 0; i < len; i++, xlwp->read_prod++)
212 1.11 bouyer xlwp->read_buffer[MASK_READ_IDX(xlwp->read_prod)] = data[i];
213 1.1 bouyer
214 1.11 bouyer KASSERT((xlwp->read_prod - xlwp->read_cons) <= sizeof(xlwp->read_buffer));
215 1.1 bouyer }
216 1.1 bouyer
217 1.2 bouyer static int
218 1.2 bouyer xenbus_dev_write(void *v)
219 1.1 bouyer {
220 1.2 bouyer struct vop_write_args /* {
221 1.2 bouyer struct vnode *a_vp;
222 1.2 bouyer struct uio *a_uio;
223 1.2 bouyer int a_ioflag;
224 1.2 bouyer struct ucred *a_cred;
225 1.2 bouyer } */ *ap = v;
226 1.2 bouyer struct kernfs_node *kfs = VTOKERN(ap->a_vp);
227 1.2 bouyer struct uio *uio = ap->a_uio;
228 1.2 bouyer
229 1.12 bouyer struct xenbus_dev_data *u;
230 1.11 bouyer struct xenbus_dev_lwp *xlwp;
231 1.1 bouyer struct xenbus_dev_transaction *trans;
232 1.1 bouyer void *reply;
233 1.2 bouyer int err;
234 1.2 bouyer size_t size;
235 1.2 bouyer
236 1.12 bouyer mutex_enter(&xenbus_dev_open_mtx);
237 1.12 bouyer u = kfs->kfs_v;
238 1.12 bouyer if (u == NULL) {
239 1.12 bouyer mutex_exit(&xenbus_dev_open_mtx);
240 1.12 bouyer return EBADF;
241 1.12 bouyer }
242 1.11 bouyer mutex_enter(&u->mtx);
243 1.12 bouyer mutex_exit(&xenbus_dev_open_mtx);
244 1.11 bouyer SLIST_FOREACH(xlwp, &u->lwps, lwp_next) {
245 1.11 bouyer if (xlwp->lwp == curlwp) {
246 1.11 bouyer break;
247 1.11 bouyer }
248 1.11 bouyer }
249 1.11 bouyer if (xlwp == NULL) {
250 1.11 bouyer mutex_exit(&u->mtx);
251 1.11 bouyer return EBADF;
252 1.11 bouyer }
253 1.11 bouyer mutex_enter(&xlwp->mtx);
254 1.11 bouyer mutex_exit(&u->mtx);
255 1.11 bouyer
256 1.11 bouyer if (uio->uio_offset < 0) {
257 1.11 bouyer err = EINVAL;
258 1.11 bouyer goto end;
259 1.11 bouyer }
260 1.2 bouyer size = uio->uio_resid;
261 1.1 bouyer
262 1.11 bouyer if ((size + xlwp->len) > sizeof(xlwp->u.buffer)) {
263 1.11 bouyer err = EINVAL;
264 1.11 bouyer goto end;
265 1.11 bouyer }
266 1.1 bouyer
267 1.11 bouyer err = uiomove(xlwp->u.buffer + xlwp->len,
268 1.11 bouyer sizeof(xlwp->u.buffer) - xlwp->len, uio);
269 1.11 bouyer if (err)
270 1.11 bouyer goto end;
271 1.11 bouyer
272 1.11 bouyer xlwp->len += size;
273 1.11 bouyer if (xlwp->len < (sizeof(xlwp->u.msg) + xlwp->u.msg.len))
274 1.11 bouyer goto end;
275 1.1 bouyer
276 1.11 bouyer switch (xlwp->u.msg.type) {
277 1.1 bouyer case XS_TRANSACTION_START:
278 1.1 bouyer case XS_TRANSACTION_END:
279 1.1 bouyer case XS_DIRECTORY:
280 1.1 bouyer case XS_READ:
281 1.1 bouyer case XS_GET_PERMS:
282 1.1 bouyer case XS_RELEASE:
283 1.1 bouyer case XS_GET_DOMAIN_PATH:
284 1.1 bouyer case XS_WRITE:
285 1.1 bouyer case XS_MKDIR:
286 1.1 bouyer case XS_RM:
287 1.1 bouyer case XS_SET_PERMS:
288 1.11 bouyer err = xenbus_dev_request_and_reply(&xlwp->u.msg, &reply);
289 1.2 bouyer if (err == 0) {
290 1.11 bouyer if (xlwp->u.msg.type == XS_TRANSACTION_START) {
291 1.16 jdolecek trans = kmem_alloc(sizeof(*trans), KM_SLEEP);
292 1.1 bouyer trans->handle = (struct xenbus_transaction *)
293 1.2 bouyer strtoul(reply, NULL, 0);
294 1.11 bouyer SLIST_INSERT_HEAD(&xlwp->transactions,
295 1.2 bouyer trans, trans_next);
296 1.11 bouyer } else if (xlwp->u.msg.type == XS_TRANSACTION_END) {
297 1.11 bouyer SLIST_FOREACH(trans, &xlwp->transactions,
298 1.2 bouyer trans_next) {
299 1.1 bouyer if ((unsigned long)trans->handle ==
300 1.11 bouyer (unsigned long)xlwp->u.msg.tx_id)
301 1.1 bouyer break;
302 1.2 bouyer }
303 1.11 bouyer if (trans == NULL) {
304 1.11 bouyer err = EINVAL;
305 1.11 bouyer goto end;
306 1.11 bouyer }
307 1.11 bouyer SLIST_REMOVE(&xlwp->transactions, trans,
308 1.2 bouyer xenbus_dev_transaction, trans_next);
309 1.16 jdolecek kmem_free(trans, sizeof(*trans));
310 1.1 bouyer }
311 1.11 bouyer queue_reply(xlwp, (char *)&xlwp->u.msg,
312 1.11 bouyer sizeof(xlwp->u.msg));
313 1.11 bouyer queue_reply(xlwp, (char *)reply, xlwp->u.msg.len);
314 1.17 jdolecek
315 1.17 jdolecek xenbus_dev_reply_free(&xlwp->u.msg, reply);
316 1.1 bouyer }
317 1.1 bouyer break;
318 1.1 bouyer
319 1.1 bouyer default:
320 1.2 bouyer err = EINVAL;
321 1.1 bouyer break;
322 1.1 bouyer }
323 1.1 bouyer
324 1.1 bouyer if (err == 0) {
325 1.11 bouyer xlwp->len = 0;
326 1.1 bouyer }
327 1.11 bouyer end:
328 1.11 bouyer mutex_exit(&xlwp->mtx);
329 1.1 bouyer return err;
330 1.1 bouyer }
331 1.1 bouyer
332 1.2 bouyer static int
333 1.2 bouyer xenbus_dev_open(void *v)
334 1.1 bouyer {
335 1.2 bouyer struct vop_open_args /* {
336 1.2 bouyer struct vnode *a_vp;
337 1.2 bouyer int a_mode;
338 1.2 bouyer struct ucred *a_cred;
339 1.2 bouyer } */ *ap = v;
340 1.10 msaitoh struct kernfs_node *kfs = VTOKERN(ap->a_vp);
341 1.1 bouyer struct xenbus_dev_data *u;
342 1.11 bouyer struct xenbus_dev_lwp *xlwp;
343 1.1 bouyer
344 1.2 bouyer if (xen_start_info.store_evtchn == 0)
345 1.2 bouyer return ENOENT;
346 1.1 bouyer
347 1.11 bouyer mutex_enter(&xenbus_dev_open_mtx);
348 1.11 bouyer u = kfs->kfs_v;
349 1.11 bouyer if (u == NULL) {
350 1.16 jdolecek mutex_exit(&xenbus_dev_open_mtx);
351 1.16 jdolecek
352 1.16 jdolecek u = kmem_zalloc(sizeof(*u), KM_SLEEP);
353 1.11 bouyer SLIST_INIT(&u->lwps);
354 1.11 bouyer mutex_init(&u->mtx, MUTEX_DEFAULT, IPL_NONE);
355 1.16 jdolecek
356 1.16 jdolecek mutex_enter(&xenbus_dev_open_mtx);
357 1.16 jdolecek /*
358 1.16 jdolecek * Must re-check if filled while waiting in alloc
359 1.16 jdolecek * by some other lwp.
360 1.16 jdolecek */
361 1.16 jdolecek if (kfs->kfs_v) {
362 1.16 jdolecek kmem_free(u, sizeof(*u));
363 1.16 jdolecek u = kfs->kfs_v;
364 1.16 jdolecek } else {
365 1.16 jdolecek kfs->kfs_v = u;
366 1.16 jdolecek }
367 1.11 bouyer };
368 1.16 jdolecek mutex_exit(&xenbus_dev_open_mtx);
369 1.16 jdolecek
370 1.11 bouyer mutex_enter(&u->mtx);
371 1.11 bouyer SLIST_FOREACH(xlwp, &u->lwps, lwp_next) {
372 1.11 bouyer if (xlwp->lwp == curlwp) {
373 1.11 bouyer break;
374 1.11 bouyer }
375 1.11 bouyer }
376 1.11 bouyer if (xlwp == NULL) {
377 1.16 jdolecek mutex_exit(&u->mtx);
378 1.16 jdolecek
379 1.16 jdolecek xlwp = kmem_zalloc(sizeof(*xlwp), KM_SLEEP);
380 1.11 bouyer xlwp->lwp = curlwp;
381 1.11 bouyer SLIST_INIT(&xlwp->transactions);
382 1.13 bouyer mutex_init(&xlwp->mtx, MUTEX_DEFAULT, IPL_NONE);
383 1.16 jdolecek
384 1.16 jdolecek mutex_enter(&u->mtx);
385 1.16 jdolecek /*
386 1.16 jdolecek * While alloc can block, this can't be re-entered with
387 1.16 jdolecek * curlwp, so no need to re-check. Also the node can't
388 1.16 jdolecek * be closed while we are blocked here.
389 1.16 jdolecek */
390 1.16 jdolecek SLIST_INSERT_HEAD(&u->lwps, xlwp, lwp_next);
391 1.11 bouyer }
392 1.11 bouyer mutex_exit(&u->mtx);
393 1.16 jdolecek
394 1.1 bouyer return 0;
395 1.1 bouyer }
396 1.1 bouyer
397 1.2 bouyer static int
398 1.2 bouyer xenbus_dev_close(void *v)
399 1.1 bouyer {
400 1.2 bouyer struct vop_close_args /* {
401 1.2 bouyer struct vnode *a_vp;
402 1.2 bouyer int a_fflag;
403 1.2 bouyer struct ucred *a_cred;
404 1.2 bouyer } */ *ap = v;
405 1.10 msaitoh struct kernfs_node *kfs = VTOKERN(ap->a_vp);
406 1.1 bouyer
407 1.14 bouyer struct xenbus_dev_data *u;
408 1.11 bouyer struct xenbus_dev_lwp *xlwp;
409 1.2 bouyer struct xenbus_dev_transaction *trans;
410 1.2 bouyer
411 1.11 bouyer mutex_enter(&xenbus_dev_open_mtx);
412 1.11 bouyer u = kfs->kfs_v;
413 1.11 bouyer KASSERT(u != NULL);
414 1.11 bouyer mutex_enter(&u->mtx);
415 1.11 bouyer SLIST_FOREACH(xlwp, &u->lwps, lwp_next) {
416 1.11 bouyer if (xlwp->lwp == curlwp) {
417 1.11 bouyer break;
418 1.11 bouyer }
419 1.11 bouyer }
420 1.11 bouyer if (xlwp == NULL) {
421 1.11 bouyer mutex_exit(&u->mtx);
422 1.11 bouyer mutex_exit(&xenbus_dev_open_mtx);
423 1.11 bouyer return EBADF;
424 1.11 bouyer }
425 1.11 bouyer mutex_enter(&xlwp->mtx);
426 1.11 bouyer while (!SLIST_EMPTY(&xlwp->transactions)) {
427 1.11 bouyer trans = SLIST_FIRST(&xlwp->transactions);
428 1.1 bouyer xenbus_transaction_end(trans->handle, 1);
429 1.11 bouyer SLIST_REMOVE_HEAD(&xlwp->transactions, trans_next);
430 1.16 jdolecek kmem_free(trans, sizeof(*trans));
431 1.1 bouyer }
432 1.11 bouyer mutex_exit(&xlwp->mtx);
433 1.11 bouyer SLIST_REMOVE(&u->lwps, xlwp, xenbus_dev_lwp, lwp_next);
434 1.11 bouyer mutex_destroy(&xlwp->mtx);
435 1.11 bouyer
436 1.11 bouyer if (!SLIST_EMPTY(&u->lwps)) {
437 1.11 bouyer mutex_exit(&u->mtx);
438 1.11 bouyer mutex_exit(&xenbus_dev_open_mtx);
439 1.11 bouyer return 0;
440 1.11 bouyer }
441 1.11 bouyer mutex_exit(&u->mtx);
442 1.11 bouyer mutex_destroy(&u->mtx);
443 1.11 bouyer kfs->kfs_v = NULL;
444 1.11 bouyer mutex_exit(&xenbus_dev_open_mtx);
445 1.16 jdolecek kmem_free(xlwp, sizeof(*xlwp));
446 1.16 jdolecek kmem_free(u, sizeof(*u));
447 1.1 bouyer return 0;
448 1.1 bouyer }
449 1.1 bouyer
450 1.3 bouyer #define LD_STRLEN 21 /* a 64bit integer needs 20 digits in base10 */
451 1.3 bouyer
452 1.3 bouyer static int
453 1.3 bouyer xsd_port_read(void *v)
454 1.3 bouyer {
455 1.3 bouyer struct vop_read_args /* {
456 1.3 bouyer struct vnode *a_vp;
457 1.3 bouyer struct uio *a_uio;
458 1.3 bouyer int a_ioflag;
459 1.3 bouyer struct ucred *a_cred;
460 1.3 bouyer } */ *ap = v;
461 1.3 bouyer struct uio *uio = ap->a_uio;
462 1.3 bouyer int off, error;
463 1.10 msaitoh size_t len;
464 1.3 bouyer char strbuf[LD_STRLEN], *bf;
465 1.3 bouyer
466 1.3 bouyer off = (int)uio->uio_offset;
467 1.3 bouyer if (off < 0)
468 1.3 bouyer return EINVAL;
469 1.3 bouyer
470 1.3 bouyer len = snprintf(strbuf, sizeof(strbuf), "%ld\n",
471 1.3 bouyer (long)xen_start_info.store_evtchn);
472 1.3 bouyer if (off >= len) {
473 1.3 bouyer bf = strbuf;
474 1.3 bouyer len = 0;
475 1.3 bouyer } else {
476 1.3 bouyer bf = &strbuf[off];
477 1.3 bouyer len -= off;
478 1.3 bouyer }
479 1.3 bouyer error = uiomove(bf, len, uio);
480 1.3 bouyer return error;
481 1.3 bouyer }
482 1.3 bouyer
483 1.1 bouyer /*
484 1.1 bouyer * Local variables:
485 1.1 bouyer * c-file-style: "linux"
486 1.1 bouyer * indent-tabs-mode: t
487 1.1 bouyer * c-indent-level: 8
488 1.1 bouyer * c-basic-offset: 8
489 1.1 bouyer * tab-width: 8
490 1.1 bouyer * End:
491 1.1 bouyer */
492