xenbus_dev.c revision 1.15 1 1.15 jdolecek /* $NetBSD: xenbus_dev.c,v 1.15 2020/04/07 08:14:43 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.15 jdolecek __KERNEL_RCSID(0, "$NetBSD: xenbus_dev.c,v 1.15 2020/04/07 08:14:43 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/malloc.h>
42 1.2 bouyer #include <sys/param.h>
43 1.2 bouyer #include <sys/proc.h>
44 1.2 bouyer #include <sys/systm.h>
45 1.2 bouyer #include <sys/dirent.h>
46 1.2 bouyer #include <sys/stat.h>
47 1.2 bouyer #include <sys/tree.h>
48 1.2 bouyer #include <sys/vnode.h>
49 1.2 bouyer #include <miscfs/specfs/specdev.h>
50 1.2 bouyer #include <miscfs/kernfs/kernfs.h>
51 1.2 bouyer
52 1.6 bouyer #include <xen/kernfs_machdep.h>
53 1.6 bouyer
54 1.6 bouyer #include <xen/hypervisor.h>
55 1.6 bouyer #include <xen/xenbus.h>
56 1.1 bouyer #include "xenbus_comms.h"
57 1.1 bouyer
58 1.2 bouyer static int xenbus_dev_read(void *);
59 1.2 bouyer static int xenbus_dev_write(void *);
60 1.2 bouyer static int xenbus_dev_open(void *);
61 1.2 bouyer static int xenbus_dev_close(void *);
62 1.3 bouyer static int xsd_port_read(void *);
63 1.1 bouyer
64 1.2 bouyer #define DIR_MODE (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
65 1.2 bouyer #define PRIVCMD_MODE (S_IRUSR | S_IWUSR)
66 1.2 bouyer static const struct kernfs_fileop xenbus_fileops[] = {
67 1.2 bouyer { .kf_fileop = KERNFS_FILEOP_OPEN, .kf_vop = xenbus_dev_open },
68 1.2 bouyer { .kf_fileop = KERNFS_FILEOP_CLOSE, .kf_vop = xenbus_dev_close },
69 1.2 bouyer { .kf_fileop = KERNFS_FILEOP_READ, .kf_vop = xenbus_dev_read },
70 1.2 bouyer { .kf_fileop = KERNFS_FILEOP_WRITE, .kf_vop = xenbus_dev_write },
71 1.2 bouyer };
72 1.2 bouyer
73 1.3 bouyer #define XSD_MODE (S_IRUSR)
74 1.3 bouyer static const struct kernfs_fileop xsd_port_fileops[] = {
75 1.3 bouyer { .kf_fileop = KERNFS_FILEOP_READ, .kf_vop = xsd_port_read },
76 1.3 bouyer };
77 1.2 bouyer
78 1.11 bouyer static kmutex_t xenbus_dev_open_mtx;
79 1.11 bouyer
80 1.2 bouyer void
81 1.8 cegger xenbus_kernfs_init(void)
82 1.2 bouyer {
83 1.2 bouyer kernfs_entry_t *dkt;
84 1.2 bouyer kfstype kfst;
85 1.2 bouyer
86 1.2 bouyer kfst = KERNFS_ALLOCTYPE(xenbus_fileops);
87 1.15 jdolecek KERNFS_ALLOCENTRY(dkt, KM_SLEEP);
88 1.2 bouyer KERNFS_INITENTRY(dkt, DT_REG, "xenbus", NULL, kfst, VREG,
89 1.2 bouyer PRIVCMD_MODE);
90 1.2 bouyer kernfs_addentry(kernxen_pkt, dkt);
91 1.3 bouyer
92 1.9 jym if (xendomain_is_dom0()) {
93 1.9 jym kfst = KERNFS_ALLOCTYPE(xsd_port_fileops);
94 1.15 jdolecek KERNFS_ALLOCENTRY(dkt, KM_SLEEP);
95 1.9 jym KERNFS_INITENTRY(dkt, DT_REG, "xsd_port", NULL,
96 1.9 jym kfst, VREG, XSD_MODE);
97 1.9 jym kernfs_addentry(kernxen_pkt, dkt);
98 1.9 jym }
99 1.11 bouyer mutex_init(&xenbus_dev_open_mtx, MUTEX_DEFAULT, IPL_NONE);
100 1.2 bouyer }
101 1.2 bouyer
102 1.11 bouyer /*
103 1.11 bouyer * several process may open /kern/xen/xenbus in parallel.
104 1.11 bouyer * In a transaction one or more write is followed by one or more read.
105 1.11 bouyer * Unfortunably we don't get a file descriptor identifier down there,
106 1.11 bouyer * which we could use to link a read() to a transaction started in a write().
107 1.11 bouyer * To work around this we keep a list of lwp that opended the xenbus file.
108 1.11 bouyer * This assumes that a single lwp won't open /kern/xen/xenbus more
109 1.11 bouyer * than once, and that a transaction started by one lwp won't be ended
110 1.11 bouyer * by another.
111 1.11 bouyer * because of this, we also assume that we always got the data before
112 1.11 bouyer * the read() syscall.
113 1.11 bouyer */
114 1.11 bouyer
115 1.11 bouyer struct xenbus_dev_transaction {
116 1.11 bouyer SLIST_ENTRY(xenbus_dev_transaction) trans_next;
117 1.11 bouyer struct xenbus_transaction *handle;
118 1.11 bouyer };
119 1.11 bouyer
120 1.11 bouyer struct xenbus_dev_lwp {
121 1.11 bouyer SLIST_ENTRY(xenbus_dev_lwp) lwp_next;
122 1.11 bouyer SLIST_HEAD(, xenbus_dev_transaction) transactions;
123 1.11 bouyer lwp_t *lwp;
124 1.11 bouyer /* Response queue. */
125 1.2 bouyer #define BUFFER_SIZE (PAGE_SIZE)
126 1.2 bouyer #define MASK_READ_IDX(idx) ((idx)&(BUFFER_SIZE-1))
127 1.11 bouyer char read_buffer[BUFFER_SIZE];
128 1.11 bouyer unsigned int read_cons, read_prod;
129 1.1 bouyer /* Partial request. */
130 1.1 bouyer unsigned int len;
131 1.1 bouyer union {
132 1.1 bouyer struct xsd_sockmsg msg;
133 1.2 bouyer char buffer[BUFFER_SIZE];
134 1.1 bouyer } u;
135 1.11 bouyer kmutex_t mtx;
136 1.11 bouyer };
137 1.1 bouyer
138 1.11 bouyer struct xenbus_dev_data {
139 1.11 bouyer /* lwps which opended this device */
140 1.11 bouyer SLIST_HEAD(, xenbus_dev_lwp) lwps;
141 1.11 bouyer kmutex_t mtx;
142 1.1 bouyer };
143 1.1 bouyer
144 1.11 bouyer
145 1.2 bouyer static int
146 1.2 bouyer xenbus_dev_read(void *v)
147 1.1 bouyer {
148 1.2 bouyer struct vop_read_args /* {
149 1.2 bouyer struct vnode *a_vp;
150 1.2 bouyer struct uio *a_uio;
151 1.2 bouyer int a_ioflag;
152 1.2 bouyer struct ucred *a_cred;
153 1.2 bouyer } */ *ap = v;
154 1.2 bouyer struct kernfs_node *kfs = VTOKERN(ap->a_vp);
155 1.2 bouyer struct uio *uio = ap->a_uio;
156 1.12 bouyer struct xenbus_dev_data *u;
157 1.11 bouyer struct xenbus_dev_lwp *xlwp;
158 1.2 bouyer int err;
159 1.2 bouyer off_t offset;
160 1.2 bouyer
161 1.12 bouyer mutex_enter(&xenbus_dev_open_mtx);
162 1.12 bouyer u = kfs->kfs_v;
163 1.12 bouyer if (u == NULL) {
164 1.12 bouyer mutex_exit(&xenbus_dev_open_mtx);
165 1.12 bouyer return EBADF;
166 1.12 bouyer }
167 1.11 bouyer mutex_enter(&u->mtx);
168 1.12 bouyer mutex_exit(&xenbus_dev_open_mtx);
169 1.11 bouyer SLIST_FOREACH(xlwp, &u->lwps, lwp_next) {
170 1.11 bouyer if (xlwp->lwp == curlwp) {
171 1.11 bouyer break;
172 1.11 bouyer }
173 1.11 bouyer }
174 1.11 bouyer if (xlwp == NULL) {
175 1.11 bouyer mutex_exit(&u->mtx);
176 1.11 bouyer return EBADF;
177 1.11 bouyer }
178 1.11 bouyer mutex_enter(&xlwp->mtx);
179 1.11 bouyer mutex_exit(&u->mtx);
180 1.11 bouyer
181 1.11 bouyer if (xlwp->read_prod == xlwp->read_cons) {
182 1.11 bouyer err = EWOULDBLOCK;
183 1.11 bouyer goto end;
184 1.2 bouyer }
185 1.11 bouyer
186 1.5 bouyer offset = uio->uio_offset;
187 1.11 bouyer if (xlwp->read_cons > xlwp->read_prod) {
188 1.11 bouyer err = uiomove(
189 1.11 bouyer &xlwp->read_buffer[MASK_READ_IDX(xlwp->read_cons)],
190 1.11 bouyer 0U - xlwp->read_cons, uio);
191 1.2 bouyer if (err)
192 1.2 bouyer goto end;
193 1.11 bouyer xlwp->read_cons += (uio->uio_offset - offset);
194 1.2 bouyer offset = uio->uio_offset;
195 1.1 bouyer }
196 1.11 bouyer err = uiomove(&xlwp->read_buffer[MASK_READ_IDX(xlwp->read_cons)],
197 1.11 bouyer xlwp->read_prod - xlwp->read_cons, uio);
198 1.2 bouyer if (err == 0)
199 1.11 bouyer xlwp->read_cons += (uio->uio_offset - offset);
200 1.1 bouyer
201 1.2 bouyer end:
202 1.11 bouyer mutex_exit(&xlwp->mtx);
203 1.2 bouyer return err;
204 1.1 bouyer }
205 1.1 bouyer
206 1.2 bouyer static void
207 1.11 bouyer queue_reply(struct xenbus_dev_lwp *xlwp,
208 1.1 bouyer char *data, unsigned int len)
209 1.1 bouyer {
210 1.1 bouyer int i;
211 1.11 bouyer KASSERT(mutex_owned(&xlwp->mtx));
212 1.11 bouyer for (i = 0; i < len; i++, xlwp->read_prod++)
213 1.11 bouyer xlwp->read_buffer[MASK_READ_IDX(xlwp->read_prod)] = data[i];
214 1.1 bouyer
215 1.11 bouyer KASSERT((xlwp->read_prod - xlwp->read_cons) <= sizeof(xlwp->read_buffer));
216 1.1 bouyer }
217 1.1 bouyer
218 1.2 bouyer static int
219 1.2 bouyer xenbus_dev_write(void *v)
220 1.1 bouyer {
221 1.2 bouyer struct vop_write_args /* {
222 1.2 bouyer struct vnode *a_vp;
223 1.2 bouyer struct uio *a_uio;
224 1.2 bouyer int a_ioflag;
225 1.2 bouyer struct ucred *a_cred;
226 1.2 bouyer } */ *ap = v;
227 1.2 bouyer struct kernfs_node *kfs = VTOKERN(ap->a_vp);
228 1.2 bouyer struct uio *uio = ap->a_uio;
229 1.2 bouyer
230 1.12 bouyer struct xenbus_dev_data *u;
231 1.11 bouyer struct xenbus_dev_lwp *xlwp;
232 1.1 bouyer struct xenbus_dev_transaction *trans;
233 1.1 bouyer void *reply;
234 1.2 bouyer int err;
235 1.2 bouyer size_t size;
236 1.2 bouyer
237 1.12 bouyer mutex_enter(&xenbus_dev_open_mtx);
238 1.12 bouyer u = kfs->kfs_v;
239 1.12 bouyer if (u == NULL) {
240 1.12 bouyer mutex_exit(&xenbus_dev_open_mtx);
241 1.12 bouyer return EBADF;
242 1.12 bouyer }
243 1.11 bouyer mutex_enter(&u->mtx);
244 1.12 bouyer mutex_exit(&xenbus_dev_open_mtx);
245 1.11 bouyer SLIST_FOREACH(xlwp, &u->lwps, lwp_next) {
246 1.11 bouyer if (xlwp->lwp == curlwp) {
247 1.11 bouyer break;
248 1.11 bouyer }
249 1.11 bouyer }
250 1.11 bouyer if (xlwp == NULL) {
251 1.11 bouyer mutex_exit(&u->mtx);
252 1.11 bouyer return EBADF;
253 1.11 bouyer }
254 1.11 bouyer mutex_enter(&xlwp->mtx);
255 1.11 bouyer mutex_exit(&u->mtx);
256 1.11 bouyer
257 1.11 bouyer if (uio->uio_offset < 0) {
258 1.11 bouyer err = EINVAL;
259 1.11 bouyer goto end;
260 1.11 bouyer }
261 1.2 bouyer size = uio->uio_resid;
262 1.1 bouyer
263 1.11 bouyer if ((size + xlwp->len) > sizeof(xlwp->u.buffer)) {
264 1.11 bouyer err = EINVAL;
265 1.11 bouyer goto end;
266 1.11 bouyer }
267 1.1 bouyer
268 1.11 bouyer err = uiomove(xlwp->u.buffer + xlwp->len,
269 1.11 bouyer sizeof(xlwp->u.buffer) - xlwp->len, uio);
270 1.11 bouyer if (err)
271 1.11 bouyer goto end;
272 1.11 bouyer
273 1.11 bouyer xlwp->len += size;
274 1.11 bouyer if (xlwp->len < (sizeof(xlwp->u.msg) + xlwp->u.msg.len))
275 1.11 bouyer goto end;
276 1.1 bouyer
277 1.11 bouyer switch (xlwp->u.msg.type) {
278 1.1 bouyer case XS_TRANSACTION_START:
279 1.1 bouyer case XS_TRANSACTION_END:
280 1.1 bouyer case XS_DIRECTORY:
281 1.1 bouyer case XS_READ:
282 1.1 bouyer case XS_GET_PERMS:
283 1.1 bouyer case XS_RELEASE:
284 1.1 bouyer case XS_GET_DOMAIN_PATH:
285 1.1 bouyer case XS_WRITE:
286 1.1 bouyer case XS_MKDIR:
287 1.1 bouyer case XS_RM:
288 1.1 bouyer case XS_SET_PERMS:
289 1.11 bouyer err = xenbus_dev_request_and_reply(&xlwp->u.msg, &reply);
290 1.2 bouyer if (err == 0) {
291 1.11 bouyer if (xlwp->u.msg.type == XS_TRANSACTION_START) {
292 1.2 bouyer trans = malloc(sizeof(*trans), M_DEVBUF,
293 1.2 bouyer M_WAITOK);
294 1.1 bouyer trans->handle = (struct xenbus_transaction *)
295 1.2 bouyer strtoul(reply, NULL, 0);
296 1.11 bouyer SLIST_INSERT_HEAD(&xlwp->transactions,
297 1.2 bouyer trans, trans_next);
298 1.11 bouyer } else if (xlwp->u.msg.type == XS_TRANSACTION_END) {
299 1.11 bouyer SLIST_FOREACH(trans, &xlwp->transactions,
300 1.2 bouyer trans_next) {
301 1.1 bouyer if ((unsigned long)trans->handle ==
302 1.11 bouyer (unsigned long)xlwp->u.msg.tx_id)
303 1.1 bouyer break;
304 1.2 bouyer }
305 1.11 bouyer if (trans == NULL) {
306 1.11 bouyer err = EINVAL;
307 1.11 bouyer goto end;
308 1.11 bouyer }
309 1.11 bouyer SLIST_REMOVE(&xlwp->transactions, trans,
310 1.2 bouyer xenbus_dev_transaction, trans_next);
311 1.2 bouyer free(trans, M_DEVBUF);
312 1.1 bouyer }
313 1.11 bouyer queue_reply(xlwp, (char *)&xlwp->u.msg,
314 1.11 bouyer sizeof(xlwp->u.msg));
315 1.11 bouyer queue_reply(xlwp, (char *)reply, xlwp->u.msg.len);
316 1.2 bouyer free(reply, M_DEVBUF);
317 1.1 bouyer }
318 1.1 bouyer break;
319 1.1 bouyer
320 1.1 bouyer default:
321 1.2 bouyer err = EINVAL;
322 1.1 bouyer break;
323 1.1 bouyer }
324 1.1 bouyer
325 1.1 bouyer if (err == 0) {
326 1.11 bouyer xlwp->len = 0;
327 1.1 bouyer }
328 1.11 bouyer end:
329 1.11 bouyer mutex_exit(&xlwp->mtx);
330 1.1 bouyer return err;
331 1.1 bouyer }
332 1.1 bouyer
333 1.2 bouyer static int
334 1.2 bouyer xenbus_dev_open(void *v)
335 1.1 bouyer {
336 1.2 bouyer struct vop_open_args /* {
337 1.2 bouyer struct vnode *a_vp;
338 1.2 bouyer int a_mode;
339 1.2 bouyer struct ucred *a_cred;
340 1.2 bouyer } */ *ap = v;
341 1.10 msaitoh struct kernfs_node *kfs = VTOKERN(ap->a_vp);
342 1.1 bouyer struct xenbus_dev_data *u;
343 1.11 bouyer struct xenbus_dev_lwp *xlwp;
344 1.1 bouyer
345 1.2 bouyer if (xen_start_info.store_evtchn == 0)
346 1.2 bouyer return ENOENT;
347 1.1 bouyer
348 1.11 bouyer mutex_enter(&xenbus_dev_open_mtx);
349 1.11 bouyer u = kfs->kfs_v;
350 1.11 bouyer if (u == NULL) {
351 1.11 bouyer u = malloc(sizeof(*u), M_DEVBUF, M_WAITOK);
352 1.11 bouyer if (u == NULL) {
353 1.11 bouyer mutex_exit(&xenbus_dev_open_mtx);
354 1.11 bouyer return ENOMEM;
355 1.11 bouyer }
356 1.11 bouyer memset(u, 0, sizeof(*u));
357 1.11 bouyer SLIST_INIT(&u->lwps);
358 1.11 bouyer mutex_init(&u->mtx, MUTEX_DEFAULT, IPL_NONE);
359 1.11 bouyer kfs->kfs_v = u;
360 1.11 bouyer };
361 1.11 bouyer mutex_enter(&u->mtx);
362 1.11 bouyer mutex_exit(&xenbus_dev_open_mtx);
363 1.11 bouyer SLIST_FOREACH(xlwp, &u->lwps, lwp_next) {
364 1.11 bouyer if (xlwp->lwp == curlwp) {
365 1.11 bouyer break;
366 1.11 bouyer }
367 1.11 bouyer }
368 1.11 bouyer if (xlwp == NULL) {
369 1.11 bouyer xlwp = malloc(sizeof(*xlwp ), M_DEVBUF, M_WAITOK);
370 1.11 bouyer if (xlwp == NULL) {
371 1.11 bouyer mutex_exit(&u->mtx);
372 1.11 bouyer return ENOMEM;
373 1.11 bouyer }
374 1.11 bouyer memset(xlwp, 0, sizeof(*xlwp));
375 1.11 bouyer xlwp->lwp = curlwp;
376 1.11 bouyer SLIST_INIT(&xlwp->transactions);
377 1.13 bouyer mutex_init(&xlwp->mtx, MUTEX_DEFAULT, IPL_NONE);
378 1.11 bouyer SLIST_INSERT_HEAD(&u->lwps,
379 1.11 bouyer xlwp, lwp_next);
380 1.11 bouyer }
381 1.11 bouyer mutex_exit(&u->mtx);
382 1.1 bouyer return 0;
383 1.1 bouyer }
384 1.1 bouyer
385 1.2 bouyer static int
386 1.2 bouyer xenbus_dev_close(void *v)
387 1.1 bouyer {
388 1.2 bouyer struct vop_close_args /* {
389 1.2 bouyer struct vnode *a_vp;
390 1.2 bouyer int a_fflag;
391 1.2 bouyer struct ucred *a_cred;
392 1.2 bouyer } */ *ap = v;
393 1.10 msaitoh struct kernfs_node *kfs = VTOKERN(ap->a_vp);
394 1.1 bouyer
395 1.14 bouyer struct xenbus_dev_data *u;
396 1.11 bouyer struct xenbus_dev_lwp *xlwp;
397 1.2 bouyer struct xenbus_dev_transaction *trans;
398 1.2 bouyer
399 1.11 bouyer mutex_enter(&xenbus_dev_open_mtx);
400 1.11 bouyer u = kfs->kfs_v;
401 1.11 bouyer KASSERT(u != NULL);
402 1.11 bouyer mutex_enter(&u->mtx);
403 1.11 bouyer SLIST_FOREACH(xlwp, &u->lwps, lwp_next) {
404 1.11 bouyer if (xlwp->lwp == curlwp) {
405 1.11 bouyer break;
406 1.11 bouyer }
407 1.11 bouyer }
408 1.11 bouyer if (xlwp == NULL) {
409 1.11 bouyer mutex_exit(&u->mtx);
410 1.11 bouyer mutex_exit(&xenbus_dev_open_mtx);
411 1.11 bouyer return EBADF;
412 1.11 bouyer }
413 1.11 bouyer mutex_enter(&xlwp->mtx);
414 1.11 bouyer while (!SLIST_EMPTY(&xlwp->transactions)) {
415 1.11 bouyer trans = SLIST_FIRST(&xlwp->transactions);
416 1.1 bouyer xenbus_transaction_end(trans->handle, 1);
417 1.11 bouyer SLIST_REMOVE_HEAD(&xlwp->transactions, trans_next);
418 1.2 bouyer free(trans, M_DEVBUF);
419 1.1 bouyer }
420 1.11 bouyer mutex_exit(&xlwp->mtx);
421 1.11 bouyer SLIST_REMOVE(&u->lwps, xlwp, xenbus_dev_lwp, lwp_next);
422 1.11 bouyer mutex_destroy(&xlwp->mtx);
423 1.11 bouyer
424 1.11 bouyer if (!SLIST_EMPTY(&u->lwps)) {
425 1.11 bouyer mutex_exit(&u->mtx);
426 1.11 bouyer mutex_exit(&xenbus_dev_open_mtx);
427 1.11 bouyer return 0;
428 1.11 bouyer }
429 1.11 bouyer mutex_exit(&u->mtx);
430 1.11 bouyer mutex_destroy(&u->mtx);
431 1.11 bouyer kfs->kfs_v = NULL;
432 1.11 bouyer mutex_exit(&xenbus_dev_open_mtx);
433 1.11 bouyer free(xlwp, M_DEVBUF);
434 1.2 bouyer free(u, M_DEVBUF);
435 1.1 bouyer return 0;
436 1.1 bouyer }
437 1.1 bouyer
438 1.3 bouyer #define LD_STRLEN 21 /* a 64bit integer needs 20 digits in base10 */
439 1.3 bouyer
440 1.3 bouyer static int
441 1.3 bouyer xsd_port_read(void *v)
442 1.3 bouyer {
443 1.3 bouyer struct vop_read_args /* {
444 1.3 bouyer struct vnode *a_vp;
445 1.3 bouyer struct uio *a_uio;
446 1.3 bouyer int a_ioflag;
447 1.3 bouyer struct ucred *a_cred;
448 1.3 bouyer } */ *ap = v;
449 1.3 bouyer struct uio *uio = ap->a_uio;
450 1.3 bouyer int off, error;
451 1.10 msaitoh size_t len;
452 1.3 bouyer char strbuf[LD_STRLEN], *bf;
453 1.3 bouyer
454 1.3 bouyer off = (int)uio->uio_offset;
455 1.3 bouyer if (off < 0)
456 1.3 bouyer return EINVAL;
457 1.3 bouyer
458 1.3 bouyer len = snprintf(strbuf, sizeof(strbuf), "%ld\n",
459 1.3 bouyer (long)xen_start_info.store_evtchn);
460 1.3 bouyer if (off >= len) {
461 1.3 bouyer bf = strbuf;
462 1.3 bouyer len = 0;
463 1.3 bouyer } else {
464 1.3 bouyer bf = &strbuf[off];
465 1.3 bouyer len -= off;
466 1.3 bouyer }
467 1.3 bouyer error = uiomove(bf, len, uio);
468 1.3 bouyer return error;
469 1.3 bouyer }
470 1.3 bouyer
471 1.1 bouyer /*
472 1.1 bouyer * Local variables:
473 1.1 bouyer * c-file-style: "linux"
474 1.1 bouyer * indent-tabs-mode: t
475 1.1 bouyer * c-indent-level: 8
476 1.1 bouyer * c-basic-offset: 8
477 1.1 bouyer * tab-width: 8
478 1.1 bouyer * End:
479 1.1 bouyer */
480