1 /* $NetBSD: puffs.c,v 1.117 2011/11/14 01:27:42 chs 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.117 2011/11/14 01:27:42 chs 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 #ifndef __minix 47 #include <pthread.h> 48 #endif /* !__minix */ 49 #include <puffs.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <syslog.h> 54 #include <unistd.h> 55 56 #include "puffs_priv.h" 57 58 /* Most file systems want this for opts, so just give it to them */ 59 const struct mntopt puffsmopts[] = { 60 MOPT_STDOPTS, 61 PUFFSMOPT_STD, 62 MOPT_NULL, 63 }; 64 65 #ifndef __minix 66 pthread_mutex_t pu_lock = PTHREAD_MUTEX_INITIALIZER; 67 #endif /* !__minix */ 68 69 #define FILLOP(lower, upper) \ 70 do { \ 71 if (pops->puffs_node_##lower) \ 72 opmask[PUFFS_VN_##upper] = 1; \ 73 } while (/*CONSTCOND*/0) 74 static void 75 fillvnopmask(struct puffs_ops *pops, struct puffs_kargs *pa) 76 { 77 uint8_t *opmask = pa->pa_vnopmask; 78 79 memset(opmask, 0, sizeof(pa->pa_vnopmask)); 80 81 FILLOP(create, CREATE); 82 FILLOP(mknod, MKNOD); 83 FILLOP(open, OPEN); 84 FILLOP(close, CLOSE); 85 FILLOP(access, ACCESS); 86 FILLOP(getattr, GETATTR); 87 FILLOP(setattr, SETATTR); 88 FILLOP(poll, POLL); 89 FILLOP(mmap, MMAP); 90 FILLOP(fsync, FSYNC); 91 FILLOP(seek, SEEK); 92 FILLOP(remove, REMOVE); 93 FILLOP(link, LINK); 94 FILLOP(rename, RENAME); 95 FILLOP(mkdir, MKDIR); 96 FILLOP(rmdir, RMDIR); 97 FILLOP(symlink, SYMLINK); 98 FILLOP(readdir, READDIR); 99 FILLOP(readlink, READLINK); 100 FILLOP(reclaim, RECLAIM); 101 FILLOP(inactive, INACTIVE); 102 FILLOP(print, PRINT); 103 FILLOP(read, READ); 104 FILLOP(write, WRITE); 105 FILLOP(advlock, ADVLOCK); 106 FILLOP(abortop, ABORTOP); 107 FILLOP(pathconf, PATHCONF); 108 109 FILLOP(getextattr, GETEXTATTR); 110 FILLOP(setextattr, SETEXTATTR); 111 FILLOP(listextattr, LISTEXTATTR); 112 FILLOP(deleteextattr, DELETEEXTATTR); 113 } 114 #undef FILLOP 115 116 /* 117 * Go over all framev entries and write everything we can. This is 118 * mostly for the benefit of delivering "unmount" to the kernel. 119 */ 120 static void 121 finalpush(struct puffs_usermount *pu) 122 { 123 #ifndef __minix 124 struct puffs_fctrl_io *fio; 125 126 LIST_FOREACH(fio, &pu->pu_ios, fio_entries) { 127 if (fio->stat & FIO_WRGONE) 128 continue; 129 130 puffs__framev_output(pu, fio->fctrl, fio); 131 } 132 #endif /* !__minix */ 133 } 134 135 /*ARGSUSED*/ 136 void 137 puffs_kernerr_abort(struct puffs_usermount *pu, uint8_t type, 138 int error, const char *str, puffs_cookie_t cookie) 139 { 140 141 #ifndef __minix 142 fprintf(stderr, "abort: type %d, error %d, cookie %p (%s)\n", 143 #else /* __minix */ 144 lpuffs_debug("abort: type %d, error %d, cookie %p (%s)\n", 145 #endif /* __minix */ 146 type, error, cookie, str); 147 abort(); 148 } 149 150 /*ARGSUSED*/ 151 void 152 puffs_kernerr_log(struct puffs_usermount *pu, uint8_t type, 153 int error, const char *str, puffs_cookie_t cookie) 154 { 155 156 syslog(LOG_WARNING, "kernel: type %d, error %d, cookie %p (%s)\n", 157 type, error, cookie, str); 158 } 159 160 #ifndef __minix 161 int 162 puffs_getselectable(struct puffs_usermount *pu) 163 { 164 165 return pu->pu_fd; 166 } 167 168 uint64_t 169 puffs__nextreq(struct puffs_usermount *pu) 170 { 171 uint64_t rv; 172 173 PU_LOCK(); 174 rv = pu->pu_nextreq++ | (uint64_t)1<<63; 175 PU_UNLOCK(); 176 177 return rv; 178 } 179 180 int 181 puffs_setblockingmode(struct puffs_usermount *pu, int mode) 182 { 183 int rv, x; 184 185 assert(puffs_getstate(pu) == PUFFS_STATE_RUNNING); 186 187 if (mode != PUFFSDEV_BLOCK && mode != PUFFSDEV_NONBLOCK) { 188 errno = EINVAL; 189 return -1; 190 } 191 192 x = mode; 193 rv = ioctl(pu->pu_fd, FIONBIO, &x); 194 195 if (rv == 0) { 196 if (mode == PUFFSDEV_BLOCK) 197 pu->pu_state &= ~PU_ASYNCFD; 198 else 199 pu->pu_state |= PU_ASYNCFD; 200 } 201 202 return rv; 203 } 204 #endif /* !__minix */ 205 206 int 207 puffs_getstate(struct puffs_usermount *pu) 208 { 209 210 return pu->pu_state & PU_STATEMASK; 211 } 212 213 void 214 puffs_setstacksize(struct puffs_usermount *pu, size_t ss) 215 { 216 long psize, minsize; 217 int stackshift; 218 int bonus; 219 220 assert(puffs_getstate(pu) == PUFFS_STATE_BEFOREMOUNT); 221 222 psize = sysconf(_SC_PAGESIZE); 223 minsize = 4*psize; 224 if (ss < (size_t)minsize || ss == PUFFS_STACKSIZE_MIN) { 225 if (ss != PUFFS_STACKSIZE_MIN) 226 #ifndef __minix 227 fprintf(stderr, "puffs_setstacksize: adjusting " 228 "stacksize to minimum %ld\n", minsize); 229 #endif /* !__minix */ 230 ss = 4*psize; 231 } 232 233 stackshift = -1; 234 bonus = 0; 235 while (ss) { 236 if (ss & 0x1) 237 bonus++; 238 ss >>= 1; 239 stackshift++; 240 } 241 if (bonus > 1) { 242 stackshift++; 243 #ifndef __minix 244 fprintf(stderr, "puffs_setstacksize: using next power of two: " 245 "%d\n", 1<<stackshift); 246 #endif /* !__minix */ 247 } 248 249 pu->pu_cc_stackshift = stackshift; 250 } 251 252 struct puffs_pathobj * 253 puffs_getrootpathobj(struct puffs_usermount *pu) 254 { 255 struct puffs_node *pnr; 256 257 pnr = pu->pu_pn_root; 258 if (pnr == NULL) { 259 errno = ENOENT; 260 return NULL; 261 } 262 263 return &pnr->pn_po; 264 } 265 266 void 267 puffs_setroot(struct puffs_usermount *pu, struct puffs_node *pn) 268 { 269 270 pu->pu_pn_root = pn; 271 } 272 273 struct puffs_node * 274 puffs_getroot(struct puffs_usermount *pu) 275 { 276 277 return pu->pu_pn_root; 278 } 279 280 void 281 puffs_setrootinfo(struct puffs_usermount *pu, enum vtype vt, 282 vsize_t vsize, dev_t rdev) 283 { 284 struct puffs_kargs *pargs = pu->pu_kargp; 285 286 if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT) { 287 warnx("puffs_setrootinfo: call has effect only " 288 "before mount\n"); 289 return; 290 } 291 292 pargs->pa_root_vtype = vt; 293 pargs->pa_root_vsize = vsize; 294 pargs->pa_root_rdev = rdev; 295 } 296 297 void * 298 puffs_getspecific(struct puffs_usermount *pu) 299 { 300 301 return pu->pu_privdata; 302 } 303 304 void 305 puffs_setspecific(struct puffs_usermount *pu, void *privdata) 306 { 307 308 pu->pu_privdata = privdata; 309 } 310 311 void 312 puffs_setmntinfo(struct puffs_usermount *pu, 313 const char *mntfromname, const char *puffsname) 314 { 315 struct puffs_kargs *pargs = pu->pu_kargp; 316 317 (void)strlcpy(pargs->pa_mntfromname, mntfromname, 318 sizeof(pargs->pa_mntfromname)); 319 (void)strlcpy(pargs->pa_typename, puffsname, 320 sizeof(pargs->pa_typename)); 321 } 322 323 size_t 324 puffs_getmaxreqlen(struct puffs_usermount *pu) 325 { 326 327 return pu->pu_maxreqlen; 328 } 329 330 void 331 puffs_setmaxreqlen(struct puffs_usermount *pu, size_t reqlen) 332 { 333 334 if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT) 335 warnx("puffs_setmaxreqlen: call has effect only " 336 "before mount\n"); 337 338 pu->pu_kargp->pa_maxmsglen = reqlen; 339 } 340 341 void 342 puffs_setfhsize(struct puffs_usermount *pu, size_t fhsize, int flags) 343 { 344 345 if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT) 346 warnx("puffs_setfhsize: call has effect only before mount\n"); 347 348 pu->pu_kargp->pa_fhsize = fhsize; 349 pu->pu_kargp->pa_fhflags = flags; 350 } 351 352 void 353 puffs_setncookiehash(struct puffs_usermount *pu, int nhash) 354 { 355 356 if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT) 357 warnx("puffs_setfhsize: call has effect only before mount\n"); 358 359 pu->pu_kargp->pa_nhashbuckets = nhash; 360 } 361 362 void 363 puffs_set_pathbuild(struct puffs_usermount *pu, pu_pathbuild_fn fn) 364 { 365 366 pu->pu_pathbuild = fn; 367 } 368 369 void 370 puffs_set_pathtransform(struct puffs_usermount *pu, pu_pathtransform_fn fn) 371 { 372 373 pu->pu_pathtransform = fn; 374 } 375 376 void 377 puffs_set_pathcmp(struct puffs_usermount *pu, pu_pathcmp_fn fn) 378 { 379 380 pu->pu_pathcmp = fn; 381 } 382 383 void 384 puffs_set_pathfree(struct puffs_usermount *pu, pu_pathfree_fn fn) 385 { 386 387 pu->pu_pathfree = fn; 388 } 389 390 void 391 puffs_set_namemod(struct puffs_usermount *pu, pu_namemod_fn fn) 392 { 393 394 pu->pu_namemod = fn; 395 } 396 397 void 398 puffs_set_errnotify(struct puffs_usermount *pu, pu_errnotify_fn fn) 399 { 400 401 pu->pu_errnotify = fn; 402 } 403 404 void 405 puffs_set_cmap(struct puffs_usermount *pu, pu_cmap_fn fn) 406 { 407 408 pu->pu_cmap = fn; 409 } 410 411 void 412 puffs_ml_setloopfn(struct puffs_usermount *pu, puffs_ml_loop_fn lfn) 413 { 414 415 pu->pu_ml_lfn = lfn; 416 } 417 418 void 419 puffs_ml_settimeout(struct puffs_usermount *pu, struct timespec *ts) 420 { 421 422 if (ts == NULL) { 423 pu->pu_ml_timep = NULL; 424 } else { 425 pu->pu_ml_timeout = *ts; 426 pu->pu_ml_timep = &pu->pu_ml_timeout; 427 } 428 } 429 430 void 431 puffs_set_prepost(struct puffs_usermount *pu, 432 pu_prepost_fn pre, pu_prepost_fn pst) 433 { 434 435 pu->pu_oppre = pre; 436 pu->pu_oppost = pst; 437 } 438 439 #ifndef __minix 440 void 441 puffs_setback(struct puffs_cc *pcc, int whatback) 442 { 443 struct puffs_req *preq = puffs__framebuf_getdataptr(pcc->pcc_pb); 444 445 assert(PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN && ( 446 preq->preq_optype == PUFFS_VN_OPEN || 447 preq->preq_optype == PUFFS_VN_MMAP || 448 preq->preq_optype == PUFFS_VN_REMOVE || 449 preq->preq_optype == PUFFS_VN_RMDIR || 450 preq->preq_optype == PUFFS_VN_INACTIVE)); 451 452 preq->preq_setbacks |= whatback & PUFFS_SETBACK_MASK; 453 } 454 455 int 456 puffs_daemon(struct puffs_usermount *pu, int nochdir, int noclose) 457 { 458 long int n; 459 int parent, value, fd; 460 461 if (pipe(pu->pu_dpipe) == -1) 462 return -1; 463 464 switch (fork()) { 465 case -1: 466 return -1; 467 case 0: 468 parent = 0; 469 break; 470 default: 471 parent = 1; 472 break; 473 } 474 pu->pu_state |= PU_PUFFSDAEMON; 475 476 if (parent) { 477 close(pu->pu_dpipe[1]); 478 n = read(pu->pu_dpipe[0], &value, sizeof(int)); 479 if (n == -1) 480 err(1, "puffs_daemon"); 481 if (n != sizeof(value)) 482 errx(1, "puffs_daemon got %ld bytes", n); 483 if (value) { 484 errno = value; 485 err(1, "puffs_daemon"); 486 } 487 exit(0); 488 } else { 489 if (setsid() == -1) 490 goto fail; 491 492 if (!nochdir) 493 chdir("/"); 494 495 if (!noclose) { 496 fd = open(_PATH_DEVNULL, O_RDWR, 0); 497 if (fd == -1) 498 goto fail; 499 dup2(fd, STDIN_FILENO); 500 dup2(fd, STDOUT_FILENO); 501 dup2(fd, STDERR_FILENO); 502 if (fd > STDERR_FILENO) 503 close(fd); 504 } 505 return 0; 506 } 507 508 fail: 509 n = write(pu->pu_dpipe[1], &errno, sizeof(int)); 510 assert(n == 4); 511 return -1; 512 } 513 #endif /* !__minix */ 514 515 static void 516 shutdaemon(struct puffs_usermount *pu, int error) 517 { 518 #ifndef __minix 519 ssize_t n; 520 521 n = write(pu->pu_dpipe[1], &error, sizeof(int)); 522 assert(n == 4); 523 close(pu->pu_dpipe[0]); 524 close(pu->pu_dpipe[1]); 525 #endif /* !__minix */ 526 pu->pu_state &= ~PU_PUFFSDAEMON; 527 } 528 529 int 530 puffs_mount(struct puffs_usermount *pu, const char *dir, int mntflags, 531 puffs_cookie_t cookie) 532 { 533 #ifndef __minix 534 int rv, fd, sverrno; 535 char *comfd; 536 #endif /* !__minix */ 537 538 pu->pu_kargp->pa_root_cookie = cookie; 539 540 #ifndef __minix 541 /* XXXkludgehere */ 542 /* kauth doesn't provide this service any longer */ 543 if (geteuid() != 0) 544 mntflags |= MNT_NOSUID | MNT_NODEV; 545 546 /* 547 * Undocumented... Well, documented only here. 548 * 549 * This is used for imaginative purposes. If the env variable is 550 * set, puffs_mount() doesn't do the regular mount procedure. 551 * Rather, it crams the mount data down the comfd and sets comfd as 552 * the puffs descriptor. 553 * 554 * This shouldn't be used unless you can read my mind ( ... or write 555 * it, not to mention execute it, but that's starting to get silly). 556 */ 557 if ((comfd = getenv("PUFFS_COMFD")) != NULL) { 558 size_t len; 559 560 if (sscanf(comfd, "%d", &pu->pu_fd) != 1) { 561 errno = EINVAL; 562 rv = -1; 563 goto out; 564 } 565 /* check that what we got at least resembles an fd */ 566 if (fcntl(pu->pu_fd, F_GETFL) == -1) { 567 rv = -1; 568 goto out; 569 } 570 571 #define allwrite(buf, len) \ 572 do { \ 573 ssize_t al_rv; \ 574 al_rv = write(pu->pu_fd, buf, len); \ 575 if ((size_t)al_rv != len) { \ 576 if (al_rv != -1) \ 577 errno = EIO; \ 578 rv = -1; \ 579 goto out; \ 580 } \ 581 } while (/*CONSTCOND*/0) 582 len = strlen(dir)+1; 583 allwrite(&len, sizeof(len)); 584 allwrite(dir, len); 585 len = strlen(pu->pu_kargp->pa_mntfromname)+1; 586 allwrite(&len, sizeof(len)); 587 allwrite(pu->pu_kargp->pa_mntfromname, len); 588 allwrite(&mntflags, sizeof(mntflags)); 589 len = sizeof(*pu->pu_kargp); 590 allwrite(&len, sizeof(len)); 591 allwrite(pu->pu_kargp, sizeof(*pu->pu_kargp)); 592 allwrite(&pu->pu_flags, sizeof(pu->pu_flags)); 593 #undef allwrite 594 595 rv = 0; 596 } else { 597 char rp[MAXPATHLEN]; 598 599 if (realpath(dir, rp) == NULL) { 600 rv = -1; 601 goto out; 602 } 603 604 if (strcmp(dir, rp) != 0) { 605 warnx("puffs_mount: \"%s\" is a relative path.", dir); 606 warnx("puffs_mount: using \"%s\" instead.", rp); 607 } 608 609 fd = open(_PATH_PUFFS, O_RDWR); 610 if (fd == -1) { 611 warnx("puffs_mount: cannot open %s", _PATH_PUFFS); 612 rv = -1; 613 goto out; 614 } 615 if (fd <= 2) 616 warnx("puffs_mount: device fd %d (<= 2), sure this is " 617 "what you want?", fd); 618 619 pu->pu_kargp->pa_fd = pu->pu_fd = fd; 620 if ((rv = mount(MOUNT_PUFFS, rp, mntflags, 621 pu->pu_kargp, sizeof(struct puffs_kargs))) == -1) 622 goto out; 623 } 624 #else /* __minix */ 625 /* Process the already-received mount request. */ 626 if (!lpuffs_pump()) { 627 /* Not mounted? This should never happen.. */ 628 free(pu->pu_kargp); 629 pu->pu_kargp = NULL; 630 errno = EINVAL; 631 return -1; 632 } 633 #endif /* __minix */ 634 635 PU_SETSTATE(pu, PUFFS_STATE_RUNNING); 636 637 #ifndef __minix 638 out: 639 if (rv != 0) 640 sverrno = errno; 641 else 642 sverrno = 0; 643 free(pu->pu_kargp); 644 pu->pu_kargp = NULL; 645 646 if (pu->pu_state & PU_PUFFSDAEMON) 647 shutdaemon(pu, sverrno); 648 649 errno = sverrno; 650 return rv; 651 #else /* __minix */ 652 return 0; 653 #endif /* __minix */ 654 } 655 656 struct puffs_usermount * 657 puffs_init(struct puffs_ops *pops, const char *mntfromname, 658 const char *puffsname, void *priv, uint32_t pflags) 659 { 660 struct puffs_usermount *pu; 661 struct puffs_kargs *pargs; 662 int sverrno; 663 664 if (puffsname == PUFFS_DEFER) 665 puffsname = "n/a"; 666 if (mntfromname == PUFFS_DEFER) 667 mntfromname = "n/a"; 668 if (priv == PUFFS_DEFER) 669 priv = NULL; 670 671 pu = malloc(sizeof(struct puffs_usermount)); 672 if (pu == NULL) 673 goto failfree; 674 memset(pu, 0, sizeof(struct puffs_usermount)); 675 676 pargs = pu->pu_kargp = malloc(sizeof(struct puffs_kargs)); 677 if (pargs == NULL) 678 goto failfree; 679 memset(pargs, 0, sizeof(struct puffs_kargs)); 680 681 pargs->pa_vers = PUFFSVERSION; 682 pargs->pa_flags = PUFFS_FLAG_KERN(pflags); 683 fillvnopmask(pops, pargs); 684 puffs_setmntinfo(pu, mntfromname, puffsname); 685 686 puffs_zerostatvfs(&pargs->pa_svfsb); 687 pargs->pa_root_cookie = NULL; 688 pargs->pa_root_vtype = VDIR; 689 pargs->pa_root_vsize = 0; 690 pargs->pa_root_rdev = 0; 691 pargs->pa_maxmsglen = 0; 692 if (/*CONSTCOND*/ sizeof(time_t) == 4) 693 pargs->pa_time32 = 1; 694 else 695 pargs->pa_time32 = 0; 696 697 pu->pu_flags = pflags; 698 pu->pu_ops = *pops; 699 free(pops); /* XXX */ 700 701 pu->pu_privdata = priv; 702 pu->pu_cc_stackshift = PUFFS_CC_STACKSHIFT_DEFAULT; 703 LIST_INIT(&pu->pu_pnodelst); 704 LIST_INIT(&pu->pu_ios); 705 LIST_INIT(&pu->pu_ios_rmlist); 706 LIST_INIT(&pu->pu_ccmagazin); 707 TAILQ_INIT(&pu->pu_sched); 708 709 #ifndef __minix 710 pu->pu_framectrl[PU_FRAMECTRL_FS].rfb = puffs__fsframe_read; 711 pu->pu_framectrl[PU_FRAMECTRL_FS].wfb = puffs__fsframe_write; 712 pu->pu_framectrl[PU_FRAMECTRL_FS].cmpfb = puffs__fsframe_cmp; 713 pu->pu_framectrl[PU_FRAMECTRL_FS].gotfb = puffs__fsframe_gotframe; 714 pu->pu_framectrl[PU_FRAMECTRL_FS].fdnotfn = puffs_framev_unmountonclose; 715 #endif /* !__minix */ 716 717 /* defaults for some user-settable translation functions */ 718 pu->pu_cmap = NULL; /* identity translation */ 719 720 pu->pu_pathbuild = puffs_stdpath_buildpath; 721 pu->pu_pathfree = puffs_stdpath_freepath; 722 pu->pu_pathcmp = puffs_stdpath_cmppath; 723 pu->pu_pathtransform = NULL; 724 pu->pu_namemod = NULL; 725 726 pu->pu_errnotify = puffs_kernerr_log; 727 728 PU_SETSTATE(pu, PUFFS_STATE_BEFOREMOUNT); 729 730 #ifdef __minix 731 /* Do the MINIX3-specific side of the initialization. */ 732 lpuffs_init(pu); 733 #endif /* __minix */ 734 735 return pu; 736 737 failfree: 738 /* can't unmount() from here for obvious reasons */ 739 sverrno = errno; 740 free(pu); 741 errno = sverrno; 742 return NULL; 743 } 744 745 void 746 puffs_cancel(struct puffs_usermount *pu, int error) 747 { 748 749 assert(puffs_getstate(pu) < PUFFS_STATE_RUNNING); 750 shutdaemon(pu, error); 751 free(pu); 752 } 753 754 /*ARGSUSED1*/ 755 int 756 puffs_exit(struct puffs_usermount *pu, int unused /* strict compat */) 757 { 758 #ifndef __minix 759 struct puffs_framebuf *pb; 760 struct puffs_req *preq; 761 void *winp; 762 size_t winlen; 763 int sverrno; 764 765 pb = puffs_framebuf_make(); 766 if (pb == NULL) { 767 errno = ENOMEM; 768 return -1; 769 } 770 771 winlen = sizeof(struct puffs_req); 772 if (puffs_framebuf_getwindow(pb, 0, &winp, &winlen) == -1) { 773 sverrno = errno; 774 puffs_framebuf_destroy(pb); 775 errno = sverrno; 776 return -1; 777 } 778 preq = winp; 779 780 preq->preq_buflen = sizeof(struct puffs_req); 781 preq->preq_opclass = PUFFSOP_UNMOUNT; 782 preq->preq_id = puffs__nextreq(pu); 783 784 puffs_framev_enqueue_justsend(pu, puffs_getselectable(pu), pb, 1, 0); 785 #else /* __minix */ 786 struct puffs_node *pn; 787 788 lpuffs_debug("puffs_exit\n"); 789 790 while ((pn = LIST_FIRST(&pu->pu_pnodelst)) != NULL) 791 puffs_pn_put(pn); 792 793 while ((pn = LIST_FIRST(&pu->pu_pnode_removed_lst)) != NULL) 794 puffs_pn_put(pn); 795 796 puffs__cc_exit(pu); 797 if (pu->pu_state & PU_HASKQ) 798 close(pu->pu_kq); 799 free(pu); 800 #endif /* __minix */ 801 802 return 0; 803 } 804 805 #ifndef __minix 806 /* no sigset_t static intializer */ 807 static int sigs[NSIG] = { 0, }; 808 static int sigcatch = 0; 809 810 int 811 puffs_unmountonsignal(int sig, bool sigignore) 812 { 813 814 if (sig < 0 || sig >= (int)NSIG) { 815 errno = EINVAL; 816 return -1; 817 } 818 if (sigignore) 819 if (signal(sig, SIG_IGN) == SIG_ERR) 820 return -1; 821 822 if (!sigs[sig]) 823 sigcatch++; 824 sigs[sig] = 1; 825 826 return 0; 827 } 828 #endif /* !__minix */ 829 830 /* 831 * Actual mainloop. This is called from a context which can block. 832 * It is called either from puffs_mainloop (indirectly, via 833 * puffs_cc_continue() or from puffs_cc_yield()). 834 */ 835 void 836 puffs__theloop(struct puffs_cc *pcc) 837 { 838 struct puffs_usermount *pu = pcc->pcc_pu; 839 #ifndef __minix 840 struct puffs_framectrl *pfctrl; 841 struct puffs_fctrl_io *fio; 842 struct kevent *curev; 843 size_t nchanges; 844 int ndone; 845 #endif /* !__minix */ 846 847 #ifndef __minix 848 while (puffs_getstate(pu) != PUFFS_STATE_UNMOUNTED) { 849 #else /* __minix */ 850 do { 851 #endif /* __minix */ 852 853 /* 854 * Schedule existing requests. 855 */ 856 while ((pcc = TAILQ_FIRST(&pu->pu_sched)) != NULL) { 857 TAILQ_REMOVE(&pu->pu_sched, pcc, pcc_schedent); 858 puffs__goto(pcc); 859 } 860 861 if (pu->pu_ml_lfn) 862 pu->pu_ml_lfn(pu); 863 864 #ifndef __minix 865 /* XXX: can we still do these optimizations? */ 866 #if 0 867 /* 868 * Do this here, because: 869 * a) loopfunc might generate some results 870 * b) it's still "after" event handling (except for round 1) 871 */ 872 if (puffs_req_putput(ppr) == -1) 873 goto out; 874 puffs_req_resetput(ppr); 875 876 /* micro optimization: skip kevent syscall if possible */ 877 if (pu->pu_nfds == 1 && pu->pu_ml_timep == NULL 878 && (pu->pu_state & PU_ASYNCFD) == 0) { 879 pfctrl = XXX->fctrl; 880 puffs_framev_input(pu, pfctrl, XXX); 881 continue; 882 } 883 #endif 884 885 /* else: do full processing */ 886 /* Don't bother worrying about O(n) for now */ 887 LIST_FOREACH(fio, &pu->pu_ios, fio_entries) { 888 if (fio->stat & FIO_WRGONE) 889 continue; 890 891 pfctrl = fio->fctrl; 892 893 /* 894 * Try to write out everything to avoid the 895 * need for enabling EVFILT_WRITE. The likely 896 * case is that we can fit everything into the 897 * socket buffer. 898 */ 899 puffs__framev_output(pu, pfctrl, fio); 900 } 901 902 /* 903 * Build list of which to enable/disable in writecheck. 904 */ 905 nchanges = 0; 906 LIST_FOREACH(fio, &pu->pu_ios, fio_entries) { 907 if (fio->stat & FIO_WRGONE) 908 continue; 909 910 /* en/disable write checks for kqueue as needed */ 911 assert((FIO_EN_WRITE(fio) && FIO_RM_WRITE(fio)) == 0); 912 if (FIO_EN_WRITE(fio)) { 913 EV_SET(&pu->pu_evs[nchanges], fio->io_fd, 914 EVFILT_WRITE, EV_ENABLE, 0, 0, 915 (uintptr_t)fio); 916 fio->stat |= FIO_WR; 917 nchanges++; 918 } 919 if (FIO_RM_WRITE(fio)) { 920 EV_SET(&pu->pu_evs[nchanges], fio->io_fd, 921 EVFILT_WRITE, EV_DISABLE, 0, 0, 922 (uintptr_t)fio); 923 fio->stat &= ~FIO_WR; 924 nchanges++; 925 } 926 } 927 928 ndone = kevent(pu->pu_kq, pu->pu_evs, nchanges, 929 pu->pu_evs, pu->pu_nevs, pu->pu_ml_timep); 930 931 if (ndone == -1) { 932 if (errno != EINTR) 933 break; 934 else 935 continue; 936 } 937 938 /* uoptimize */ 939 if (ndone == 0) 940 continue; 941 942 /* iterate over the results */ 943 for (curev = pu->pu_evs; ndone--; curev++) { 944 int what; 945 946 #if 0 947 /* get & possibly dispatch events from kernel */ 948 if (curev->ident == puffsfd) { 949 if (puffs_req_handle(pgr, ppr, 0) == -1) 950 goto out; 951 continue; 952 } 953 #endif 954 955 fio = (void *)curev->udata; 956 if (__predict_true(fio)) 957 pfctrl = fio->fctrl; 958 else 959 pfctrl = NULL; 960 if (curev->flags & EV_ERROR) { 961 assert(curev->filter == EVFILT_WRITE); 962 fio->stat &= ~FIO_WR; 963 964 /* XXX: how to know if it's a transient error */ 965 puffs__framev_writeclose(pu, fio, 966 (int)curev->data); 967 puffs__framev_notify(fio, PUFFS_FBIO_ERROR); 968 continue; 969 } 970 971 what = 0; 972 if (curev->filter == EVFILT_READ) { 973 puffs__framev_input(pu, pfctrl, fio); 974 what |= PUFFS_FBIO_READ; 975 } 976 977 else if (curev->filter == EVFILT_WRITE) { 978 puffs__framev_output(pu, pfctrl, fio); 979 what |= PUFFS_FBIO_WRITE; 980 } 981 982 else if (__predict_false(curev->filter==EVFILT_SIGNAL)){ 983 if ((pu->pu_state & PU_DONEXIT) == 0) { 984 PU_SETSFLAG(pu, PU_DONEXIT); 985 puffs_exit(pu, 0); 986 } 987 } 988 if (what) 989 puffs__framev_notify(fio, what); 990 } 991 992 /* 993 * Really free fd's now that we don't have references 994 * to them. 995 */ 996 while ((fio = LIST_FIRST(&pu->pu_ios_rmlist)) != NULL) { 997 LIST_REMOVE(fio, fio_entries); 998 free(fio); 999 } 1000 #endif /* !__minix */ 1001 } 1002 #ifdef __minix 1003 while (lpuffs_pump()); 1004 #endif /* __minix */ 1005 1006 if (puffs__cc_restoremain(pu) == -1) 1007 warn("cannot restore main context. impending doom"); 1008 } 1009 int 1010 puffs_mainloop(struct puffs_usermount *pu) 1011 { 1012 #ifndef __minix 1013 struct puffs_fctrl_io *fio; 1014 #endif /* !__minix */ 1015 struct puffs_cc *pcc; 1016 #ifndef __minix 1017 struct kevent *curev; 1018 size_t nevs; 1019 int sverrno, i; 1020 #else /* __minix */ 1021 int sverrno; 1022 #endif /* !__minix */ 1023 1024 assert(puffs_getstate(pu) >= PUFFS_STATE_RUNNING); 1025 1026 #ifndef __minix 1027 pu->pu_kq = kqueue(); 1028 if (pu->pu_kq == -1) 1029 goto out; 1030 #endif /* !__minix */ 1031 pu->pu_state |= PU_HASKQ; 1032 1033 #ifndef __minix 1034 puffs_setblockingmode(pu, PUFFSDEV_NONBLOCK); 1035 if (puffs__framev_addfd_ctrl(pu, puffs_getselectable(pu), 1036 PUFFS_FBIO_READ | PUFFS_FBIO_WRITE, 1037 &pu->pu_framectrl[PU_FRAMECTRL_FS]) == -1) 1038 goto out; 1039 1040 nevs = pu->pu_nevs + sigcatch; 1041 curev = realloc(pu->pu_evs, nevs * sizeof(struct kevent)); 1042 if (curev == NULL) 1043 goto out; 1044 pu->pu_evs = curev; 1045 pu->pu_nevs = nevs; 1046 1047 LIST_FOREACH(fio, &pu->pu_ios, fio_entries) { 1048 EV_SET(curev, fio->io_fd, EVFILT_READ, EV_ADD, 1049 0, 0, (uintptr_t)fio); 1050 curev++; 1051 EV_SET(curev, fio->io_fd, EVFILT_WRITE, EV_ADD | EV_DISABLE, 1052 0, 0, (uintptr_t)fio); 1053 curev++; 1054 } 1055 for (i = 0; i < NSIG; i++) { 1056 if (sigs[i]) { 1057 EV_SET(curev, i, EVFILT_SIGNAL, EV_ADD | EV_ENABLE, 1058 0, 0, 0); 1059 curev++; 1060 } 1061 } 1062 assert(curev - pu->pu_evs == (ssize_t)pu->pu_nevs); 1063 if (kevent(pu->pu_kq, pu->pu_evs, pu->pu_nevs, NULL, 0, NULL) == -1) 1064 goto out; 1065 #endif /* !__minix */ 1066 1067 pu->pu_state |= PU_INLOOP; 1068 1069 /* 1070 * Create alternate execution context and jump to it. Note 1071 * that we come "out" of savemain twice. Where we come out 1072 * of it depends on the architecture. If the return address is 1073 * stored on the stack, we jump out from puffs_cc_continue(), 1074 * for a register return address from puffs__cc_savemain(). 1075 * PU_MAINRESTORE makes sure we DTRT in both cases. 1076 */ 1077 if (puffs__cc_create(pu, puffs__theloop, &pcc) == -1) { 1078 goto out; 1079 } 1080 1081 #if 0 1082 if (puffs__cc_savemain(pu) == -1) { 1083 goto out; 1084 } 1085 #else 1086 /* 1087 * XXX 1088 * puffs__cc_savemain() uses getcontext() and then returns. 1089 * the caller (this function) may overwrite the stack frame 1090 * of puffs__cc_savemain(), so when we call setcontext() later and 1091 * return from puffs__cc_savemain() again, the return address or 1092 * saved stack pointer can be garbage. 1093 * avoid this by calling getcontext() directly here. 1094 */ 1095 extern int puffs_fakecc; 1096 if (!puffs_fakecc) { 1097 PU_CLRSFLAG(pu, PU_MAINRESTORE); 1098 if (getcontext(&pu->pu_mainctx) == -1) { 1099 goto out; 1100 } 1101 } 1102 #endif 1103 1104 if ((pu->pu_state & PU_MAINRESTORE) == 0) 1105 puffs_cc_continue(pcc); 1106 1107 finalpush(pu); 1108 errno = 0; 1109 1110 out: 1111 /* store the real error for a while */ 1112 sverrno = errno; 1113 1114 errno = sverrno; 1115 if (errno) 1116 return -1; 1117 else 1118 return 0; 1119 } 1120