1 1.19 andvar /* $NetBSD: xenbus_dev.c,v 1.19 2024/02/09 22:08:34 andvar 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.19 andvar __KERNEL_RCSID(0, "$NetBSD: xenbus_dev.c,v 1.19 2024/02/09 22:08:34 andvar 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.18 bouyer #include <xen/intr.h> 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.19 andvar * Unfortunately 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.16 jdolecek trans = kmem_alloc(sizeof(*trans), KM_SLEEP); 293 1.1 bouyer trans->handle = (struct xenbus_transaction *) 294 1.2 bouyer strtoul(reply, NULL, 0); 295 1.11 bouyer SLIST_INSERT_HEAD(&xlwp->transactions, 296 1.2 bouyer trans, trans_next); 297 1.11 bouyer } else if (xlwp->u.msg.type == XS_TRANSACTION_END) { 298 1.11 bouyer SLIST_FOREACH(trans, &xlwp->transactions, 299 1.2 bouyer trans_next) { 300 1.1 bouyer if ((unsigned long)trans->handle == 301 1.11 bouyer (unsigned long)xlwp->u.msg.tx_id) 302 1.1 bouyer break; 303 1.2 bouyer } 304 1.11 bouyer if (trans == NULL) { 305 1.11 bouyer err = EINVAL; 306 1.11 bouyer goto end; 307 1.11 bouyer } 308 1.11 bouyer SLIST_REMOVE(&xlwp->transactions, trans, 309 1.2 bouyer xenbus_dev_transaction, trans_next); 310 1.16 jdolecek kmem_free(trans, sizeof(*trans)); 311 1.1 bouyer } 312 1.11 bouyer queue_reply(xlwp, (char *)&xlwp->u.msg, 313 1.11 bouyer sizeof(xlwp->u.msg)); 314 1.11 bouyer queue_reply(xlwp, (char *)reply, xlwp->u.msg.len); 315 1.17 jdolecek 316 1.17 jdolecek xenbus_dev_reply_free(&xlwp->u.msg, reply); 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.16 jdolecek mutex_exit(&xenbus_dev_open_mtx); 352 1.16 jdolecek 353 1.16 jdolecek u = kmem_zalloc(sizeof(*u), KM_SLEEP); 354 1.11 bouyer SLIST_INIT(&u->lwps); 355 1.11 bouyer mutex_init(&u->mtx, MUTEX_DEFAULT, IPL_NONE); 356 1.16 jdolecek 357 1.16 jdolecek mutex_enter(&xenbus_dev_open_mtx); 358 1.16 jdolecek /* 359 1.16 jdolecek * Must re-check if filled while waiting in alloc 360 1.16 jdolecek * by some other lwp. 361 1.16 jdolecek */ 362 1.16 jdolecek if (kfs->kfs_v) { 363 1.16 jdolecek kmem_free(u, sizeof(*u)); 364 1.16 jdolecek u = kfs->kfs_v; 365 1.16 jdolecek } else { 366 1.16 jdolecek kfs->kfs_v = u; 367 1.16 jdolecek } 368 1.11 bouyer }; 369 1.16 jdolecek mutex_exit(&xenbus_dev_open_mtx); 370 1.16 jdolecek 371 1.11 bouyer mutex_enter(&u->mtx); 372 1.11 bouyer SLIST_FOREACH(xlwp, &u->lwps, lwp_next) { 373 1.11 bouyer if (xlwp->lwp == curlwp) { 374 1.11 bouyer break; 375 1.11 bouyer } 376 1.11 bouyer } 377 1.11 bouyer if (xlwp == NULL) { 378 1.16 jdolecek mutex_exit(&u->mtx); 379 1.16 jdolecek 380 1.16 jdolecek xlwp = kmem_zalloc(sizeof(*xlwp), KM_SLEEP); 381 1.11 bouyer xlwp->lwp = curlwp; 382 1.11 bouyer SLIST_INIT(&xlwp->transactions); 383 1.13 bouyer mutex_init(&xlwp->mtx, MUTEX_DEFAULT, IPL_NONE); 384 1.16 jdolecek 385 1.16 jdolecek mutex_enter(&u->mtx); 386 1.16 jdolecek /* 387 1.16 jdolecek * While alloc can block, this can't be re-entered with 388 1.16 jdolecek * curlwp, so no need to re-check. Also the node can't 389 1.16 jdolecek * be closed while we are blocked here. 390 1.16 jdolecek */ 391 1.16 jdolecek SLIST_INSERT_HEAD(&u->lwps, xlwp, lwp_next); 392 1.11 bouyer } 393 1.11 bouyer mutex_exit(&u->mtx); 394 1.16 jdolecek 395 1.1 bouyer return 0; 396 1.1 bouyer } 397 1.1 bouyer 398 1.2 bouyer static int 399 1.2 bouyer xenbus_dev_close(void *v) 400 1.1 bouyer { 401 1.2 bouyer struct vop_close_args /* { 402 1.2 bouyer struct vnode *a_vp; 403 1.2 bouyer int a_fflag; 404 1.2 bouyer struct ucred *a_cred; 405 1.2 bouyer } */ *ap = v; 406 1.10 msaitoh struct kernfs_node *kfs = VTOKERN(ap->a_vp); 407 1.1 bouyer 408 1.14 bouyer struct xenbus_dev_data *u; 409 1.11 bouyer struct xenbus_dev_lwp *xlwp; 410 1.2 bouyer struct xenbus_dev_transaction *trans; 411 1.2 bouyer 412 1.11 bouyer mutex_enter(&xenbus_dev_open_mtx); 413 1.11 bouyer u = kfs->kfs_v; 414 1.11 bouyer KASSERT(u != NULL); 415 1.11 bouyer mutex_enter(&u->mtx); 416 1.11 bouyer SLIST_FOREACH(xlwp, &u->lwps, lwp_next) { 417 1.11 bouyer if (xlwp->lwp == curlwp) { 418 1.11 bouyer break; 419 1.11 bouyer } 420 1.11 bouyer } 421 1.11 bouyer if (xlwp == NULL) { 422 1.11 bouyer mutex_exit(&u->mtx); 423 1.11 bouyer mutex_exit(&xenbus_dev_open_mtx); 424 1.11 bouyer return EBADF; 425 1.11 bouyer } 426 1.11 bouyer mutex_enter(&xlwp->mtx); 427 1.11 bouyer while (!SLIST_EMPTY(&xlwp->transactions)) { 428 1.11 bouyer trans = SLIST_FIRST(&xlwp->transactions); 429 1.1 bouyer xenbus_transaction_end(trans->handle, 1); 430 1.11 bouyer SLIST_REMOVE_HEAD(&xlwp->transactions, trans_next); 431 1.16 jdolecek kmem_free(trans, sizeof(*trans)); 432 1.1 bouyer } 433 1.11 bouyer mutex_exit(&xlwp->mtx); 434 1.11 bouyer SLIST_REMOVE(&u->lwps, xlwp, xenbus_dev_lwp, lwp_next); 435 1.11 bouyer mutex_destroy(&xlwp->mtx); 436 1.11 bouyer 437 1.11 bouyer if (!SLIST_EMPTY(&u->lwps)) { 438 1.11 bouyer mutex_exit(&u->mtx); 439 1.11 bouyer mutex_exit(&xenbus_dev_open_mtx); 440 1.11 bouyer return 0; 441 1.11 bouyer } 442 1.11 bouyer mutex_exit(&u->mtx); 443 1.11 bouyer mutex_destroy(&u->mtx); 444 1.11 bouyer kfs->kfs_v = NULL; 445 1.11 bouyer mutex_exit(&xenbus_dev_open_mtx); 446 1.16 jdolecek kmem_free(xlwp, sizeof(*xlwp)); 447 1.16 jdolecek kmem_free(u, sizeof(*u)); 448 1.1 bouyer return 0; 449 1.1 bouyer } 450 1.1 bouyer 451 1.3 bouyer #define LD_STRLEN 21 /* a 64bit integer needs 20 digits in base10 */ 452 1.3 bouyer 453 1.3 bouyer static int 454 1.3 bouyer xsd_port_read(void *v) 455 1.3 bouyer { 456 1.3 bouyer struct vop_read_args /* { 457 1.3 bouyer struct vnode *a_vp; 458 1.3 bouyer struct uio *a_uio; 459 1.3 bouyer int a_ioflag; 460 1.3 bouyer struct ucred *a_cred; 461 1.3 bouyer } */ *ap = v; 462 1.3 bouyer struct uio *uio = ap->a_uio; 463 1.3 bouyer int off, error; 464 1.10 msaitoh size_t len; 465 1.3 bouyer char strbuf[LD_STRLEN], *bf; 466 1.3 bouyer 467 1.3 bouyer off = (int)uio->uio_offset; 468 1.3 bouyer if (off < 0) 469 1.3 bouyer return EINVAL; 470 1.3 bouyer 471 1.3 bouyer len = snprintf(strbuf, sizeof(strbuf), "%ld\n", 472 1.3 bouyer (long)xen_start_info.store_evtchn); 473 1.3 bouyer if (off >= len) { 474 1.3 bouyer bf = strbuf; 475 1.3 bouyer len = 0; 476 1.3 bouyer } else { 477 1.3 bouyer bf = &strbuf[off]; 478 1.3 bouyer len -= off; 479 1.3 bouyer } 480 1.3 bouyer error = uiomove(bf, len, uio); 481 1.3 bouyer return error; 482 1.3 bouyer } 483 1.3 bouyer 484 1.1 bouyer /* 485 1.1 bouyer * Local variables: 486 1.1 bouyer * c-file-style: "linux" 487 1.1 bouyer * indent-tabs-mode: t 488 1.1 bouyer * c-indent-level: 8 489 1.1 bouyer * c-basic-offset: 8 490 1.1 bouyer * tab-width: 8 491 1.1 bouyer * End: 492 1.1 bouyer */ 493