1 /* $NetBSD: puffs.c,v 1.80 2007/12/05 12:11:56 pooka Exp $ */ 2 3 /* 4 * Copyright (c) 2005, 2006, 2007 Antti Kantee. All Rights Reserved. 5 * 6 * Development of this software was supported by the 7 * Google Summer of Code program and the Ulla Tuominen Foundation. 8 * The Google SoC project was mentored by Bill Studenmund. 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 #include <sys/cdefs.h> 33 #if !defined(lint) 34 __RCSID("$NetBSD: puffs.c,v 1.80 2007/12/05 12:11:56 pooka Exp $"); 35 #endif /* !lint */ 36 37 #include <sys/param.h> 38 #include <sys/mount.h> 39 40 #include <assert.h> 41 #include <err.h> 42 #include <errno.h> 43 #include <fcntl.h> 44 #include <mntopts.h> 45 #include <paths.h> 46 #include <puffs.h> 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 #include <syslog.h> 51 #include <unistd.h> 52 53 #include "puffs_priv.h" 54 55 /* Most file systems want this for opts, so just give it to them */ 56 const struct mntopt puffsmopts[] = { 57 MOPT_STDOPTS, 58 PUFFSMOPT_STD, 59 MOPT_NULL, 60 }; 61 62 #ifdef PUFFS_WITH_THREADS 63 #include <pthread.h> 64 pthread_mutex_t pu_lock = PTHREAD_MUTEX_INITIALIZER; 65 #endif 66 67 #define FILLOP(lower, upper) \ 68 do { \ 69 if (pops->puffs_node_##lower) \ 70 opmask[PUFFS_VN_##upper] = 1; \ 71 } while (/*CONSTCOND*/0) 72 static void 73 fillvnopmask(struct puffs_ops *pops, uint8_t *opmask) 74 { 75 76 memset(opmask, 0, PUFFS_VN_MAX); 77 78 FILLOP(create, CREATE); 79 FILLOP(mknod, MKNOD); 80 FILLOP(open, OPEN); 81 FILLOP(close, CLOSE); 82 FILLOP(access, ACCESS); 83 FILLOP(getattr, GETATTR); 84 FILLOP(setattr, SETATTR); 85 FILLOP(poll, POLL); /* XXX: not ready in kernel */ 86 FILLOP(mmap, MMAP); 87 FILLOP(fsync, FSYNC); 88 FILLOP(seek, SEEK); 89 FILLOP(remove, REMOVE); 90 FILLOP(link, LINK); 91 FILLOP(rename, RENAME); 92 FILLOP(mkdir, MKDIR); 93 FILLOP(rmdir, RMDIR); 94 FILLOP(symlink, SYMLINK); 95 FILLOP(readdir, READDIR); 96 FILLOP(readlink, READLINK); 97 FILLOP(reclaim, RECLAIM); 98 FILLOP(inactive, INACTIVE); 99 FILLOP(print, PRINT); 100 FILLOP(read, READ); 101 FILLOP(write, WRITE); 102 } 103 #undef FILLOP 104 105 /* 106 * Go over all framev entries and write everything we can. This is 107 * mostly for the benefit of delivering "unmount" to the kernel. 108 */ 109 static void 110 finalpush(struct puffs_usermount *pu) 111 { 112 struct puffs_fctrl_io *fio; 113 114 LIST_FOREACH(fio, &pu->pu_ios, fio_entries) { 115 if (fio->stat & FIO_WRGONE) 116 continue; 117 118 puffs_framev_output(pu, fio->fctrl, fio); 119 } 120 } 121 122 /*ARGSUSED*/ 123 static void 124 puffs_defaulterror(struct puffs_usermount *pu, uint8_t type, 125 int error, const char *str, void *cookie) 126 { 127 128 fprintf(stderr, "abort: type %d, error %d, cookie %p (%s)\n", 129 type, error, cookie, str); 130 abort(); 131 } 132 133 int 134 puffs_getselectable(struct puffs_usermount *pu) 135 { 136 137 return pu->pu_fd; 138 } 139 140 uint64_t 141 puffs__nextreq(struct puffs_usermount *pu) 142 { 143 uint64_t rv; 144 145 PU_LOCK(); 146 rv = pu->pu_nextreq++; 147 PU_UNLOCK(); 148 149 return rv; 150 } 151 152 int 153 puffs_setblockingmode(struct puffs_usermount *pu, int mode) 154 { 155 int rv, x; 156 157 assert(puffs_getstate(pu) == PUFFS_STATE_RUNNING); 158 159 if (mode != PUFFSDEV_BLOCK && mode != PUFFSDEV_NONBLOCK) { 160 errno = EINVAL; 161 return -1; 162 } 163 164 x = mode; 165 rv = ioctl(pu->pu_fd, FIONBIO, &x); 166 167 if (rv == 0) { 168 if (mode == PUFFSDEV_BLOCK) 169 pu->pu_state &= ~PU_ASYNCFD; 170 else 171 pu->pu_state |= PU_ASYNCFD; 172 } 173 174 return rv; 175 } 176 177 int 178 puffs_getstate(struct puffs_usermount *pu) 179 { 180 181 return pu->pu_state & PU_STATEMASK; 182 } 183 184 void 185 puffs_setstacksize(struct puffs_usermount *pu, size_t ss) 186 { 187 long psize; 188 int stackshift; 189 190 psize = sysconf(_SC_PAGESIZE); 191 if (ss < 2*psize) { 192 ss = 2*psize; 193 fprintf(stderr, "puffs_setstacksize: adjusting stacksize " 194 "to minimum %zu\n", ss); 195 } 196 197 assert(puffs_getstate(pu) == PUFFS_STATE_BEFOREMOUNT); 198 stackshift = -1; 199 while (ss) { 200 ss >>= 1; 201 stackshift++; 202 } 203 pu->pu_cc_stackshift = stackshift; 204 assert(1<<stackshift == ss); 205 } 206 207 struct puffs_pathobj * 208 puffs_getrootpathobj(struct puffs_usermount *pu) 209 { 210 struct puffs_node *pnr; 211 212 pnr = pu->pu_pn_root; 213 if (pnr == NULL) { 214 errno = ENOENT; 215 return NULL; 216 } 217 218 return &pnr->pn_po; 219 } 220 221 void 222 puffs_setroot(struct puffs_usermount *pu, struct puffs_node *pn) 223 { 224 225 pu->pu_pn_root = pn; 226 } 227 228 struct puffs_node * 229 puffs_getroot(struct puffs_usermount *pu) 230 { 231 232 return pu->pu_pn_root; 233 } 234 235 void 236 puffs_setrootinfo(struct puffs_usermount *pu, enum vtype vt, 237 vsize_t vsize, dev_t rdev) 238 { 239 struct puffs_kargs *pargs = pu->pu_kargp; 240 241 if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT) { 242 warnx("puffs_setrootinfo: call has effect only " 243 "before mount\n"); 244 return; 245 } 246 247 pargs->pa_root_vtype = vt; 248 pargs->pa_root_vsize = vsize; 249 pargs->pa_root_rdev = rdev; 250 } 251 252 void * 253 puffs_getspecific(struct puffs_usermount *pu) 254 { 255 256 return pu->pu_privdata; 257 } 258 259 size_t 260 puffs_getmaxreqlen(struct puffs_usermount *pu) 261 { 262 263 return pu->pu_maxreqlen; 264 } 265 266 void 267 puffs_setmaxreqlen(struct puffs_usermount *pu, size_t reqlen) 268 { 269 270 if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT) 271 warnx("puffs_setmaxreqlen: call has effect only " 272 "before mount\n"); 273 274 pu->pu_kargp->pa_maxmsglen = reqlen; 275 } 276 277 void 278 puffs_setfhsize(struct puffs_usermount *pu, size_t fhsize, int flags) 279 { 280 281 if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT) 282 warnx("puffs_setfhsize: call has effect only before mount\n"); 283 284 pu->pu_kargp->pa_fhsize = fhsize; 285 pu->pu_kargp->pa_fhflags = flags; 286 } 287 288 void 289 puffs_setncookiehash(struct puffs_usermount *pu, int nhash) 290 { 291 292 if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT) 293 warnx("puffs_setfhsize: call has effect only before mount\n"); 294 295 pu->pu_kargp->pa_nhashbuckets = nhash; 296 } 297 298 void 299 puffs_set_pathbuild(struct puffs_usermount *pu, pu_pathbuild_fn fn) 300 { 301 302 pu->pu_pathbuild = fn; 303 } 304 305 void 306 puffs_set_pathtransform(struct puffs_usermount *pu, pu_pathtransform_fn fn) 307 { 308 309 pu->pu_pathtransform = fn; 310 } 311 312 void 313 puffs_set_pathcmp(struct puffs_usermount *pu, pu_pathcmp_fn fn) 314 { 315 316 pu->pu_pathcmp = fn; 317 } 318 319 void 320 puffs_set_pathfree(struct puffs_usermount *pu, pu_pathfree_fn fn) 321 { 322 323 pu->pu_pathfree = fn; 324 } 325 326 void 327 puffs_set_namemod(struct puffs_usermount *pu, pu_namemod_fn fn) 328 { 329 330 pu->pu_namemod = fn; 331 } 332 333 void 334 puffs_set_errnotify(struct puffs_usermount *pu, pu_errnotify_fn fn) 335 { 336 337 pu->pu_errnotify = fn; 338 } 339 340 void 341 puffs_ml_setloopfn(struct puffs_usermount *pu, puffs_ml_loop_fn lfn) 342 { 343 344 pu->pu_ml_lfn = lfn; 345 } 346 347 void 348 puffs_ml_settimeout(struct puffs_usermount *pu, struct timespec *ts) 349 { 350 351 if (ts == NULL) { 352 pu->pu_ml_timep = NULL; 353 } else { 354 pu->pu_ml_timeout = *ts; 355 pu->pu_ml_timep = &pu->pu_ml_timeout; 356 } 357 } 358 359 void 360 puffs_set_prepost(struct puffs_usermount *pu, 361 pu_prepost_fn pre, pu_prepost_fn pst) 362 { 363 364 pu->pu_oppre = pre; 365 pu->pu_oppost = pst; 366 } 367 368 void 369 puffs_setback(struct puffs_cc *pcc, int whatback) 370 { 371 struct puffs_req *preq = puffs__framebuf_getdataptr(pcc->pcc_pb); 372 373 assert(PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN && ( 374 preq->preq_optype == PUFFS_VN_OPEN || 375 preq->preq_optype == PUFFS_VN_MMAP || 376 preq->preq_optype == PUFFS_VN_REMOVE || 377 preq->preq_optype == PUFFS_VN_RMDIR || 378 preq->preq_optype == PUFFS_VN_INACTIVE)); 379 380 preq->preq_setbacks |= whatback & PUFFS_SETBACK_MASK; 381 } 382 383 int 384 puffs_daemon(struct puffs_usermount *pu, int nochdir, int noclose) 385 { 386 ssize_t n; 387 int parent, value, fd; 388 389 if (pipe(pu->pu_dpipe) == -1) 390 return -1; 391 392 switch (fork()) { 393 case -1: 394 return -1; 395 case 0: 396 parent = 0; 397 break; 398 default: 399 parent = 1; 400 break; 401 } 402 pu->pu_state |= PU_PUFFSDAEMON; 403 404 if (parent) { 405 n = read(pu->pu_dpipe[0], &value, sizeof(int)); 406 if (n == -1) 407 err(1, "puffs_daemon"); 408 assert(n == sizeof(value)); 409 if (value) { 410 errno = value; 411 err(1, "puffs_daemon"); 412 } 413 exit(0); 414 } else { 415 if (setsid() == -1) 416 goto fail; 417 418 if (!nochdir) 419 chdir("/"); 420 421 if (!noclose) { 422 fd = open(_PATH_DEVNULL, O_RDWR, 0); 423 if (fd == -1) 424 goto fail; 425 dup2(fd, STDIN_FILENO); 426 dup2(fd, STDOUT_FILENO); 427 dup2(fd, STDERR_FILENO); 428 if (fd > STDERR_FILENO) 429 close(fd); 430 } 431 return 0; 432 } 433 434 fail: 435 n = write(pu->pu_dpipe[1], &errno, sizeof(int)); 436 assert(n == 4); 437 return -1; 438 } 439 440 int 441 puffs_mount(struct puffs_usermount *pu, const char *dir, int mntflags, 442 void *cookie) 443 { 444 char rp[MAXPATHLEN]; 445 ssize_t n; 446 int rv, fd, sverrno; 447 448 #if 1 449 /* XXXkludgehere */ 450 /* kauth doesn't provide this service any longer */ 451 if (geteuid() != 0) 452 mntflags |= MNT_NOSUID | MNT_NODEV; 453 #endif 454 455 if (realpath(dir, rp) == NULL) { 456 rv = -1; 457 goto out; 458 } 459 460 if (strcmp(dir, rp) != 0) { 461 warnx("puffs_mount: \"%s\" is a relative path.", dir); 462 warnx("puffs_mount: using \"%s\" instead.", rp); 463 } 464 465 fd = open(_PATH_PUFFS, O_RDWR); 466 if (fd == -1) { 467 warnx("puffs_mount: cannot open %s", _PATH_PUFFS); 468 rv = -1; 469 goto out; 470 } 471 if (fd <= 2) 472 warnx("puffs_init: device fd %d (<= 2), sure this is " 473 "what you want?", fd); 474 475 pu->pu_kargp->pa_fd = pu->pu_fd = fd; 476 pu->pu_kargp->pa_root_cookie = cookie; 477 if ((rv = mount(MOUNT_PUFFS, rp, mntflags, 478 pu->pu_kargp, sizeof(struct puffs_kargs))) == -1) 479 goto out; 480 #if 0 481 if ((rv = ioctl(pu->pu_fd, PUFFSREQSIZEOP, &pu->pu_maxreqlen)) == -1) 482 goto out; 483 #endif 484 PU_SETSTATE(pu, PUFFS_STATE_RUNNING); 485 486 out: 487 if (rv != 0) 488 sverrno = errno; 489 else 490 sverrno = 0; 491 free(pu->pu_kargp); 492 pu->pu_kargp = NULL; 493 494 if (pu->pu_state & PU_PUFFSDAEMON) { 495 n = write(pu->pu_dpipe[1], &sverrno, sizeof(int)); 496 assert(n == 4); 497 close(pu->pu_dpipe[0]); 498 close(pu->pu_dpipe[1]); 499 } 500 501 errno = sverrno; 502 return rv; 503 } 504 505 struct puffs_usermount * 506 _puffs_init(int develv, struct puffs_ops *pops, const char *mntfromname, 507 const char *puffsname, void *priv, uint32_t pflags) 508 { 509 struct puffs_usermount *pu; 510 struct puffs_kargs *pargs; 511 int sverrno; 512 513 if (develv != PUFFS_DEVEL_LIBVERSION) { 514 warnx("puffs_init: mounting with lib version %d, need %d", 515 develv, PUFFS_DEVEL_LIBVERSION); 516 errno = EINVAL; 517 return NULL; 518 } 519 520 pu = malloc(sizeof(struct puffs_usermount)); 521 if (pu == NULL) 522 goto failfree; 523 memset(pu, 0, sizeof(struct puffs_usermount)); 524 525 pargs = pu->pu_kargp = malloc(sizeof(struct puffs_kargs)); 526 if (pargs == NULL) 527 goto failfree; 528 memset(pargs, 0, sizeof(struct puffs_kargs)); 529 530 pargs->pa_vers = PUFFSDEVELVERS | PUFFSVERSION; 531 pargs->pa_flags = PUFFS_FLAG_KERN(pflags); 532 fillvnopmask(pops, pargs->pa_vnopmask); 533 (void)strlcpy(pargs->pa_typename, puffsname, 534 sizeof(pargs->pa_typename)); 535 (void)strlcpy(pargs->pa_mntfromname, mntfromname, 536 sizeof(pargs->pa_mntfromname)); 537 538 puffs_zerostatvfs(&pargs->pa_svfsb); 539 pargs->pa_root_cookie = NULL; 540 pargs->pa_root_vtype = VDIR; 541 pargs->pa_root_vsize = 0; 542 pargs->pa_root_rdev = 0; 543 pargs->pa_maxmsglen = 0; 544 545 pu->pu_flags = pflags; 546 pu->pu_ops = *pops; 547 free(pops); /* XXX */ 548 549 pu->pu_privdata = priv; 550 pu->pu_cc_stackshift = PUFFS_CC_STACKSHIFT_DEFAULT; 551 LIST_INIT(&pu->pu_pnodelst); 552 LIST_INIT(&pu->pu_ios); 553 LIST_INIT(&pu->pu_ios_rmlist); 554 LIST_INIT(&pu->pu_ccnukelst); 555 TAILQ_INIT(&pu->pu_sched); 556 TAILQ_INIT(&pu->pu_exq); 557 558 pu->pu_framectrl[PU_FRAMECTRL_FS].rfb = puffs_fsframe_read; 559 pu->pu_framectrl[PU_FRAMECTRL_FS].wfb = puffs_fsframe_write; 560 pu->pu_framectrl[PU_FRAMECTRL_FS].cmpfb = puffs_fsframe_cmp; 561 pu->pu_framectrl[PU_FRAMECTRL_FS].gotfb = puffs_fsframe_gotframe; 562 pu->pu_framectrl[PU_FRAMECTRL_FS].fdnotfn = puffs_framev_unmountonclose; 563 564 /* defaults for some user-settable translation functions */ 565 pu->pu_cmap = NULL; /* identity translation */ 566 567 pu->pu_pathbuild = puffs_stdpath_buildpath; 568 pu->pu_pathfree = puffs_stdpath_freepath; 569 pu->pu_pathcmp = puffs_stdpath_cmppath; 570 pu->pu_pathtransform = NULL; 571 pu->pu_namemod = NULL; 572 573 pu->pu_errnotify = puffs_defaulterror; 574 575 PU_SETSTATE(pu, PUFFS_STATE_BEFOREMOUNT); 576 577 return pu; 578 579 failfree: 580 /* can't unmount() from here for obvious reasons */ 581 sverrno = errno; 582 free(pu); 583 errno = sverrno; 584 return NULL; 585 } 586 587 /* 588 * XXX: there's currently no clean way to request unmount from 589 * within the user server, so be very brutal about it. 590 */ 591 /*ARGSUSED1*/ 592 int 593 puffs_exit(struct puffs_usermount *pu, int force) 594 { 595 struct puffs_node *pn; 596 597 force = 1; /* currently */ 598 599 if (pu->pu_fd) 600 close(pu->pu_fd); 601 602 while ((pn = LIST_FIRST(&pu->pu_pnodelst)) != NULL) 603 puffs_pn_put(pn); 604 605 finalpush(pu); 606 puffs_framev_exit(pu); 607 if (pu->pu_state & PU_HASKQ) 608 close(pu->pu_kq); 609 free(pu); 610 611 return 0; /* always succesful for now, WILL CHANGE */ 612 } 613 614 int 615 puffs_mainloop(struct puffs_usermount *pu) 616 { 617 struct puffs_framectrl *pfctrl; 618 struct puffs_fctrl_io *fio; 619 struct puffs_cc *pcc; 620 struct kevent *curev; 621 size_t nchanges; 622 int ndone, sverrno; 623 624 assert(puffs_getstate(pu) >= PUFFS_STATE_RUNNING); 625 626 pu->pu_kq = kqueue(); 627 if (pu->pu_kq == -1) 628 goto out; 629 pu->pu_state |= PU_HASKQ; 630 631 puffs_setblockingmode(pu, PUFFSDEV_NONBLOCK); 632 if (puffs__framev_addfd_ctrl(pu, puffs_getselectable(pu), 633 PUFFS_FBIO_READ | PUFFS_FBIO_WRITE, 634 &pu->pu_framectrl[PU_FRAMECTRL_FS]) == -1) 635 goto out; 636 637 curev = realloc(pu->pu_evs, (2*pu->pu_nfds)*sizeof(struct kevent)); 638 if (curev == NULL) 639 goto out; 640 pu->pu_evs = curev; 641 642 LIST_FOREACH(fio, &pu->pu_ios, fio_entries) { 643 EV_SET(curev, fio->io_fd, EVFILT_READ, EV_ADD, 644 0, 0, (uintptr_t)fio); 645 curev++; 646 EV_SET(curev, fio->io_fd, EVFILT_WRITE, EV_ADD | EV_DISABLE, 647 0, 0, (uintptr_t)fio); 648 curev++; 649 } 650 if (kevent(pu->pu_kq, pu->pu_evs, 2*pu->pu_nfds, NULL, 0, NULL) == -1) 651 goto out; 652 653 pu->pu_state |= PU_INLOOP; 654 655 while (puffs_getstate(pu) != PUFFS_STATE_UNMOUNTED) { 656 if (pu->pu_ml_lfn) 657 pu->pu_ml_lfn(pu); 658 659 /* XXX: can we still do these optimizations? */ 660 #if 0 661 /* 662 * Do this here, because: 663 * a) loopfunc might generate some results 664 * b) it's still "after" event handling (except for round 1) 665 */ 666 if (puffs_req_putput(ppr) == -1) 667 goto out; 668 puffs_req_resetput(ppr); 669 670 /* micro optimization: skip kevent syscall if possible */ 671 if (pu->pu_nfds == 1 && pu->pu_ml_timep == NULL 672 && (pu->pu_state & PU_ASYNCFD) == 0) { 673 pfctrl = XXX->fctrl; 674 puffs_framev_input(pu, pfctrl, XXX); 675 continue; 676 } 677 #endif 678 679 /* else: do full processing */ 680 /* Don't bother worrying about O(n) for now */ 681 LIST_FOREACH(fio, &pu->pu_ios, fio_entries) { 682 if (fio->stat & FIO_WRGONE) 683 continue; 684 685 pfctrl = fio->fctrl; 686 687 /* 688 * Try to write out everything to avoid the 689 * need for enabling EVFILT_WRITE. The likely 690 * case is that we can fit everything into the 691 * socket buffer. 692 */ 693 puffs_framev_output(pu, pfctrl, fio); 694 } 695 696 /* 697 * Build list of which to enable/disable in writecheck. 698 */ 699 nchanges = 0; 700 LIST_FOREACH(fio, &pu->pu_ios, fio_entries) { 701 if (fio->stat & FIO_WRGONE) 702 continue; 703 704 /* en/disable write checks for kqueue as needed */ 705 assert((FIO_EN_WRITE(fio) && FIO_RM_WRITE(fio)) == 0); 706 if (FIO_EN_WRITE(fio)) { 707 EV_SET(&pu->pu_evs[nchanges], fio->io_fd, 708 EVFILT_WRITE, EV_ENABLE, 0, 0, 709 (uintptr_t)fio); 710 fio->stat |= FIO_WR; 711 nchanges++; 712 } 713 if (FIO_RM_WRITE(fio)) { 714 EV_SET(&pu->pu_evs[nchanges], fio->io_fd, 715 EVFILT_WRITE, EV_DISABLE, 0, 0, 716 (uintptr_t)fio); 717 fio->stat &= ~FIO_WR; 718 nchanges++; 719 } 720 assert(nchanges <= pu->pu_nfds); 721 } 722 723 ndone = kevent(pu->pu_kq, pu->pu_evs, nchanges, 724 pu->pu_evs, 2*pu->pu_nfds, pu->pu_ml_timep); 725 726 if (ndone == -1) { 727 if (errno != EINTR) 728 goto out; 729 else 730 continue; 731 } 732 733 /* uoptimize */ 734 if (ndone == 0) 735 continue; 736 737 /* iterate over the results */ 738 for (curev = pu->pu_evs; ndone--; curev++) { 739 int what; 740 741 #if 0 742 /* get & possibly dispatch events from kernel */ 743 if (curev->ident == puffsfd) { 744 if (puffs_req_handle(pgr, ppr, 0) == -1) 745 goto out; 746 continue; 747 } 748 #endif 749 750 fio = (void *)curev->udata; 751 pfctrl = fio->fctrl; 752 if (curev->flags & EV_ERROR) { 753 assert(curev->filter == EVFILT_WRITE); 754 fio->stat &= ~FIO_WR; 755 756 /* XXX: how to know if it's a transient error */ 757 puffs_framev_writeclose(pu, fio, 758 (int)curev->data); 759 puffs_framev_notify(fio, PUFFS_FBIO_ERROR); 760 continue; 761 } 762 763 what = 0; 764 if (curev->filter == EVFILT_READ) { 765 puffs_framev_input(pu, pfctrl, fio); 766 what |= PUFFS_FBIO_READ; 767 } 768 769 else if (curev->filter == EVFILT_WRITE) { 770 puffs_framev_output(pu, pfctrl, fio); 771 what |= PUFFS_FBIO_WRITE; 772 } 773 if (what) 774 puffs_framev_notify(fio, what); 775 } 776 777 /* 778 * Schedule continuations. 779 */ 780 while ((pcc = TAILQ_FIRST(&pu->pu_sched)) != NULL) { 781 TAILQ_REMOVE(&pu->pu_sched, pcc, entries); 782 puffs_goto(pcc); 783 } 784 785 /* 786 * Really free fd's now that we don't have references 787 * to them. 788 */ 789 while ((fio = LIST_FIRST(&pu->pu_ios_rmlist)) != NULL) { 790 LIST_REMOVE(fio, fio_entries); 791 free(fio); 792 } 793 } 794 finalpush(pu); 795 errno = 0; 796 797 out: 798 /* store the real error for a while */ 799 sverrno = errno; 800 801 errno = sverrno; 802 if (errno) 803 return -1; 804 else 805 return 0; 806 } 807