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