1 /* $NetBSD: putter.c,v 1.6 2007/12/03 15:24:06 pooka Exp $ */ 2 3 /* 4 * Copyright (c) 2006, 2007 Antti Kantee. All Rights Reserved. 5 * 6 * Development of this software was supported by the 7 * Ulla Tuominen Foundation and the Finnish Cultural Foundation and the 8 * Research Foundation of Helsinki University of Technology 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 20 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 /* 33 * Pass-to-Userspace TransporTER: generic kernel-user request-response 34 * transport interface. 35 */ 36 37 #include <sys/cdefs.h> 38 __KERNEL_RCSID(0, "$NetBSD: putter.c,v 1.6 2007/12/03 15:24:06 pooka Exp $"); 39 40 #include <sys/param.h> 41 #include <sys/conf.h> 42 #include <sys/file.h> 43 #include <sys/filedesc.h> 44 #include <sys/kmem.h> 45 #include <sys/poll.h> 46 #include <sys/socketvar.h> 47 48 #include <dev/putter/putter_sys.h> 49 50 /* 51 * Configuration data. 52 * 53 * This is static-size for now. Will be redone for devfs. 54 */ 55 56 #define PUTTER_CONFSIZE 16 57 58 static struct putter_config { 59 int pc_minor; 60 int (*pc_config)(int, int, int); 61 } putterconf[PUTTER_CONFSIZE]; 62 63 static int 64 putter_configure(dev_t dev, int flags, int fmt, int fd) 65 { 66 struct putter_config *pc; 67 68 /* are we the catch-all node? */ 69 if (minor(dev) == PUTTER_MINOR_WILDCARD 70 || minor(dev) == PUTTER_MINOR_COMPAT) 71 return 0; 72 73 /* nopes? try to configure us */ 74 for (pc = putterconf; pc->pc_config; pc++) 75 if (minor(dev) == pc->pc_minor) 76 return pc->pc_config(fd, flags, fmt); 77 return ENXIO; 78 } 79 80 int 81 putter_register(putter_config_fn pcfn, int minor) 82 { 83 int i; 84 85 for (i = 0; i < PUTTER_CONFSIZE; i++) 86 if (putterconf[i].pc_config == NULL) 87 break; 88 if (i == PUTTER_CONFSIZE) 89 return EBUSY; 90 91 putterconf[i].pc_minor = minor; 92 putterconf[i].pc_config = pcfn; 93 return 0; 94 } 95 96 /* 97 * putter instance structures. these are always allocated and freed 98 * from the context of the transport user. 99 */ 100 struct putter_instance { 101 pid_t pi_pid; 102 int pi_idx; 103 int pi_fd; 104 struct selinfo pi_sel; 105 106 void *pi_private; 107 struct putter_ops *pi_pop; 108 109 uint8_t *pi_curput; 110 size_t pi_curres; 111 void *pi_curopaq; 112 113 TAILQ_ENTRY(putter_instance) pi_entries; 114 }; 115 #define PUTTER_EMBRYO ((void *)-1) /* before attach */ 116 #define PUTTER_DEAD ((void *)-2) /* after detach */ 117 118 static TAILQ_HEAD(, putter_instance) putter_ilist 119 = TAILQ_HEAD_INITIALIZER(putter_ilist); 120 121 static int get_pi_idx(struct putter_instance *); 122 123 #ifdef DEBUG 124 #ifndef PUTTERDEBUG 125 #define PUTTERDEBUG 126 #endif 127 #endif 128 129 #ifdef PUTTERDEBUG 130 static int putterdebug = 0; 131 #define DPRINTF(x) if (putterdebug > 0) printf x 132 #define DPRINTF_VERBOSE(x) if (putterdebug > 1) printf x 133 #else 134 #define DPRINTF(x) 135 #define DPRINTF_VERBOSE(x) 136 #endif 137 138 /* 139 * public init / deinit 140 */ 141 142 /* protects both the list and the contents of the list elements */ 143 static kmutex_t pi_mtx; 144 145 void putterattach(void); 146 147 void 148 putterattach() 149 { 150 151 mutex_init(&pi_mtx, MUTEX_DEFAULT, IPL_NONE); 152 } 153 154 #if 0 155 void 156 putter_destroy() 157 { 158 159 mutex_destroy(&pi_mtx); 160 } 161 #endif 162 163 /* 164 * fd routines, for cloner 165 */ 166 static int putter_fop_read(struct file *, off_t *, struct uio *, 167 kauth_cred_t, int); 168 static int putter_fop_write(struct file *, off_t *, struct uio *, 169 kauth_cred_t, int); 170 static int putter_fop_ioctl(struct file*, u_long, void *, struct lwp *); 171 static int putter_fop_poll(struct file *, int, struct lwp *); 172 static int putter_fop_close(struct file *, struct lwp *); 173 static int putter_fop_kqfilter(struct file *, struct knote *); 174 175 176 static const struct fileops putter_fileops = { 177 putter_fop_read, 178 putter_fop_write, 179 putter_fop_ioctl, 180 fnullop_fcntl, 181 putter_fop_poll, 182 fbadop_stat, 183 putter_fop_close, 184 putter_fop_kqfilter 185 }; 186 187 static int 188 putter_fop_read(struct file *fp, off_t *off, struct uio *uio, 189 kauth_cred_t cred, int flags) 190 { 191 struct putter_instance *pi = fp->f_data; 192 size_t origres, moved; 193 int error; 194 195 if (pi->pi_private == PUTTER_EMBRYO || pi->pi_private == PUTTER_DEAD) { 196 printf("putter_fop_read: private %d not inited\n", pi->pi_idx); 197 return ENOENT; 198 } 199 200 if (pi->pi_curput == NULL) { 201 error = pi->pi_pop->pop_getout(pi->pi_private, uio->uio_resid, 202 fp->f_flag & O_NONBLOCK, &pi->pi_curput, 203 &pi->pi_curres, &pi->pi_curopaq); 204 if (error) 205 return error; 206 } 207 208 origres = uio->uio_resid; 209 error = uiomove(pi->pi_curput, pi->pi_curres, uio); 210 moved = origres - uio->uio_resid; 211 DPRINTF(("putter_fop_read (%p): moved %zu bytes from %p, error %d\n", 212 pi, moved, pi->pi_curput, error)); 213 214 KASSERT(pi->pi_curres >= moved); 215 pi->pi_curres -= moved; 216 pi->pi_curput += moved; 217 218 if (pi->pi_curres == 0) { 219 pi->pi_pop->pop_releaseout(pi->pi_private, 220 pi->pi_curopaq, error); 221 pi->pi_curput = NULL; 222 } 223 224 return error; 225 } 226 227 static int 228 putter_fop_write(struct file *fp, off_t *off, struct uio *uio, 229 kauth_cred_t cred, int flags) 230 { 231 struct putter_instance *pi = fp->f_data; 232 struct putter_hdr pth; 233 uint8_t *buf; 234 size_t frsize; 235 int error; 236 237 DPRINTF(("putter_fop_write (%p): writing response, resid %zu\n", 238 pi->pi_private, uio->uio_resid)); 239 240 if (pi->pi_private == PUTTER_EMBRYO || pi->pi_private == PUTTER_DEAD) { 241 printf("putter_fop_write: putter %d not inited\n", pi->pi_idx); 242 return ENOENT; 243 } 244 245 error = uiomove(&pth, sizeof(struct putter_hdr), uio); 246 if (error) 247 return error; 248 249 /* Sorry mate, the kernel doesn't buffer. */ 250 frsize = pth.pth_framelen - sizeof(struct putter_hdr); 251 if (uio->uio_resid < frsize) 252 return EINVAL; 253 254 buf = kmem_alloc(frsize + sizeof(struct putter_hdr), KM_SLEEP); 255 memcpy(buf, &pth, sizeof(pth)); 256 error = uiomove(buf+sizeof(struct putter_hdr), frsize, uio); 257 if (error == 0) { 258 pi->pi_pop->pop_dispatch(pi->pi_private, 259 (struct putter_hdr *)buf); 260 } 261 kmem_free(buf, frsize + sizeof(struct putter_hdr)); 262 263 return error; 264 } 265 266 /* 267 * Poll query interface. The question is only if an event 268 * can be read from us. 269 */ 270 #define PUTTERPOLL_EVSET (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI) 271 static int 272 putter_fop_poll(struct file *fp, int events, struct lwp *l) 273 { 274 struct putter_instance *pi = fp->f_data; 275 int revents; 276 277 if (pi->pi_private == PUTTER_EMBRYO || pi->pi_private == PUTTER_DEAD) { 278 printf("putter_fop_ioctl: putter %d not inited\n", pi->pi_idx); 279 return ENOENT; 280 } 281 282 revents = events & (POLLOUT | POLLWRNORM | POLLWRBAND); 283 if ((events & PUTTERPOLL_EVSET) == 0) 284 return revents; 285 286 /* check queue */ 287 if (pi->pi_pop->pop_waitcount(pi->pi_private)) 288 revents |= PUTTERPOLL_EVSET; 289 else 290 selrecord(l, &pi->pi_sel); 291 292 return revents; 293 } 294 295 /* 296 * device close = forced unmount. 297 * 298 * unmounting is a frightfully complex operation to avoid races 299 */ 300 static int 301 putter_fop_close(struct file *fp, struct lwp *l) 302 { 303 struct putter_instance *pi = fp->f_data; 304 int rv; 305 306 DPRINTF(("putter_fop_close: device closed\n")); 307 308 restart: 309 mutex_enter(&pi_mtx); 310 /* 311 * First check if the fs was never mounted. In that case 312 * remove the instance from the list. If mount is attempted later, 313 * it will simply fail. 314 */ 315 if (pi->pi_private == PUTTER_EMBRYO) { 316 TAILQ_REMOVE(&putter_ilist, pi, pi_entries); 317 mutex_exit(&pi_mtx); 318 319 DPRINTF(("putter_fop_close: data associated with fp %p was " 320 "embryonic\n", fp)); 321 322 goto out; 323 } 324 325 /* 326 * Next, analyze if unmount was called and the instance is dead. 327 * In this case we can just free the structure and go home, it 328 * was removed from the list by putter_rmprivate(). 329 */ 330 if (pi->pi_private == PUTTER_DEAD) { 331 mutex_exit(&pi_mtx); 332 333 DPRINTF(("putter_fop_close: putter associated with fp %p (%d) " 334 "dead, freeing\n", fp, pi->pi_idx)); 335 336 goto out; 337 } 338 339 /* 340 * So we have a reference. Proceed to unwrap the file system. 341 */ 342 mutex_exit(&pi_mtx); 343 344 /* hmm? suspicious locking? */ 345 while ((rv = pi->pi_pop->pop_close(pi->pi_private)) == ERESTART) 346 goto restart; 347 348 out: 349 /* 350 * Finally, release the instance information. It was already 351 * removed from the list by putter_rmprivate() and we know it's 352 * dead, so no need to lock. 353 */ 354 kmem_free(pi, sizeof(struct putter_instance)); 355 356 return 0; 357 } 358 359 static int 360 putter_fop_ioctl(struct file *fp, u_long cmd, void *data, struct lwp *l) 361 { 362 363 /* 364 * work already done in sys_ioctl(). skip sanity checks to enable 365 * setting non-blocking fd without yet having mounted the fs 366 */ 367 if (cmd == FIONBIO) 368 return 0; 369 370 return EINVAL; 371 } 372 373 /* kqueue stuff */ 374 375 static void 376 filt_putterdetach(struct knote *kn) 377 { 378 struct putter_instance *pi = kn->kn_hook; 379 380 mutex_enter(&pi_mtx); 381 SLIST_REMOVE(&pi->pi_sel.sel_klist, kn, knote, kn_selnext); 382 mutex_exit(&pi_mtx); 383 } 384 385 static int 386 filt_putter(struct knote *kn, long hint) 387 { 388 struct putter_instance *pi = kn->kn_hook; 389 int error; 390 391 error = 0; 392 mutex_enter(&pi_mtx); 393 if (pi->pi_private == PUTTER_EMBRYO || pi->pi_private == PUTTER_DEAD) 394 error = 1; 395 mutex_exit(&pi_mtx); 396 if (error) 397 return 0; 398 399 kn->kn_data = pi->pi_pop->pop_waitcount(pi->pi_private); 400 401 return kn->kn_data != 0; 402 } 403 404 static const struct filterops putter_filtops = 405 { 1, NULL, filt_putterdetach, filt_putter }; 406 407 static int 408 putter_fop_kqfilter(struct file *fp, struct knote *kn) 409 { 410 struct putter_instance *pi = fp->f_data; 411 struct klist *klist; 412 413 switch (kn->kn_filter) { 414 case EVFILT_READ: 415 klist = &pi->pi_sel.sel_klist; 416 kn->kn_fop = &putter_filtops; 417 kn->kn_hook = pi; 418 419 mutex_enter(&pi_mtx); 420 SLIST_INSERT_HEAD(klist, kn, kn_selnext); 421 mutex_exit(&pi_mtx); 422 423 break; 424 case EVFILT_WRITE: 425 kn->kn_fop = &seltrue_filtops; 426 break; 427 default: 428 return EINVAL; 429 } 430 431 return 0; 432 } 433 434 /* 435 * Device routines. These are for when /dev/puffs is initially 436 * opened before it has been cloned. 437 */ 438 439 dev_type_open(puttercdopen); 440 dev_type_close(puttercdclose); 441 dev_type_ioctl(puttercdioctl); 442 443 /* dev */ 444 const struct cdevsw putter_cdevsw = { 445 puttercdopen, puttercdclose, noread, nowrite, 446 noioctl, nostop, notty, nopoll, 447 nommap, nokqfilter, D_OTHER 448 }; 449 int 450 puttercdopen(dev_t dev, int flags, int fmt, struct lwp *l) 451 { 452 struct putter_instance *pi; 453 struct file *fp; 454 int error, fd, idx; 455 456 pi = kmem_alloc(sizeof(struct putter_instance), KM_SLEEP); 457 mutex_enter(&pi_mtx); 458 idx = get_pi_idx(pi); 459 460 pi->pi_pid = l->l_proc->p_pid; 461 pi->pi_idx = idx; 462 pi->pi_curput = NULL; 463 pi->pi_curres = 0; 464 pi->pi_curopaq = NULL; 465 selinit(&pi->pi_sel); 466 mutex_exit(&pi_mtx); 467 468 if ((error = falloc(l, &fp, &fd)) != 0) 469 goto bad1; 470 471 if ((error = putter_configure(dev, flags, fmt, fd)) != 0) 472 goto bad2; 473 474 DPRINTF(("puttercdopen: registered embryonic pmp for pid: %d\n", 475 pi->pi_pid)); 476 477 error = fdclone(l, fp, fd, FREAD|FWRITE, &putter_fileops, pi); 478 KASSERT(error = EMOVEFD); 479 return error; 480 481 bad2: 482 FILE_UNUSE(fp, l); 483 fdremove(l->l_proc->p_fd, fd); 484 ffree(fp); 485 bad1: 486 putter_detach(pi); 487 kmem_free(pi, sizeof(struct putter_instance)); 488 return error; 489 } 490 491 int 492 puttercdclose(dev_t dev, int flags, int fmt, struct lwp *l) 493 { 494 495 panic("puttercdclose impossible\n"); 496 497 return 0; 498 } 499 500 501 /* 502 * Set the private structure for the file descriptor. This is 503 * typically done immediately when the counterpart has knowledge 504 * about the private structure's address and the file descriptor 505 * (e.g. vfs mount routine). 506 * 507 * We only want to make sure that the caller had the right to open the 508 * device, we don't so much care about which context it gets in case 509 * the same process opened multiple (since they are equal at this point). 510 */ 511 struct putter_instance * 512 putter_attach(pid_t pid, int fd, void *ppriv, struct putter_ops *pop) 513 { 514 struct putter_instance *pi = NULL; 515 516 mutex_enter(&pi_mtx); 517 TAILQ_FOREACH(pi, &putter_ilist, pi_entries) { 518 if (pi->pi_pid == pid && pi->pi_private == PUTTER_EMBRYO) { 519 pi->pi_private = ppriv; 520 pi->pi_fd = fd; 521 pi->pi_pop = pop; 522 break; 523 } 524 } 525 mutex_exit(&pi_mtx); 526 527 DPRINTF(("putter_setprivate: pi at %p (%d/%d)\n", pi, 528 pi ? pi->pi_pid : 0, pi ? pi->pi_fd : 0)); 529 530 return pi; 531 } 532 533 /* 534 * Remove fp <-> private mapping. 535 */ 536 void 537 putter_detach(struct putter_instance *pi) 538 { 539 540 mutex_enter(&pi_mtx); 541 TAILQ_REMOVE(&putter_ilist, pi, pi_entries); 542 pi->pi_private = PUTTER_DEAD; 543 mutex_exit(&pi_mtx); 544 545 DPRINTF(("putter_nukebypmp: nuked %p\n", pi)); 546 } 547 548 void 549 putter_notify(struct putter_instance *pi) 550 { 551 552 selnotify(&pi->pi_sel, 0); 553 } 554 555 /* search sorted list of instances for free minor, sorted insert arg */ 556 static int 557 get_pi_idx(struct putter_instance *pi_i) 558 { 559 struct putter_instance *pi; 560 int i; 561 562 KASSERT(mutex_owned(&pi_mtx)); 563 564 i = 0; 565 TAILQ_FOREACH(pi, &putter_ilist, pi_entries) { 566 if (i != pi->pi_idx) 567 break; 568 i++; 569 } 570 571 pi_i->pi_private = PUTTER_EMBRYO; 572 573 if (pi == NULL) 574 TAILQ_INSERT_TAIL(&putter_ilist, pi_i, pi_entries); 575 else 576 TAILQ_INSERT_BEFORE(pi, pi_i, pi_entries); 577 578 return i; 579 } 580