1*100a3398Sandvar /* $NetBSD: xenbus_dev.c,v 1.19 2024/02/09 22:08:34 andvar Exp $ */
2ed3fe49dSbouyer /*
3ed3fe49dSbouyer * xenbus_dev.c
4ed3fe49dSbouyer *
5ed3fe49dSbouyer * Driver giving user-space access to the kernel's xenbus connection
6ed3fe49dSbouyer * to xenstore.
7ed3fe49dSbouyer *
8ed3fe49dSbouyer * Copyright (c) 2005, Christian Limpach
9ed3fe49dSbouyer * Copyright (c) 2005, Rusty Russell, IBM Corporation
10ed3fe49dSbouyer *
11ed3fe49dSbouyer * This file may be distributed separately from the Linux kernel, or
12ed3fe49dSbouyer * incorporated into other software packages, subject to the following license:
13ed3fe49dSbouyer *
14ed3fe49dSbouyer * Permission is hereby granted, free of charge, to any person obtaining a copy
15ed3fe49dSbouyer * of this source file (the "Software"), to deal in the Software without
16ed3fe49dSbouyer * restriction, including without limitation the rights to use, copy, modify,
17ed3fe49dSbouyer * merge, publish, distribute, sublicense, and/or sell copies of the Software,
18ed3fe49dSbouyer * and to permit persons to whom the Software is furnished to do so, subject to
19ed3fe49dSbouyer * the following conditions:
20ed3fe49dSbouyer *
21ed3fe49dSbouyer * The above copyright notice and this permission notice shall be included in
22ed3fe49dSbouyer * all copies or substantial portions of the Software.
23ed3fe49dSbouyer *
24ed3fe49dSbouyer * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25ed3fe49dSbouyer * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26ed3fe49dSbouyer * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27ed3fe49dSbouyer * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28ed3fe49dSbouyer * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29ed3fe49dSbouyer * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30ed3fe49dSbouyer * IN THE SOFTWARE.
31ed3fe49dSbouyer */
32ed3fe49dSbouyer
3316046408Sbouyer #include <sys/cdefs.h>
34*100a3398Sandvar __KERNEL_RCSID(0, "$NetBSD: xenbus_dev.c,v 1.19 2024/02/09 22:08:34 andvar Exp $");
35ed3fe49dSbouyer
3616046408Sbouyer #include "opt_xen.h"
3716046408Sbouyer
3816046408Sbouyer #include <sys/types.h>
3916046408Sbouyer #include <sys/null.h>
4016046408Sbouyer #include <sys/errno.h>
4116046408Sbouyer #include <sys/param.h>
4216046408Sbouyer #include <sys/proc.h>
4316046408Sbouyer #include <sys/systm.h>
4416046408Sbouyer #include <sys/dirent.h>
4516046408Sbouyer #include <sys/stat.h>
4616046408Sbouyer #include <sys/tree.h>
4716046408Sbouyer #include <sys/vnode.h>
4816046408Sbouyer #include <miscfs/specfs/specdev.h>
4916046408Sbouyer #include <miscfs/kernfs/kernfs.h>
5016046408Sbouyer
514e541343Sbouyer #include <xen/kernfs_machdep.h>
524e541343Sbouyer
53c24c993fSbouyer #include <xen/intr.h>
544e541343Sbouyer #include <xen/hypervisor.h>
554e541343Sbouyer #include <xen/xenbus.h>
56ed3fe49dSbouyer #include "xenbus_comms.h"
57ed3fe49dSbouyer
5816046408Sbouyer static int xenbus_dev_read(void *);
5916046408Sbouyer static int xenbus_dev_write(void *);
6016046408Sbouyer static int xenbus_dev_open(void *);
6116046408Sbouyer static int xenbus_dev_close(void *);
622ed85162Sbouyer static int xsd_port_read(void *);
63ed3fe49dSbouyer
6416046408Sbouyer #define DIR_MODE (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
6516046408Sbouyer #define PRIVCMD_MODE (S_IRUSR | S_IWUSR)
6616046408Sbouyer static const struct kernfs_fileop xenbus_fileops[] = {
6716046408Sbouyer { .kf_fileop = KERNFS_FILEOP_OPEN, .kf_vop = xenbus_dev_open },
6816046408Sbouyer { .kf_fileop = KERNFS_FILEOP_CLOSE, .kf_vop = xenbus_dev_close },
6916046408Sbouyer { .kf_fileop = KERNFS_FILEOP_READ, .kf_vop = xenbus_dev_read },
7016046408Sbouyer { .kf_fileop = KERNFS_FILEOP_WRITE, .kf_vop = xenbus_dev_write },
7116046408Sbouyer };
7216046408Sbouyer
732ed85162Sbouyer #define XSD_MODE (S_IRUSR)
742ed85162Sbouyer static const struct kernfs_fileop xsd_port_fileops[] = {
752ed85162Sbouyer { .kf_fileop = KERNFS_FILEOP_READ, .kf_vop = xsd_port_read },
762ed85162Sbouyer };
7716046408Sbouyer
78e78e0779Sbouyer static kmutex_t xenbus_dev_open_mtx;
79e78e0779Sbouyer
8016046408Sbouyer void
xenbus_kernfs_init(void)8196276685Scegger xenbus_kernfs_init(void)
8216046408Sbouyer {
8316046408Sbouyer kernfs_entry_t *dkt;
8416046408Sbouyer kfstype kfst;
8516046408Sbouyer
8616046408Sbouyer kfst = KERNFS_ALLOCTYPE(xenbus_fileops);
878a3ee726Sjdolecek KERNFS_ALLOCENTRY(dkt, KM_SLEEP);
8816046408Sbouyer KERNFS_INITENTRY(dkt, DT_REG, "xenbus", NULL, kfst, VREG,
8916046408Sbouyer PRIVCMD_MODE);
9016046408Sbouyer kernfs_addentry(kernxen_pkt, dkt);
912ed85162Sbouyer
92afeabb04Sjym if (xendomain_is_dom0()) {
932ed85162Sbouyer kfst = KERNFS_ALLOCTYPE(xsd_port_fileops);
948a3ee726Sjdolecek KERNFS_ALLOCENTRY(dkt, KM_SLEEP);
95afeabb04Sjym KERNFS_INITENTRY(dkt, DT_REG, "xsd_port", NULL,
96afeabb04Sjym kfst, VREG, XSD_MODE);
972ed85162Sbouyer kernfs_addentry(kernxen_pkt, dkt);
9816046408Sbouyer }
99e78e0779Sbouyer mutex_init(&xenbus_dev_open_mtx, MUTEX_DEFAULT, IPL_NONE);
100afeabb04Sjym }
10116046408Sbouyer
102e78e0779Sbouyer /*
103e78e0779Sbouyer * several process may open /kern/xen/xenbus in parallel.
104e78e0779Sbouyer * In a transaction one or more write is followed by one or more read.
105*100a3398Sandvar * Unfortunately we don't get a file descriptor identifier down there,
106e78e0779Sbouyer * which we could use to link a read() to a transaction started in a write().
107e78e0779Sbouyer * To work around this we keep a list of lwp that opended the xenbus file.
108e78e0779Sbouyer * This assumes that a single lwp won't open /kern/xen/xenbus more
109e78e0779Sbouyer * than once, and that a transaction started by one lwp won't be ended
110e78e0779Sbouyer * by another.
111e78e0779Sbouyer * because of this, we also assume that we always got the data before
112e78e0779Sbouyer * the read() syscall.
113e78e0779Sbouyer */
114e78e0779Sbouyer
115e78e0779Sbouyer struct xenbus_dev_transaction {
116e78e0779Sbouyer SLIST_ENTRY(xenbus_dev_transaction) trans_next;
117e78e0779Sbouyer struct xenbus_transaction *handle;
118e78e0779Sbouyer };
119e78e0779Sbouyer
120e78e0779Sbouyer struct xenbus_dev_lwp {
121e78e0779Sbouyer SLIST_ENTRY(xenbus_dev_lwp) lwp_next;
122e78e0779Sbouyer SLIST_HEAD(, xenbus_dev_transaction) transactions;
123e78e0779Sbouyer lwp_t *lwp;
124e78e0779Sbouyer /* Response queue. */
12516046408Sbouyer #define BUFFER_SIZE (PAGE_SIZE)
12616046408Sbouyer #define MASK_READ_IDX(idx) ((idx)&(BUFFER_SIZE-1))
127e78e0779Sbouyer char read_buffer[BUFFER_SIZE];
128e78e0779Sbouyer unsigned int read_cons, read_prod;
129ed3fe49dSbouyer /* Partial request. */
130ed3fe49dSbouyer unsigned int len;
131ed3fe49dSbouyer union {
132ed3fe49dSbouyer struct xsd_sockmsg msg;
13316046408Sbouyer char buffer[BUFFER_SIZE];
134ed3fe49dSbouyer } u;
135e78e0779Sbouyer kmutex_t mtx;
136ed3fe49dSbouyer };
137ed3fe49dSbouyer
138e78e0779Sbouyer struct xenbus_dev_data {
139e78e0779Sbouyer /* lwps which opended this device */
140e78e0779Sbouyer SLIST_HEAD(, xenbus_dev_lwp) lwps;
141e78e0779Sbouyer kmutex_t mtx;
142e78e0779Sbouyer };
143e78e0779Sbouyer
144e78e0779Sbouyer
14516046408Sbouyer static int
xenbus_dev_read(void * v)14616046408Sbouyer xenbus_dev_read(void *v)
147ed3fe49dSbouyer {
14816046408Sbouyer struct vop_read_args /* {
14916046408Sbouyer struct vnode *a_vp;
15016046408Sbouyer struct uio *a_uio;
15116046408Sbouyer int a_ioflag;
15216046408Sbouyer struct ucred *a_cred;
15316046408Sbouyer } */ *ap = v;
15416046408Sbouyer struct kernfs_node *kfs = VTOKERN(ap->a_vp);
15516046408Sbouyer struct uio *uio = ap->a_uio;
15646a06789Sbouyer struct xenbus_dev_data *u;
157e78e0779Sbouyer struct xenbus_dev_lwp *xlwp;
15816046408Sbouyer int err;
15916046408Sbouyer off_t offset;
160ed3fe49dSbouyer
16146a06789Sbouyer mutex_enter(&xenbus_dev_open_mtx);
16246a06789Sbouyer u = kfs->kfs_v;
16346a06789Sbouyer if (u == NULL) {
16446a06789Sbouyer mutex_exit(&xenbus_dev_open_mtx);
16546a06789Sbouyer return EBADF;
16646a06789Sbouyer }
167e78e0779Sbouyer mutex_enter(&u->mtx);
16846a06789Sbouyer mutex_exit(&xenbus_dev_open_mtx);
169e78e0779Sbouyer SLIST_FOREACH(xlwp, &u->lwps, lwp_next) {
170e78e0779Sbouyer if (xlwp->lwp == curlwp) {
171e78e0779Sbouyer break;
172e78e0779Sbouyer }
173e78e0779Sbouyer }
174e78e0779Sbouyer if (xlwp == NULL) {
175e78e0779Sbouyer mutex_exit(&u->mtx);
176e78e0779Sbouyer return EBADF;
177e78e0779Sbouyer }
178e78e0779Sbouyer mutex_enter(&xlwp->mtx);
179e78e0779Sbouyer mutex_exit(&u->mtx);
180e78e0779Sbouyer
181e78e0779Sbouyer if (xlwp->read_prod == xlwp->read_cons) {
182e78e0779Sbouyer err = EWOULDBLOCK;
18316046408Sbouyer goto end;
18416046408Sbouyer }
185ed3fe49dSbouyer
186e78e0779Sbouyer offset = uio->uio_offset;
187e78e0779Sbouyer if (xlwp->read_cons > xlwp->read_prod) {
188e78e0779Sbouyer err = uiomove(
189e78e0779Sbouyer &xlwp->read_buffer[MASK_READ_IDX(xlwp->read_cons)],
190e78e0779Sbouyer 0U - xlwp->read_cons, uio);
19116046408Sbouyer if (err)
19216046408Sbouyer goto end;
193e78e0779Sbouyer xlwp->read_cons += (uio->uio_offset - offset);
19416046408Sbouyer offset = uio->uio_offset;
19516046408Sbouyer }
196e78e0779Sbouyer err = uiomove(&xlwp->read_buffer[MASK_READ_IDX(xlwp->read_cons)],
197e78e0779Sbouyer xlwp->read_prod - xlwp->read_cons, uio);
19816046408Sbouyer if (err == 0)
199e78e0779Sbouyer xlwp->read_cons += (uio->uio_offset - offset);
20016046408Sbouyer
20116046408Sbouyer end:
202e78e0779Sbouyer mutex_exit(&xlwp->mtx);
20316046408Sbouyer return err;
204ed3fe49dSbouyer }
205ed3fe49dSbouyer
20616046408Sbouyer static void
queue_reply(struct xenbus_dev_lwp * xlwp,char * data,unsigned int len)207e78e0779Sbouyer queue_reply(struct xenbus_dev_lwp *xlwp,
208ed3fe49dSbouyer char *data, unsigned int len)
209ed3fe49dSbouyer {
210ed3fe49dSbouyer int i;
211e78e0779Sbouyer KASSERT(mutex_owned(&xlwp->mtx));
212e78e0779Sbouyer for (i = 0; i < len; i++, xlwp->read_prod++)
213e78e0779Sbouyer xlwp->read_buffer[MASK_READ_IDX(xlwp->read_prod)] = data[i];
214ed3fe49dSbouyer
215e78e0779Sbouyer KASSERT((xlwp->read_prod - xlwp->read_cons) <= sizeof(xlwp->read_buffer));
216ed3fe49dSbouyer }
217ed3fe49dSbouyer
21816046408Sbouyer static int
xenbus_dev_write(void * v)21916046408Sbouyer xenbus_dev_write(void *v)
220ed3fe49dSbouyer {
22116046408Sbouyer struct vop_write_args /* {
22216046408Sbouyer struct vnode *a_vp;
22316046408Sbouyer struct uio *a_uio;
22416046408Sbouyer int a_ioflag;
22516046408Sbouyer struct ucred *a_cred;
22616046408Sbouyer } */ *ap = v;
22716046408Sbouyer struct kernfs_node *kfs = VTOKERN(ap->a_vp);
22816046408Sbouyer struct uio *uio = ap->a_uio;
22916046408Sbouyer
23046a06789Sbouyer struct xenbus_dev_data *u;
231e78e0779Sbouyer struct xenbus_dev_lwp *xlwp;
232ed3fe49dSbouyer struct xenbus_dev_transaction *trans;
233ed3fe49dSbouyer void *reply;
23416046408Sbouyer int err;
23516046408Sbouyer size_t size;
236ed3fe49dSbouyer
23746a06789Sbouyer mutex_enter(&xenbus_dev_open_mtx);
23846a06789Sbouyer u = kfs->kfs_v;
23946a06789Sbouyer if (u == NULL) {
24046a06789Sbouyer mutex_exit(&xenbus_dev_open_mtx);
24146a06789Sbouyer return EBADF;
24246a06789Sbouyer }
243e78e0779Sbouyer mutex_enter(&u->mtx);
24446a06789Sbouyer mutex_exit(&xenbus_dev_open_mtx);
245e78e0779Sbouyer SLIST_FOREACH(xlwp, &u->lwps, lwp_next) {
246e78e0779Sbouyer if (xlwp->lwp == curlwp) {
247e78e0779Sbouyer break;
248e78e0779Sbouyer }
249e78e0779Sbouyer }
250e78e0779Sbouyer if (xlwp == NULL) {
251e78e0779Sbouyer mutex_exit(&u->mtx);
252e78e0779Sbouyer return EBADF;
253e78e0779Sbouyer }
254e78e0779Sbouyer mutex_enter(&xlwp->mtx);
255e78e0779Sbouyer mutex_exit(&u->mtx);
256e78e0779Sbouyer
257e78e0779Sbouyer if (uio->uio_offset < 0) {
258e78e0779Sbouyer err = EINVAL;
259e78e0779Sbouyer goto end;
260e78e0779Sbouyer }
26116046408Sbouyer size = uio->uio_resid;
262ed3fe49dSbouyer
263e78e0779Sbouyer if ((size + xlwp->len) > sizeof(xlwp->u.buffer)) {
264e78e0779Sbouyer err = EINVAL;
265e78e0779Sbouyer goto end;
266e78e0779Sbouyer }
267ed3fe49dSbouyer
268e78e0779Sbouyer err = uiomove(xlwp->u.buffer + xlwp->len,
269e78e0779Sbouyer sizeof(xlwp->u.buffer) - xlwp->len, uio);
27016046408Sbouyer if (err)
271e78e0779Sbouyer goto end;
27216046408Sbouyer
273e78e0779Sbouyer xlwp->len += size;
274e78e0779Sbouyer if (xlwp->len < (sizeof(xlwp->u.msg) + xlwp->u.msg.len))
275e78e0779Sbouyer goto end;
276ed3fe49dSbouyer
277e78e0779Sbouyer switch (xlwp->u.msg.type) {
278ed3fe49dSbouyer case XS_TRANSACTION_START:
279ed3fe49dSbouyer case XS_TRANSACTION_END:
280ed3fe49dSbouyer case XS_DIRECTORY:
281ed3fe49dSbouyer case XS_READ:
282ed3fe49dSbouyer case XS_GET_PERMS:
283ed3fe49dSbouyer case XS_RELEASE:
284ed3fe49dSbouyer case XS_GET_DOMAIN_PATH:
285ed3fe49dSbouyer case XS_WRITE:
286ed3fe49dSbouyer case XS_MKDIR:
287ed3fe49dSbouyer case XS_RM:
288ed3fe49dSbouyer case XS_SET_PERMS:
289e78e0779Sbouyer err = xenbus_dev_request_and_reply(&xlwp->u.msg, &reply);
29016046408Sbouyer if (err == 0) {
291e78e0779Sbouyer if (xlwp->u.msg.type == XS_TRANSACTION_START) {
2921c0b49f5Sjdolecek trans = kmem_alloc(sizeof(*trans), KM_SLEEP);
293ed3fe49dSbouyer trans->handle = (struct xenbus_transaction *)
29416046408Sbouyer strtoul(reply, NULL, 0);
295e78e0779Sbouyer SLIST_INSERT_HEAD(&xlwp->transactions,
29616046408Sbouyer trans, trans_next);
297e78e0779Sbouyer } else if (xlwp->u.msg.type == XS_TRANSACTION_END) {
298e78e0779Sbouyer SLIST_FOREACH(trans, &xlwp->transactions,
29916046408Sbouyer trans_next) {
300ed3fe49dSbouyer if ((unsigned long)trans->handle ==
301e78e0779Sbouyer (unsigned long)xlwp->u.msg.tx_id)
302ed3fe49dSbouyer break;
30316046408Sbouyer }
304e78e0779Sbouyer if (trans == NULL) {
305e78e0779Sbouyer err = EINVAL;
306e78e0779Sbouyer goto end;
307e78e0779Sbouyer }
308e78e0779Sbouyer SLIST_REMOVE(&xlwp->transactions, trans,
30916046408Sbouyer xenbus_dev_transaction, trans_next);
3101c0b49f5Sjdolecek kmem_free(trans, sizeof(*trans));
311ed3fe49dSbouyer }
312e78e0779Sbouyer queue_reply(xlwp, (char *)&xlwp->u.msg,
313e78e0779Sbouyer sizeof(xlwp->u.msg));
314e78e0779Sbouyer queue_reply(xlwp, (char *)reply, xlwp->u.msg.len);
31579743bc4Sjdolecek
31679743bc4Sjdolecek xenbus_dev_reply_free(&xlwp->u.msg, reply);
317ed3fe49dSbouyer }
318ed3fe49dSbouyer break;
319ed3fe49dSbouyer
320ed3fe49dSbouyer default:
32116046408Sbouyer err = EINVAL;
322ed3fe49dSbouyer break;
323ed3fe49dSbouyer }
324ed3fe49dSbouyer
325ed3fe49dSbouyer if (err == 0) {
326e78e0779Sbouyer xlwp->len = 0;
327ed3fe49dSbouyer }
328e78e0779Sbouyer end:
329e78e0779Sbouyer mutex_exit(&xlwp->mtx);
330ed3fe49dSbouyer return err;
331ed3fe49dSbouyer }
332ed3fe49dSbouyer
33316046408Sbouyer static int
xenbus_dev_open(void * v)33416046408Sbouyer xenbus_dev_open(void *v)
335ed3fe49dSbouyer {
33616046408Sbouyer struct vop_open_args /* {
33716046408Sbouyer struct vnode *a_vp;
33816046408Sbouyer int a_mode;
33916046408Sbouyer struct ucred *a_cred;
34016046408Sbouyer } */ *ap = v;
34116046408Sbouyer struct kernfs_node *kfs = VTOKERN(ap->a_vp);
342ed3fe49dSbouyer struct xenbus_dev_data *u;
343e78e0779Sbouyer struct xenbus_dev_lwp *xlwp;
344ed3fe49dSbouyer
34516046408Sbouyer if (xen_start_info.store_evtchn == 0)
34616046408Sbouyer return ENOENT;
347ed3fe49dSbouyer
348e78e0779Sbouyer mutex_enter(&xenbus_dev_open_mtx);
349e78e0779Sbouyer u = kfs->kfs_v;
350e78e0779Sbouyer if (u == NULL) {
351e78e0779Sbouyer mutex_exit(&xenbus_dev_open_mtx);
3521c0b49f5Sjdolecek
3531c0b49f5Sjdolecek u = kmem_zalloc(sizeof(*u), KM_SLEEP);
354e78e0779Sbouyer SLIST_INIT(&u->lwps);
355e78e0779Sbouyer mutex_init(&u->mtx, MUTEX_DEFAULT, IPL_NONE);
3561c0b49f5Sjdolecek
3571c0b49f5Sjdolecek mutex_enter(&xenbus_dev_open_mtx);
3581c0b49f5Sjdolecek /*
3591c0b49f5Sjdolecek * Must re-check if filled while waiting in alloc
3601c0b49f5Sjdolecek * by some other lwp.
3611c0b49f5Sjdolecek */
3621c0b49f5Sjdolecek if (kfs->kfs_v) {
3631c0b49f5Sjdolecek kmem_free(u, sizeof(*u));
3641c0b49f5Sjdolecek u = kfs->kfs_v;
3651c0b49f5Sjdolecek } else {
36616046408Sbouyer kfs->kfs_v = u;
3671c0b49f5Sjdolecek }
368e78e0779Sbouyer };
369e78e0779Sbouyer mutex_exit(&xenbus_dev_open_mtx);
3701c0b49f5Sjdolecek
3711c0b49f5Sjdolecek mutex_enter(&u->mtx);
372e78e0779Sbouyer SLIST_FOREACH(xlwp, &u->lwps, lwp_next) {
373e78e0779Sbouyer if (xlwp->lwp == curlwp) {
374e78e0779Sbouyer break;
375e78e0779Sbouyer }
376e78e0779Sbouyer }
377e78e0779Sbouyer if (xlwp == NULL) {
378e78e0779Sbouyer mutex_exit(&u->mtx);
3791c0b49f5Sjdolecek
3801c0b49f5Sjdolecek xlwp = kmem_zalloc(sizeof(*xlwp), KM_SLEEP);
381e78e0779Sbouyer xlwp->lwp = curlwp;
382e78e0779Sbouyer SLIST_INIT(&xlwp->transactions);
38372413a9eSbouyer mutex_init(&xlwp->mtx, MUTEX_DEFAULT, IPL_NONE);
3841c0b49f5Sjdolecek
3851c0b49f5Sjdolecek mutex_enter(&u->mtx);
3861c0b49f5Sjdolecek /*
3871c0b49f5Sjdolecek * While alloc can block, this can't be re-entered with
3881c0b49f5Sjdolecek * curlwp, so no need to re-check. Also the node can't
3891c0b49f5Sjdolecek * be closed while we are blocked here.
3901c0b49f5Sjdolecek */
3911c0b49f5Sjdolecek SLIST_INSERT_HEAD(&u->lwps, xlwp, lwp_next);
392e78e0779Sbouyer }
393e78e0779Sbouyer mutex_exit(&u->mtx);
3941c0b49f5Sjdolecek
395ed3fe49dSbouyer return 0;
396ed3fe49dSbouyer }
397ed3fe49dSbouyer
39816046408Sbouyer static int
xenbus_dev_close(void * v)39916046408Sbouyer xenbus_dev_close(void *v)
400ed3fe49dSbouyer {
40116046408Sbouyer struct vop_close_args /* {
40216046408Sbouyer struct vnode *a_vp;
40316046408Sbouyer int a_fflag;
40416046408Sbouyer struct ucred *a_cred;
40516046408Sbouyer } */ *ap = v;
40616046408Sbouyer struct kernfs_node *kfs = VTOKERN(ap->a_vp);
407ed3fe49dSbouyer
408f0d7af04Sbouyer struct xenbus_dev_data *u;
409e78e0779Sbouyer struct xenbus_dev_lwp *xlwp;
41016046408Sbouyer struct xenbus_dev_transaction *trans;
41116046408Sbouyer
412e78e0779Sbouyer mutex_enter(&xenbus_dev_open_mtx);
413e78e0779Sbouyer u = kfs->kfs_v;
414e78e0779Sbouyer KASSERT(u != NULL);
415e78e0779Sbouyer mutex_enter(&u->mtx);
416e78e0779Sbouyer SLIST_FOREACH(xlwp, &u->lwps, lwp_next) {
417e78e0779Sbouyer if (xlwp->lwp == curlwp) {
418e78e0779Sbouyer break;
419e78e0779Sbouyer }
420e78e0779Sbouyer }
421e78e0779Sbouyer if (xlwp == NULL) {
422e78e0779Sbouyer mutex_exit(&u->mtx);
423e78e0779Sbouyer mutex_exit(&xenbus_dev_open_mtx);
424e78e0779Sbouyer return EBADF;
425e78e0779Sbouyer }
426e78e0779Sbouyer mutex_enter(&xlwp->mtx);
427e78e0779Sbouyer while (!SLIST_EMPTY(&xlwp->transactions)) {
428e78e0779Sbouyer trans = SLIST_FIRST(&xlwp->transactions);
429ed3fe49dSbouyer xenbus_transaction_end(trans->handle, 1);
430e78e0779Sbouyer SLIST_REMOVE_HEAD(&xlwp->transactions, trans_next);
4311c0b49f5Sjdolecek kmem_free(trans, sizeof(*trans));
432ed3fe49dSbouyer }
433e78e0779Sbouyer mutex_exit(&xlwp->mtx);
434e78e0779Sbouyer SLIST_REMOVE(&u->lwps, xlwp, xenbus_dev_lwp, lwp_next);
435e78e0779Sbouyer mutex_destroy(&xlwp->mtx);
436ed3fe49dSbouyer
437e78e0779Sbouyer if (!SLIST_EMPTY(&u->lwps)) {
438e78e0779Sbouyer mutex_exit(&u->mtx);
439e78e0779Sbouyer mutex_exit(&xenbus_dev_open_mtx);
440e78e0779Sbouyer return 0;
441e78e0779Sbouyer }
442e78e0779Sbouyer mutex_exit(&u->mtx);
443e78e0779Sbouyer mutex_destroy(&u->mtx);
44416046408Sbouyer kfs->kfs_v = NULL;
445e78e0779Sbouyer mutex_exit(&xenbus_dev_open_mtx);
4461c0b49f5Sjdolecek kmem_free(xlwp, sizeof(*xlwp));
4471c0b49f5Sjdolecek kmem_free(u, sizeof(*u));
448ed3fe49dSbouyer return 0;
449ed3fe49dSbouyer }
450ed3fe49dSbouyer
4512ed85162Sbouyer #define LD_STRLEN 21 /* a 64bit integer needs 20 digits in base10 */
4522ed85162Sbouyer
4532ed85162Sbouyer static int
xsd_port_read(void * v)4542ed85162Sbouyer xsd_port_read(void *v)
4552ed85162Sbouyer {
4562ed85162Sbouyer struct vop_read_args /* {
4572ed85162Sbouyer struct vnode *a_vp;
4582ed85162Sbouyer struct uio *a_uio;
4592ed85162Sbouyer int a_ioflag;
4602ed85162Sbouyer struct ucred *a_cred;
4612ed85162Sbouyer } */ *ap = v;
4622ed85162Sbouyer struct uio *uio = ap->a_uio;
4632ed85162Sbouyer int off, error;
4642ed85162Sbouyer size_t len;
4652ed85162Sbouyer char strbuf[LD_STRLEN], *bf;
4662ed85162Sbouyer
4672ed85162Sbouyer off = (int)uio->uio_offset;
4682ed85162Sbouyer if (off < 0)
4692ed85162Sbouyer return EINVAL;
4702ed85162Sbouyer
4712ed85162Sbouyer len = snprintf(strbuf, sizeof(strbuf), "%ld\n",
4722ed85162Sbouyer (long)xen_start_info.store_evtchn);
4732ed85162Sbouyer if (off >= len) {
4742ed85162Sbouyer bf = strbuf;
4752ed85162Sbouyer len = 0;
4762ed85162Sbouyer } else {
4772ed85162Sbouyer bf = &strbuf[off];
4782ed85162Sbouyer len -= off;
4792ed85162Sbouyer }
4802ed85162Sbouyer error = uiomove(bf, len, uio);
4812ed85162Sbouyer return error;
4822ed85162Sbouyer }
4832ed85162Sbouyer
484ed3fe49dSbouyer /*
485ed3fe49dSbouyer * Local variables:
486ed3fe49dSbouyer * c-file-style: "linux"
487ed3fe49dSbouyer * indent-tabs-mode: t
488ed3fe49dSbouyer * c-indent-level: 8
489ed3fe49dSbouyer * c-basic-offset: 8
490ed3fe49dSbouyer * tab-width: 8
491ed3fe49dSbouyer * End:
492ed3fe49dSbouyer */
493