Home | History | Annotate | Line # | Download | only in libpuffs
puffs.c revision 1.35
      1 /*	$NetBSD: puffs.c,v 1.35 2007/04/12 15:09:01 pooka Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2005, 2006  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  * 3. The name of the company nor the name of the author may be used to
     19  *    endorse or promote products derived from this software without specific
     20  *    prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     23  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     24  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     25  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     28  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  * SUCH DAMAGE.
     33  */
     34 
     35 #include <sys/cdefs.h>
     36 #if !defined(lint)
     37 __RCSID("$NetBSD: puffs.c,v 1.35 2007/04/12 15:09:01 pooka Exp $");
     38 #endif /* !lint */
     39 
     40 #include <sys/param.h>
     41 #include <sys/mount.h>
     42 
     43 #include <assert.h>
     44 #include <err.h>
     45 #include <errno.h>
     46 #include <fcntl.h>
     47 #include <mntopts.h>
     48 #include <puffs.h>
     49 #include <puffsdump.h>
     50 #include <stdarg.h>
     51 #include <stdio.h>
     52 #include <stdlib.h>
     53 #include <string.h>
     54 #include <syslog.h>
     55 #include <unistd.h>
     56 
     57 #include "puffs_priv.h"
     58 
     59 /* Most file systems want this for opts, so just give it to them */
     60 const struct mntopt puffsmopts[] = {
     61 	MOPT_STDOPTS,
     62 	PUFFSMOPT_STD,
     63 	MOPT_NULL,
     64 };
     65 
     66 #define FILLOP(lower, upper)						\
     67 do {									\
     68 	if (pops->puffs_node_##lower)					\
     69 		opmask[PUFFS_VN_##upper] = 1;				\
     70 } while (/*CONSTCOND*/0)
     71 static void
     72 fillvnopmask(struct puffs_ops *pops, uint8_t *opmask)
     73 {
     74 
     75 	memset(opmask, 0, PUFFS_VN_MAX);
     76 
     77 	FILLOP(create,   CREATE);
     78 	FILLOP(mknod,    MKNOD);
     79 	FILLOP(open,     OPEN);
     80 	FILLOP(close,    CLOSE);
     81 	FILLOP(access,   ACCESS);
     82 	FILLOP(getattr,  GETATTR);
     83 	FILLOP(setattr,  SETATTR);
     84 	FILLOP(poll,     POLL); /* XXX: not ready in kernel */
     85 	FILLOP(mmap,     MMAP);
     86 	FILLOP(fsync,    FSYNC);
     87 	FILLOP(seek,     SEEK);
     88 	FILLOP(remove,   REMOVE);
     89 	FILLOP(link,     LINK);
     90 	FILLOP(rename,   RENAME);
     91 	FILLOP(mkdir,    MKDIR);
     92 	FILLOP(rmdir,    RMDIR);
     93 	FILLOP(symlink,  SYMLINK);
     94 	FILLOP(readdir,  READDIR);
     95 	FILLOP(readlink, READLINK);
     96 	FILLOP(reclaim,  RECLAIM);
     97 	FILLOP(inactive, INACTIVE);
     98 	FILLOP(print,    PRINT);
     99 	FILLOP(read,     READ);
    100 	FILLOP(write,    WRITE);
    101 
    102 	/* XXX: not implemented in the kernel */
    103 	FILLOP(getextattr, GETEXTATTR);
    104 	FILLOP(setextattr, SETEXTATTR);
    105 	FILLOP(listextattr, LISTEXTATTR);
    106 }
    107 #undef FILLOP
    108 
    109 int
    110 puffs_getselectable(struct puffs_usermount *pu)
    111 {
    112 
    113 	return pu->pu_fd;
    114 }
    115 
    116 int
    117 puffs_setblockingmode(struct puffs_usermount *pu, int mode)
    118 {
    119 	int x;
    120 
    121 	x = mode;
    122 	return ioctl(pu->pu_fd, FIONBIO, &x);
    123 }
    124 
    125 int
    126 puffs_getstate(struct puffs_usermount *pu)
    127 {
    128 
    129 	return pu->pu_state;
    130 }
    131 
    132 void
    133 puffs_setstacksize(struct puffs_usermount *pu, size_t ss)
    134 {
    135 
    136 	pu->pu_cc_stacksize = ss;
    137 }
    138 
    139 struct puffs_pathobj *
    140 puffs_getrootpathobj(struct puffs_usermount *pu)
    141 {
    142 	struct puffs_node *pnr;
    143 
    144 	pnr = pu->pu_pn_root;
    145 	if (pnr == NULL) {
    146 		errno = ENOENT;
    147 		return NULL;
    148 	}
    149 
    150 	return &pnr->pn_po;
    151 }
    152 
    153 void
    154 puffs_setroot(struct puffs_usermount *pu, struct puffs_node *pn)
    155 {
    156 
    157 	pu->pu_pn_root = pn;
    158 }
    159 
    160 struct puffs_node *
    161 puffs_getroot(struct puffs_usermount *pu)
    162 {
    163 
    164 	return pu->pu_pn_root;
    165 }
    166 
    167 void *
    168 puffs_getspecific(struct puffs_usermount *pu)
    169 {
    170 
    171 	return pu->pu_privdata;
    172 }
    173 
    174 size_t
    175 puffs_getmaxreqlen(struct puffs_usermount *pu)
    176 {
    177 
    178 	return pu->pu_maxreqlen;
    179 }
    180 
    181 void
    182 puffs_set_pathbuild(struct puffs_usermount *pu, pu_pathbuild_fn fn)
    183 {
    184 
    185 	pu->pu_pathbuild = fn;
    186 }
    187 
    188 void
    189 puffs_set_pathtransform(struct puffs_usermount *pu, pu_pathtransform_fn fn)
    190 {
    191 
    192 	pu->pu_pathtransform = fn;
    193 }
    194 
    195 void
    196 puffs_set_pathcmp(struct puffs_usermount *pu, pu_pathcmp_fn fn)
    197 {
    198 
    199 	pu->pu_pathcmp = fn;
    200 }
    201 
    202 void
    203 puffs_set_pathfree(struct puffs_usermount *pu, pu_pathfree_fn fn)
    204 {
    205 
    206 	pu->pu_pathfree = fn;
    207 }
    208 
    209 void
    210 puffs_set_namemod(struct puffs_usermount *pu, pu_namemod_fn fn)
    211 {
    212 
    213 	pu->pu_namemod = fn;
    214 }
    215 
    216 enum {PUFFCALL_ANSWER, PUFFCALL_IGNORE, PUFFCALL_AGAIN};
    217 
    218 struct puffs_usermount *
    219 _puffs_mount(int develv, struct puffs_ops *pops, const char *dir, int mntflags,
    220 	const char *puffsname, void *priv, uint32_t pflags, size_t maxreqlen)
    221 {
    222 	struct puffs_args pargs;
    223 	struct puffs_usermount *pu;
    224 	int fd = 0;
    225 
    226 	if (develv != PUFFS_DEVEL_LIBVERSION) {
    227 		warnx("puffs_mount: mounting with lib version %d, need %d",
    228 		    develv, PUFFS_DEVEL_LIBVERSION);
    229 		errno = EINVAL;
    230 		return NULL;
    231 	}
    232 
    233 	fd = open("/dev/puffs", O_RDONLY);
    234 	if (fd == -1)
    235 		return NULL;
    236 	if (fd <= 2)
    237 		warnx("puffs_mount: device fd %d (<= 2), sure this is "
    238 		    "what you want?", fd);
    239 
    240 	pargs.pa_vers = PUFFSDEVELVERS | PUFFSVERSION;
    241 	pargs.pa_flags = PUFFS_FLAG_KERN(pflags);
    242 	pargs.pa_fd = fd;
    243 	pargs.pa_maxreqlen = maxreqlen;
    244 	fillvnopmask(pops, pargs.pa_vnopmask);
    245 	(void)strlcpy(pargs.pa_name, puffsname, sizeof(pargs.pa_name));
    246 
    247 	pu = malloc(sizeof(struct puffs_usermount));
    248 	if (!pu)
    249 		return NULL;
    250 
    251 	pu->pu_flags = pflags;
    252 	pu->pu_ops = *pops;
    253 	free(pops); /* XXX */
    254 	pu->pu_fd = fd;
    255 	pu->pu_privdata = priv;
    256 	pu->pu_cc_stacksize = PUFFS_CC_STACKSIZE_DEFAULT;
    257 	LIST_INIT(&pu->pu_pnodelst);
    258 
    259 	/* defaults for some user-settable translation functions */
    260 	pu->pu_cmap = NULL; /* identity translation */
    261 
    262 	pu->pu_pathbuild = puffs_stdpath_buildpath;
    263 	pu->pu_pathfree = puffs_stdpath_freepath;
    264 	pu->pu_pathcmp = puffs_stdpath_cmppath;
    265 	pu->pu_pathtransform = NULL;
    266 	pu->pu_namemod = NULL;
    267 
    268 	pu->pu_state = PUFFS_STATE_MOUNTING;
    269 
    270 #if 1
    271 	/* XXXkludgehere */
    272 	/* kauth doesn't provide this service any longer */
    273 	if (geteuid() != 0)
    274 		mntflags |= MNT_NOSUID | MNT_NODEV;
    275 #endif
    276 
    277 	if (mount(MOUNT_PUFFS, dir, mntflags, &pargs) == -1)
    278 		goto failfree;
    279 	pu->pu_maxreqlen = pargs.pa_maxreqlen;
    280 
    281 	return pu;
    282 
    283  failfree:
    284 	/* can't unmount() from here for obvious reasons */
    285 	if (fd)
    286 		close(fd);
    287 	free(pu);
    288 	return NULL;
    289 }
    290 
    291 int
    292 puffs_start(struct puffs_usermount *pu, void *rootcookie, struct statvfs *sbp)
    293 {
    294 	struct puffs_startreq sreq;
    295 
    296 	memset(&sreq, 0, sizeof(struct puffs_startreq));
    297 	sreq.psr_cookie = rootcookie;
    298 	sreq.psr_sb = *sbp;
    299 
    300 	/* tell kernel we're flying */
    301 	if (ioctl(pu->pu_fd, PUFFSSTARTOP, &sreq) == -1)
    302 		return -1;
    303 
    304 	pu->pu_state = PUFFS_STATE_RUNNING;
    305 
    306 	return 0;
    307 }
    308 
    309 /*
    310  * XXX: there's currently no clean way to request unmount from
    311  * within the user server, so be very brutal about it.
    312  */
    313 /*ARGSUSED*/
    314 int
    315 puffs_exit(struct puffs_usermount *pu, int force)
    316 {
    317 	struct puffs_node *pn, *pn_next;
    318 
    319 	force = 1; /* currently */
    320 
    321 	if (pu->pu_fd)
    322 		close(pu->pu_fd);
    323 
    324 	pn = LIST_FIRST(&pu->pu_pnodelst);
    325 	while (pn) {
    326 		pn_next = LIST_NEXT(pn, pn_entries);
    327 		puffs_pn_put(pn);
    328 		pn = pn_next;
    329 	}
    330 	free(pu);
    331 
    332 	return 0; /* always succesful for now, WILL CHANGE */
    333 }
    334 
    335 int
    336 puffs_mainloop(struct puffs_usermount *pu, int flags)
    337 {
    338 	struct puffs_getreq *pgr;
    339 	struct puffs_putreq *ppr;
    340 	int rv;
    341 
    342 	rv = -1;
    343 	pgr = puffs_req_makeget(pu, pu->pu_maxreqlen, 0);
    344 	if (pgr == NULL)
    345 		return -1;
    346 
    347 	ppr = puffs_req_makeput(pu);
    348 	if (ppr == NULL) {
    349 		puffs_req_destroyget(pgr);
    350 		return -1;
    351 	}
    352 
    353 	if ((flags & PUFFSLOOP_NODAEMON) == 0)
    354 		if (daemon(1, 0) == -1)
    355 			goto out;
    356 
    357 	/* XXX: should be a bit more robust with errors here */
    358 	while (puffs_getstate(pu) == PUFFS_STATE_RUNNING
    359 	    || puffs_getstate(pu) == PUFFS_STATE_UNMOUNTING) {
    360 		puffs_req_resetput(ppr);
    361 
    362 		if (puffs_req_handle(pu, pgr, ppr, 0) == -1) {
    363 			rv = -1;
    364 			break;
    365 		}
    366 		if (puffs_req_putput(ppr) == -1) {
    367 			rv = -1;
    368 			break;
    369 		}
    370 	}
    371 
    372  out:
    373 	puffs_req_destroyput(ppr);
    374 	puffs_req_destroyget(pgr);
    375 	return rv;
    376 }
    377 
    378 int
    379 puffs_dopreq(struct puffs_usermount *pu, struct puffs_req *preq,
    380 	struct puffs_putreq *ppr)
    381 {
    382 	struct puffs_cc *pcc;
    383 	int rv;
    384 
    385 	/*
    386 	 * XXX: the structure is currently a mess.  anyway, trap
    387 	 * the cacheops here already, since they don't need a cc.
    388 	 * I really should get around to revamping the operation
    389 	 * dispatching code one of these days.
    390 	 */
    391 	if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_CACHE) {
    392 		struct puffs_cacheinfo *pci = (void *)preq;
    393 
    394 		if (pu->pu_ops.puffs_cache_write == NULL)
    395 			return 0;
    396 
    397 		pu->pu_ops.puffs_cache_write(pu, preq->preq_cookie,
    398 		    pci->pcache_nruns, pci->pcache_runs);
    399 	}
    400 
    401 	if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
    402 		puffsdump_req(preq);
    403 
    404 	pcc = puffs_cc_create(pu);
    405 
    406 	/* XXX: temporary kludging */
    407 	pcc->pcc_preq = malloc(preq->preq_buflen);
    408 	if (pcc->pcc_preq == NULL)
    409 		return -1;
    410 	(void) memcpy(pcc->pcc_preq, preq, preq->preq_buflen);
    411 
    412 	rv = puffs_docc(pcc, ppr);
    413 
    414 	if ((pcc->pcc_flags & PCC_DONE) == 0)
    415 		return 0;
    416 
    417 	return rv;
    418 }
    419 
    420 int
    421 puffs_docc(struct puffs_cc *pcc, struct puffs_putreq *ppr)
    422 {
    423 	struct puffs_usermount *pu = pcc->pcc_pu;
    424 	int rv;
    425 
    426 	assert((pcc->pcc_flags & PCC_DONE) == 0);
    427 
    428 	puffs_cc_continue(pcc);
    429 	rv = pcc->pcc_rv;
    430 
    431 	if ((pcc->pcc_flags & PCC_DONE) == 0)
    432 		rv = PUFFCALL_AGAIN;
    433 
    434 	/* check if we need to store this reply */
    435 	switch (rv) {
    436 	case PUFFCALL_ANSWER:
    437 		if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
    438 			puffsdump_rv(pcc->pcc_preq);
    439 
    440 		puffs_req_putcc(ppr, pcc);
    441 		break;
    442 	case PUFFCALL_IGNORE:
    443 		puffs_cc_destroy(pcc);
    444 		break;
    445 	case PUFFCALL_AGAIN:
    446 		break;
    447 	default:
    448 		assert(/*CONSTCOND*/0);
    449 	}
    450 
    451 	return 0;
    452 }
    453 
    454 /* library private, but linked from callcontext.c */
    455 
    456 void
    457 puffs_calldispatcher(struct puffs_cc *pcc)
    458 {
    459 	struct puffs_usermount *pu = pcc->pcc_pu;
    460 	struct puffs_ops *pops = &pu->pu_ops;
    461 	struct puffs_req *preq = pcc->pcc_preq;
    462 	void *auxbuf = preq; /* help with typecasting */
    463 	int error, rv, buildpath;
    464 
    465 	assert(pcc->pcc_flags & (PCC_ONCE | PCC_REALCC));
    466 
    467 	if (PUFFSOP_WANTREPLY(preq->preq_opclass))
    468 		rv = PUFFCALL_ANSWER;
    469 	else
    470 		rv = PUFFCALL_IGNORE;
    471 
    472 	buildpath = pu->pu_flags & PUFFS_FLAG_BUILDPATH;
    473 
    474 	if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) {
    475 		switch (preq->preq_optype) {
    476 		case PUFFS_VFS_UNMOUNT:
    477 		{
    478 			struct puffs_vfsreq_unmount *auxt = auxbuf;
    479 
    480 			pu->pu_state = PUFFS_STATE_UNMOUNTING;
    481 			error = pops->puffs_fs_unmount(pcc,
    482 			    auxt->pvfsr_flags, auxt->pvfsr_pid);
    483 			if (!error)
    484 				pu->pu_state = PUFFS_STATE_UNMOUNTED;
    485 			else
    486 				pu->pu_state = PUFFS_STATE_RUNNING;
    487 			break;
    488 		}
    489 
    490 		case PUFFS_VFS_STATVFS:
    491 		{
    492 			struct puffs_vfsreq_statvfs *auxt = auxbuf;
    493 
    494 			error = pops->puffs_fs_statvfs(pcc,
    495 			    &auxt->pvfsr_sb, auxt->pvfsr_pid);
    496 			break;
    497 		}
    498 
    499 		case PUFFS_VFS_SYNC:
    500 		{
    501 			struct puffs_vfsreq_sync *auxt = auxbuf;
    502 
    503 			error = pops->puffs_fs_sync(pcc,
    504 			    auxt->pvfsr_waitfor, &auxt->pvfsr_cred,
    505 			    auxt->pvfsr_pid);
    506 			break;
    507 		}
    508 
    509 		case PUFFS_VFS_FHTOVP:
    510 		{
    511 			struct puffs_vfsreq_fhtonode *auxt = auxbuf;
    512 
    513 			error = pops->puffs_fs_fhtonode(pcc, auxt->pvfsr_data,
    514 			    auxt->pvfsr_dsize, &auxt->pvfsr_fhcookie,
    515 			    &auxt->pvfsr_vtype, &auxt->pvfsr_size,
    516 			    &auxt->pvfsr_rdev);
    517 
    518 			break;
    519 		}
    520 
    521 		case PUFFS_VFS_VPTOFH:
    522 		{
    523 			struct puffs_vfsreq_nodetofh *auxt = auxbuf;
    524 
    525 			error = pops->puffs_fs_nodetofh(pcc,
    526 			    auxt->pvfsr_fhcookie, auxt->pvfsr_data,
    527 			    &auxt->pvfsr_dsize);
    528 
    529 			break;
    530 		}
    531 
    532 		case PUFFS_VFS_SUSPEND:
    533 		{
    534 			struct puffs_vfsreq_suspend *auxt = auxbuf;
    535 
    536 			error = 0;
    537 			if (pops->puffs_fs_suspend == NULL)
    538 				break;
    539 
    540 			pops->puffs_fs_suspend(pcc, auxt->pvfsr_status);
    541 			break;
    542 		}
    543 
    544 		default:
    545 			/*
    546 			 * I guess the kernel sees this one coming
    547 			 */
    548 			error = EINVAL;
    549 			break;
    550 		}
    551 
    552 	/* XXX: audit return values */
    553 	/* XXX: sync with kernel */
    554 	} else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) {
    555 		switch (preq->preq_optype) {
    556 		case PUFFS_VN_LOOKUP:
    557 		{
    558 			struct puffs_vnreq_lookup *auxt = auxbuf;
    559 			struct puffs_cn pcn;
    560 
    561 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    562 			if (buildpath) {
    563 				error = puffs_path_pcnbuild(pu, &pcn,
    564 				    preq->preq_cookie);
    565 				if (error)
    566 					break;
    567 			}
    568 
    569 			/* lookup *must* be present */
    570 			error = pops->puffs_node_lookup(pcc, preq->preq_cookie,
    571 			    &auxt->pvnr_newnode, &auxt->pvnr_vtype,
    572 			    &auxt->pvnr_size, &auxt->pvnr_rdev, &pcn);
    573 
    574 			if (buildpath) {
    575 				if (error) {
    576 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    577 				} else {
    578 					struct puffs_node *pn;
    579 
    580 					/*
    581 					 * did we get a new node or a
    582 					 * recycled node?
    583 					 */
    584 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    585 					if (pn->pn_po.po_path == NULL)
    586 						pn->pn_po = pcn.pcn_po_full;
    587 					else
    588 						pu->pu_pathfree(pu,
    589 						    &pcn.pcn_po_full);
    590 				}
    591 			}
    592 
    593 			break;
    594 		}
    595 
    596 		case PUFFS_VN_CREATE:
    597 		{
    598 			struct puffs_vnreq_create *auxt = auxbuf;
    599 			struct puffs_cn pcn;
    600 			if (pops->puffs_node_create == NULL) {
    601 				error = 0;
    602 				break;
    603 			}
    604 
    605 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    606 			if (buildpath) {
    607 				error = puffs_path_pcnbuild(pu, &pcn,
    608 				    preq->preq_cookie);
    609 				if (error)
    610 					break;
    611 			}
    612 
    613 			error = pops->puffs_node_create(pcc,
    614 			    preq->preq_cookie, &auxt->pvnr_newnode,
    615 			    &pcn, &auxt->pvnr_va);
    616 
    617 			if (buildpath) {
    618 				if (error) {
    619 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    620 				} else {
    621 					struct puffs_node *pn;
    622 
    623 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    624 					pn->pn_po = pcn.pcn_po_full;
    625 				}
    626 			}
    627 
    628 			break;
    629 		}
    630 
    631 		case PUFFS_VN_MKNOD:
    632 		{
    633 			struct puffs_vnreq_mknod *auxt = auxbuf;
    634 			struct puffs_cn pcn;
    635 			if (pops->puffs_node_mknod == NULL) {
    636 				error = 0;
    637 				break;
    638 			}
    639 
    640 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    641 			if (buildpath) {
    642 				error = puffs_path_pcnbuild(pu, &pcn,
    643 				    preq->preq_cookie);
    644 				if (error)
    645 					break;
    646 			}
    647 
    648 			error = pops->puffs_node_mknod(pcc,
    649 			    preq->preq_cookie, &auxt->pvnr_newnode,
    650 			    &pcn, &auxt->pvnr_va);
    651 
    652 			if (buildpath) {
    653 				if (error) {
    654 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    655 				} else {
    656 					struct puffs_node *pn;
    657 
    658 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    659 					pn->pn_po = pcn.pcn_po_full;
    660 				}
    661 			}
    662 
    663 			break;
    664 		}
    665 
    666 		case PUFFS_VN_OPEN:
    667 		{
    668 			struct puffs_vnreq_open *auxt = auxbuf;
    669 			if (pops->puffs_node_open == NULL) {
    670 				error = 0;
    671 				break;
    672 			}
    673 
    674 			error = pops->puffs_node_open(pcc,
    675 			    preq->preq_cookie, auxt->pvnr_mode,
    676 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    677 			break;
    678 		}
    679 
    680 		case PUFFS_VN_CLOSE:
    681 		{
    682 			struct puffs_vnreq_close *auxt = auxbuf;
    683 			if (pops->puffs_node_close == NULL) {
    684 				error = 0;
    685 				break;
    686 			}
    687 
    688 			error = pops->puffs_node_close(pcc,
    689 			    preq->preq_cookie, auxt->pvnr_fflag,
    690 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    691 			break;
    692 		}
    693 
    694 		case PUFFS_VN_ACCESS:
    695 		{
    696 			struct puffs_vnreq_access *auxt = auxbuf;
    697 			if (pops->puffs_node_access == NULL) {
    698 				error = 0;
    699 				break;
    700 			}
    701 
    702 			error = pops->puffs_node_access(pcc,
    703 			    preq->preq_cookie, auxt->pvnr_mode,
    704 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    705 			break;
    706 		}
    707 
    708 		case PUFFS_VN_GETATTR:
    709 		{
    710 			struct puffs_vnreq_getattr *auxt = auxbuf;
    711 			if (pops->puffs_node_getattr == NULL) {
    712 				error = EOPNOTSUPP;
    713 				break;
    714 			}
    715 
    716 			error = pops->puffs_node_getattr(pcc,
    717 			    preq->preq_cookie, &auxt->pvnr_va,
    718 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    719 			break;
    720 		}
    721 
    722 		case PUFFS_VN_SETATTR:
    723 		{
    724 			struct puffs_vnreq_setattr *auxt = auxbuf;
    725 			if (pops->puffs_node_setattr == NULL) {
    726 				error = EOPNOTSUPP;
    727 				break;
    728 			}
    729 
    730 			error = pops->puffs_node_setattr(pcc,
    731 			    preq->preq_cookie, &auxt->pvnr_va,
    732 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    733 			break;
    734 		}
    735 
    736 		case PUFFS_VN_MMAP:
    737 		{
    738 			struct puffs_vnreq_mmap *auxt = auxbuf;
    739 			if (pops->puffs_node_mmap == NULL) {
    740 				error = 0;
    741 				break;
    742 			}
    743 
    744 			error = pops->puffs_node_mmap(pcc,
    745 			    preq->preq_cookie, auxt->pvnr_fflags,
    746 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    747 			break;
    748 		}
    749 
    750 		case PUFFS_VN_FSYNC:
    751 		{
    752 			struct puffs_vnreq_fsync *auxt = auxbuf;
    753 			if (pops->puffs_node_fsync == NULL) {
    754 				error = 0;
    755 				break;
    756 			}
    757 
    758 			error = pops->puffs_node_fsync(pcc,
    759 			    preq->preq_cookie, &auxt->pvnr_cred,
    760 			    auxt->pvnr_flags, auxt->pvnr_offlo,
    761 			    auxt->pvnr_offhi, auxt->pvnr_pid);
    762 			break;
    763 		}
    764 
    765 		case PUFFS_VN_SEEK:
    766 		{
    767 			struct puffs_vnreq_seek *auxt = auxbuf;
    768 			if (pops->puffs_node_seek == NULL) {
    769 				error = 0;
    770 				break;
    771 			}
    772 
    773 			error = pops->puffs_node_seek(pcc,
    774 			    preq->preq_cookie, auxt->pvnr_oldoff,
    775 			    auxt->pvnr_newoff, &auxt->pvnr_cred);
    776 			break;
    777 		}
    778 
    779 		case PUFFS_VN_REMOVE:
    780 		{
    781 			struct puffs_vnreq_remove *auxt = auxbuf;
    782 			struct puffs_cn pcn;
    783 			if (pops->puffs_node_remove == NULL) {
    784 				error = 0;
    785 				break;
    786 			}
    787 
    788 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    789 
    790 			error = pops->puffs_node_remove(pcc,
    791 			    preq->preq_cookie, auxt->pvnr_cookie_targ, &pcn);
    792 			break;
    793 		}
    794 
    795 		case PUFFS_VN_LINK:
    796 		{
    797 			struct puffs_vnreq_link *auxt = auxbuf;
    798 			struct puffs_cn pcn;
    799 			if (pops->puffs_node_link == NULL) {
    800 				error = 0;
    801 				break;
    802 			}
    803 
    804 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    805 			if (buildpath) {
    806 				error = puffs_path_pcnbuild(pu, &pcn,
    807 				    preq->preq_cookie);
    808 				if (error)
    809 					break;
    810 			}
    811 
    812 			error = pops->puffs_node_link(pcc,
    813 			    preq->preq_cookie, auxt->pvnr_cookie_targ, &pcn);
    814 			if (buildpath)
    815 				pu->pu_pathfree(pu, &pcn.pcn_po_full);
    816 
    817 			break;
    818 		}
    819 
    820 		case PUFFS_VN_RENAME:
    821 		{
    822 			struct puffs_vnreq_rename *auxt = auxbuf;
    823 			struct puffs_cn pcn_src, pcn_targ;
    824 			struct puffs_node *pn_src;
    825 
    826 			if (pops->puffs_node_rename == NULL) {
    827 				error = 0;
    828 				break;
    829 			}
    830 
    831 			pcn_src.pcn_pkcnp = &auxt->pvnr_cn_src;
    832 			pcn_targ.pcn_pkcnp = &auxt->pvnr_cn_targ;
    833 			if (buildpath) {
    834 				pn_src = auxt->pvnr_cookie_src;
    835 				pcn_src.pcn_po_full = pn_src->pn_po;
    836 
    837 				error = puffs_path_pcnbuild(pu, &pcn_targ,
    838 				    auxt->pvnr_cookie_targdir);
    839 				if (error)
    840 					break;
    841 			}
    842 
    843 			error = pops->puffs_node_rename(pcc,
    844 			    preq->preq_cookie, auxt->pvnr_cookie_src,
    845 			    &pcn_src, auxt->pvnr_cookie_targdir,
    846 			    auxt->pvnr_cookie_targ, &pcn_targ);
    847 
    848 			if (buildpath) {
    849 				if (error) {
    850 					pu->pu_pathfree(pu,
    851 					    &pcn_targ.pcn_po_full);
    852 				} else {
    853 					struct puffs_pathinfo pi;
    854 					struct puffs_pathobj po_old;
    855 
    856 					/* handle this node */
    857 					po_old = pn_src->pn_po;
    858 					pn_src->pn_po = pcn_targ.pcn_po_full;
    859 
    860 					if (pn_src->pn_va.va_type != VDIR) {
    861 						pu->pu_pathfree(pu, &po_old);
    862 						break;
    863 					}
    864 
    865 					/* handle all child nodes for DIRs */
    866 					pi.pi_old = &pcn_src.pcn_po_full;
    867 					pi.pi_new = &pcn_targ.pcn_po_full;
    868 
    869 					if (puffs_pn_nodewalk(pu,
    870 					    puffs_path_prefixadj, &pi) != NULL)
    871 						error = ENOMEM;
    872 					pu->pu_pathfree(pu, &po_old);
    873 				}
    874 			}
    875 			break;
    876 		}
    877 
    878 		case PUFFS_VN_MKDIR:
    879 		{
    880 			struct puffs_vnreq_mkdir *auxt = auxbuf;
    881 			struct puffs_cn pcn;
    882 			if (pops->puffs_node_mkdir == NULL) {
    883 				error = 0;
    884 				break;
    885 			}
    886 
    887 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    888 			if (buildpath) {
    889 				error = puffs_path_pcnbuild(pu, &pcn,
    890 				    preq->preq_cookie);
    891 				if (error)
    892 					break;
    893 			}
    894 
    895 			error = pops->puffs_node_mkdir(pcc,
    896 			    preq->preq_cookie, &auxt->pvnr_newnode,
    897 			    &pcn, &auxt->pvnr_va);
    898 
    899 			if (buildpath) {
    900 				if (error) {
    901 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    902 				} else {
    903 					struct puffs_node *pn;
    904 
    905 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    906 					pn->pn_po = pcn.pcn_po_full;
    907 				}
    908 			}
    909 
    910 			break;
    911 		}
    912 
    913 		case PUFFS_VN_RMDIR:
    914 		{
    915 			struct puffs_vnreq_rmdir *auxt = auxbuf;
    916 			struct puffs_cn pcn;
    917 			if (pops->puffs_node_rmdir == NULL) {
    918 				error = 0;
    919 				break;
    920 			}
    921 
    922 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    923 
    924 			error = pops->puffs_node_rmdir(pcc,
    925 			    preq->preq_cookie, auxt->pvnr_cookie_targ, &pcn);
    926 			break;
    927 		}
    928 
    929 		case PUFFS_VN_SYMLINK:
    930 		{
    931 			struct puffs_vnreq_symlink *auxt = auxbuf;
    932 			struct puffs_cn pcn;
    933 			if (pops->puffs_node_symlink == NULL) {
    934 				error = 0;
    935 				break;
    936 			}
    937 
    938 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    939 			if (buildpath) {
    940 				error = puffs_path_pcnbuild(pu, &pcn,
    941 				    preq->preq_cookie);
    942 				if (error)
    943 					break;
    944 			}
    945 
    946 			error = pops->puffs_node_symlink(pcc,
    947 			    preq->preq_cookie, &auxt->pvnr_newnode,
    948 			    &pcn, &auxt->pvnr_va, auxt->pvnr_link);
    949 
    950 			if (buildpath) {
    951 				if (error) {
    952 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    953 				} else {
    954 					struct puffs_node *pn;
    955 
    956 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    957 					pn->pn_po = pcn.pcn_po_full;
    958 				}
    959 			}
    960 
    961 			break;
    962 		}
    963 
    964 		case PUFFS_VN_READDIR:
    965 		{
    966 			struct puffs_vnreq_readdir *auxt = auxbuf;
    967 			struct dirent *dent;
    968 			off_t *cookies;
    969 			size_t res;
    970 
    971 			if (pops->puffs_node_readdir == NULL) {
    972 				error = 0;
    973 				break;
    974 			}
    975 
    976 			if (auxt->pvnr_ncookies) {
    977 				/* LINTED: pvnr_data is __aligned() */
    978 				cookies = (off_t *)auxt->pvnr_data;
    979 			} else {
    980 				cookies = NULL;
    981 			}
    982 			/* LINTED: dentoff is aligned in the kernel */
    983 			dent = (struct dirent *)
    984 			    (auxt->pvnr_data + auxt->pvnr_dentoff);
    985 
    986 			res = auxt->pvnr_resid;
    987 			error = pops->puffs_node_readdir(pcc,
    988 			    preq->preq_cookie, dent, &auxt->pvnr_offset,
    989 			    &auxt->pvnr_resid, &auxt->pvnr_cred,
    990 			    &auxt->pvnr_eofflag, cookies, &auxt->pvnr_ncookies);
    991 
    992 			/* need to move a bit more */
    993 			preq->preq_buflen = sizeof(struct puffs_vnreq_readdir)
    994 			    + auxt->pvnr_dentoff + (res - auxt->pvnr_resid);
    995 			break;
    996 		}
    997 
    998 		case PUFFS_VN_READLINK:
    999 		{
   1000 			struct puffs_vnreq_readlink *auxt = auxbuf;
   1001 			if (pops->puffs_node_readlink == NULL) {
   1002 				error = EOPNOTSUPP;
   1003 				break;
   1004 			}
   1005 
   1006 			error = pops->puffs_node_readlink(pcc,
   1007 			    preq->preq_cookie, &auxt->pvnr_cred,
   1008 			    auxt->pvnr_link, &auxt->pvnr_linklen);
   1009 			break;
   1010 		}
   1011 
   1012 		case PUFFS_VN_RECLAIM:
   1013 		{
   1014 			struct puffs_vnreq_reclaim *auxt = auxbuf;
   1015 			if (pops->puffs_node_reclaim == NULL) {
   1016 				error = 0;
   1017 				break;
   1018 			}
   1019 
   1020 			error = pops->puffs_node_reclaim(pcc,
   1021 			    preq->preq_cookie, auxt->pvnr_pid);
   1022 			break;
   1023 		}
   1024 
   1025 		case PUFFS_VN_INACTIVE:
   1026 		{
   1027 			struct puffs_vnreq_inactive *auxt = auxbuf;
   1028 			if (pops->puffs_node_inactive == NULL) {
   1029 				error = EOPNOTSUPP;
   1030 				break;
   1031 			}
   1032 
   1033 			error = pops->puffs_node_inactive(pcc,
   1034 			    preq->preq_cookie, auxt->pvnr_pid,
   1035 			    &auxt->pvnr_backendrefs);
   1036 			break;
   1037 		}
   1038 
   1039 		case PUFFS_VN_PATHCONF:
   1040 		{
   1041 			struct puffs_vnreq_pathconf *auxt = auxbuf;
   1042 			if (pops->puffs_node_pathconf == NULL) {
   1043 				error = 0;
   1044 				break;
   1045 			}
   1046 
   1047 			error = pops->puffs_node_pathconf(pcc,
   1048 			    preq->preq_cookie, auxt->pvnr_name,
   1049 			    &auxt->pvnr_retval);
   1050 			break;
   1051 		}
   1052 
   1053 		case PUFFS_VN_ADVLOCK:
   1054 		{
   1055 			struct puffs_vnreq_advlock *auxt = auxbuf;
   1056 			if (pops->puffs_node_advlock == NULL) {
   1057 				error = 0;
   1058 				break;
   1059 			}
   1060 
   1061 			error = pops->puffs_node_advlock(pcc,
   1062 			    preq->preq_cookie, auxt->pvnr_id, auxt->pvnr_op,
   1063 			    &auxt->pvnr_fl, auxt->pvnr_flags);
   1064 			break;
   1065 		}
   1066 
   1067 		case PUFFS_VN_PRINT:
   1068 		{
   1069 			if (pops->puffs_node_print == NULL) {
   1070 				error = 0;
   1071 				break;
   1072 			}
   1073 
   1074 			error = pops->puffs_node_print(pcc,
   1075 			    preq->preq_cookie);
   1076 			break;
   1077 		}
   1078 
   1079 		case PUFFS_VN_READ:
   1080 		{
   1081 			struct puffs_vnreq_read *auxt = auxbuf;
   1082 			size_t res;
   1083 
   1084 			if (pops->puffs_node_read == NULL) {
   1085 				error = EIO;
   1086 				break;
   1087 			}
   1088 
   1089 			res = auxt->pvnr_resid;
   1090 			error = pops->puffs_node_read(pcc,
   1091 			    preq->preq_cookie, auxt->pvnr_data,
   1092 			    auxt->pvnr_offset, &auxt->pvnr_resid,
   1093 			    &auxt->pvnr_cred, auxt->pvnr_ioflag);
   1094 
   1095 			/* need to move a bit more */
   1096 			preq->preq_buflen = sizeof(struct puffs_vnreq_read)
   1097 			    + (res - auxt->pvnr_resid);
   1098 			break;
   1099 		}
   1100 
   1101 		case PUFFS_VN_WRITE:
   1102 		{
   1103 			struct puffs_vnreq_write *auxt = auxbuf;
   1104 
   1105 			if (pops->puffs_node_write == NULL) {
   1106 				error = EIO;
   1107 				break;
   1108 			}
   1109 
   1110 			error = pops->puffs_node_write(pcc,
   1111 			    preq->preq_cookie, auxt->pvnr_data,
   1112 			    auxt->pvnr_offset, &auxt->pvnr_resid,
   1113 			    &auxt->pvnr_cred, auxt->pvnr_ioflag);
   1114 
   1115 			/* don't need to move data back to the kernel */
   1116 			preq->preq_buflen = sizeof(struct puffs_vnreq_write);
   1117 			break;
   1118 		}
   1119 
   1120 /* holy bitrot, ryydman! */
   1121 #if 0
   1122 		case PUFFS_VN_IOCTL:
   1123 			error = pops->puffs_node_ioctl1(pcc, preq->preq_cookie,
   1124 			     (struct puffs_vnreq_ioctl *)auxbuf, &pop);
   1125 			if (error != 0)
   1126 				break;
   1127 			pop.pso_reqid = preq->preq_id;
   1128 
   1129 			/* let the kernel do it's intermediate duty */
   1130 			error = ioctl(pu->pu_fd, PUFFSSIZEOP, &pop);
   1131 			/*
   1132 			 * XXX: I don't actually know what the correct
   1133 			 * thing to do in case of an error is, so I'll
   1134 			 * just ignore it for the time being.
   1135 			 */
   1136 			error = pops->puffs_node_ioctl2(pcc, preq->preq_cookie,
   1137 			    (struct puffs_vnreq_ioctl *)auxbuf, &pop);
   1138 			break;
   1139 
   1140 		case PUFFS_VN_FCNTL:
   1141 			error = pops->puffs_node_fcntl1(pcc, preq->preq_cookie,
   1142 			     (struct puffs_vnreq_fcntl *)auxbuf, &pop);
   1143 			if (error != 0)
   1144 				break;
   1145 			pop.pso_reqid = preq->preq_id;
   1146 
   1147 			/* let the kernel do it's intermediate duty */
   1148 			error = ioctl(pu->pu_fd, PUFFSSIZEOP, &pop);
   1149 			/*
   1150 			 * XXX: I don't actually know what the correct
   1151 			 * thing to do in case of an error is, so I'll
   1152 			 * just ignore it for the time being.
   1153 			 */
   1154 			error = pops->puffs_node_fcntl2(pcc, preq->preq_cookie,
   1155 			    (struct puffs_vnreq_fcntl *)auxbuf, &pop);
   1156 			break;
   1157 #endif
   1158 
   1159 		default:
   1160 			printf("inval op %d\n", preq->preq_optype);
   1161 			error = EINVAL;
   1162 			break;
   1163 		}
   1164 	} else {
   1165 		/*
   1166 		 * this one also
   1167 		 */
   1168 		error = EINVAL;
   1169 	}
   1170 
   1171 	preq->preq_rv = error;
   1172 
   1173 	pcc->pcc_rv = rv;
   1174 	pcc->pcc_flags |= PCC_DONE;
   1175 }
   1176 
   1177 
   1178 #if 0
   1179 		case PUFFS_VN_POLL:
   1180 		{
   1181 			struct puffs_vnreq_poll *auxt = auxbuf;
   1182 			if (pops->puffs_node_poll == NULL) {
   1183 				error = 0;
   1184 				break;
   1185 			}
   1186 
   1187 			error = pops->puffs_node_poll(pcc,
   1188 			    preq->preq_cookie, preq-);
   1189 			break;
   1190 		}
   1191 
   1192 		case PUFFS_VN_KQFILTER:
   1193 		{
   1194 			struct puffs_vnreq_kqfilter *auxt = auxbuf;
   1195 			if (pops->puffs_node_kqfilter == NULL) {
   1196 				error = 0;
   1197 				break;
   1198 			}
   1199 
   1200 			error = pops->puffs_node_kqfilter(pcc,
   1201 			    preq->preq_cookie, );
   1202 			break;
   1203 		}
   1204 
   1205 		case PUFFS_VN_CLOSEEXTATTR:
   1206 		{
   1207 			struct puffs_vnreq_closeextattr *auxt = auxbuf;
   1208 			if (pops->puffs_closeextattr == NULL) {
   1209 				error = 0;
   1210 				break;
   1211 			}
   1212 
   1213 			error = pops->puffs_closeextattr(pcc,
   1214 			    preq->preq_cookie, );
   1215 			break;
   1216 		}
   1217 
   1218 		case PUFFS_VN_GETEXTATTR:
   1219 		{
   1220 			struct puffs_vnreq_getextattr *auxt = auxbuf;
   1221 			if (pops->puffs_getextattr == NULL) {
   1222 				error = 0;
   1223 				break;
   1224 			}
   1225 
   1226 			error = pops->puffs_getextattr(pcc,
   1227 			    preq->preq_cookie, );
   1228 			break;
   1229 		}
   1230 
   1231 		case PUFFS_VN_LISTEXTATTR:
   1232 		{
   1233 			struct puffs_vnreq_listextattr *auxt = auxbuf;
   1234 			if (pops->puffs_listextattr == NULL) {
   1235 				error = 0;
   1236 				break;
   1237 			}
   1238 
   1239 			error = pops->puffs_listextattr(pcc,
   1240 			    preq->preq_cookie, );
   1241 			break;
   1242 		}
   1243 
   1244 		case PUFFS_VN_OPENEXTATTR:
   1245 		{
   1246 			struct puffs_vnreq_openextattr *auxt = auxbuf;
   1247 			if (pops->puffs_openextattr == NULL) {
   1248 				error = 0;
   1249 				break;
   1250 			}
   1251 
   1252 			error = pops->puffs_openextattr(pcc,
   1253 			    preq->preq_cookie, );
   1254 			break;
   1255 		}
   1256 
   1257 		case PUFFS_VN_DELETEEXTATTR:
   1258 		{
   1259 			struct puffs_vnreq_deleteextattr *auxt = auxbuf;
   1260 			if (pops->puffs_deleteextattr == NULL) {
   1261 				error = 0;
   1262 				break;
   1263 			}
   1264 
   1265 			error = pops->puffs_deleteextattr(pcc,
   1266 			    preq->preq_cookie, );
   1267 			break;
   1268 		}
   1269 
   1270 		case PUFFS_VN_SETEXTATTR:
   1271 		{
   1272 			struct puffs_vnreq_setextattr *auxt = auxbuf;
   1273 			if (pops->puffs_setextattr == NULL) {
   1274 				error = 0;
   1275 				break;
   1276 			}
   1277 
   1278 			error = pops->puffs_setextattr(pcc,
   1279 			    preq->preq_cookie, );
   1280 			break;
   1281 		}
   1282 
   1283 #endif
   1284