Home | History | Annotate | Line # | Download | only in libpuffs
puffs.c revision 1.38
      1 /*	$NetBSD: puffs.c,v 1.38 2007/04/16 13:04:49 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.38 2007/04/16 13:04:49 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_kargs.pa_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_kargs.pa_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_kargs.pa_maxreqlen;
    179 }
    180 
    181 void
    182 puffs_setmaxreqlen(struct puffs_usermount *pu, size_t reqlen)
    183 {
    184 
    185 	if (pu->pu_state != PUFFS_STATE_BEFOREMOUNT)
    186 		warnx("puffs_setmaxreqlen: call has effect only "
    187 		    "before mount\n");
    188 
    189 	pu->pu_kargs.pa_maxreqlen = reqlen;
    190 }
    191 
    192 void
    193 puffs_setfhsize(struct puffs_usermount *pu, size_t fhsize, int flags)
    194 {
    195 
    196 	if (pu->pu_state != PUFFS_STATE_BEFOREMOUNT)
    197 		warnx("puffs_setfhsize: call has effect only before mount\n");
    198 
    199 	pu->pu_kargs.pa_fhsize = fhsize;
    200 	pu->pu_kargs.pa_fhflags = flags;
    201 }
    202 
    203 void
    204 puffs_setncookiehash(struct puffs_usermount *pu, int nhash)
    205 {
    206 
    207 	if (pu->pu_state != PUFFS_STATE_BEFOREMOUNT)
    208 		warnx("puffs_setfhsize: call has effect only before mount\n");
    209 
    210 	pu->pu_kargs.pa_nhashbuckets = nhash;
    211 }
    212 
    213 void
    214 puffs_set_pathbuild(struct puffs_usermount *pu, pu_pathbuild_fn fn)
    215 {
    216 
    217 	pu->pu_pathbuild = fn;
    218 }
    219 
    220 void
    221 puffs_set_pathtransform(struct puffs_usermount *pu, pu_pathtransform_fn fn)
    222 {
    223 
    224 	pu->pu_pathtransform = fn;
    225 }
    226 
    227 void
    228 puffs_set_pathcmp(struct puffs_usermount *pu, pu_pathcmp_fn fn)
    229 {
    230 
    231 	pu->pu_pathcmp = fn;
    232 }
    233 
    234 void
    235 puffs_set_pathfree(struct puffs_usermount *pu, pu_pathfree_fn fn)
    236 {
    237 
    238 	pu->pu_pathfree = fn;
    239 }
    240 
    241 void
    242 puffs_set_namemod(struct puffs_usermount *pu, pu_namemod_fn fn)
    243 {
    244 
    245 	pu->pu_namemod = fn;
    246 }
    247 
    248 int
    249 puffs_domount(struct puffs_usermount *pu, const char *dir, int mntflags)
    250 {
    251 
    252 #if 1
    253 	/* XXXkludgehere */
    254 	/* kauth doesn't provide this service any longer */
    255 	if (geteuid() != 0)
    256 		mntflags |= MNT_NOSUID | MNT_NODEV;
    257 #endif
    258 
    259 	if (mount(MOUNT_PUFFS, dir, mntflags, &pu->pu_kargs) == -1)
    260 		return -1;
    261 	pu->pu_state = PUFFS_STATE_MOUNTING;
    262 
    263 	return 0;
    264 }
    265 
    266 struct puffs_usermount *
    267 _puffs_init(int develv, struct puffs_ops *pops, const char *puffsname,
    268 	void *priv, uint32_t pflags)
    269 {
    270 	struct puffs_usermount *pu;
    271 	struct puffs_kargs *pargs;
    272 	int fd;
    273 
    274 	if (develv != PUFFS_DEVEL_LIBVERSION) {
    275 		warnx("puffs_mount: mounting with lib version %d, need %d",
    276 		    develv, PUFFS_DEVEL_LIBVERSION);
    277 		errno = EINVAL;
    278 		return NULL;
    279 	}
    280 
    281 	fd = open("/dev/puffs", O_RDONLY);
    282 	if (fd == -1)
    283 		return NULL;
    284 	if (fd <= 2)
    285 		warnx("puffs_mount: device fd %d (<= 2), sure this is "
    286 		    "what you want?", fd);
    287 
    288 	pu = malloc(sizeof(struct puffs_usermount));
    289 	if (pu == NULL)
    290 		goto failfree;
    291 
    292 	pargs = &pu->pu_kargs;
    293 	memset(pargs, 0, sizeof(struct puffs_kargs));
    294 	pargs->pa_vers = PUFFSDEVELVERS | PUFFSVERSION;
    295 	pargs->pa_flags = PUFFS_FLAG_KERN(pflags);
    296 	pargs->pa_fd = fd;
    297 	fillvnopmask(pops, pargs->pa_vnopmask);
    298 	(void)strlcpy(pargs->pa_name, puffsname, sizeof(pargs->pa_name));
    299 
    300 	pu->pu_flags = pflags;
    301 	pu->pu_ops = *pops;
    302 	free(pops); /* XXX */
    303 
    304 	pu->pu_privdata = priv;
    305 	pu->pu_cc_stacksize = PUFFS_CC_STACKSIZE_DEFAULT;
    306 	LIST_INIT(&pu->pu_pnodelst);
    307 
    308 	/* defaults for some user-settable translation functions */
    309 	pu->pu_cmap = NULL; /* identity translation */
    310 
    311 	pu->pu_pathbuild = puffs_stdpath_buildpath;
    312 	pu->pu_pathfree = puffs_stdpath_freepath;
    313 	pu->pu_pathcmp = puffs_stdpath_cmppath;
    314 	pu->pu_pathtransform = NULL;
    315 	pu->pu_namemod = NULL;
    316 
    317 	pu->pu_state = PUFFS_STATE_BEFOREMOUNT;
    318 
    319 	return pu;
    320 
    321  failfree:
    322 	/* can't unmount() from here for obvious reasons */
    323 	close(fd);
    324 	free(pu);
    325 	return NULL;
    326 }
    327 
    328 struct puffs_usermount *
    329 _puffs_mount(int develv, struct puffs_ops *pops, const char *dir, int mntflags,
    330 	const char *puffsname, void *priv, uint32_t pflags)
    331 {
    332 	struct puffs_usermount *pu;
    333 	int sverrno;
    334 
    335 	pu = _puffs_init(develv, pops, puffsname, priv, pflags);
    336 	if (pu == NULL)
    337 		return NULL;
    338 
    339 	if (puffs_domount(pu, dir, mntflags) == -1) {
    340 		sverrno = errno;
    341 		puffs_exit(pu, 1);
    342 		errno = sverrno;
    343 		return NULL;
    344 	}
    345 
    346 	return pu;
    347 }
    348 
    349 int
    350 puffs_start(struct puffs_usermount *pu, void *rootcookie, struct statvfs *sbp)
    351 {
    352 	struct puffs_startreq sreq;
    353 
    354 	memset(&sreq, 0, sizeof(struct puffs_startreq));
    355 	sreq.psr_cookie = rootcookie;
    356 	sreq.psr_sb = *sbp;
    357 
    358 	/* tell kernel we're flying */
    359 	if (ioctl(pu->pu_kargs.pa_fd, PUFFSSTARTOP, &sreq) == -1)
    360 		return -1;
    361 
    362 	pu->pu_state = PUFFS_STATE_RUNNING;
    363 
    364 	return 0;
    365 }
    366 
    367 /*
    368  * XXX: there's currently no clean way to request unmount from
    369  * within the user server, so be very brutal about it.
    370  */
    371 /*ARGSUSED1*/
    372 int
    373 puffs_exit(struct puffs_usermount *pu, int force)
    374 {
    375 	struct puffs_node *pn, *pn_next;
    376 
    377 	force = 1; /* currently */
    378 
    379 	if (pu->pu_kargs.pa_fd)
    380 		close(pu->pu_kargs.pa_fd);
    381 
    382 	pn = LIST_FIRST(&pu->pu_pnodelst);
    383 	while (pn) {
    384 		pn_next = LIST_NEXT(pn, pn_entries);
    385 		puffs_pn_put(pn);
    386 		pn = pn_next;
    387 	}
    388 	free(pu);
    389 
    390 	return 0; /* always succesful for now, WILL CHANGE */
    391 }
    392 
    393 int
    394 puffs_mainloop(struct puffs_usermount *pu, int flags)
    395 {
    396 	struct puffs_getreq *pgr;
    397 	struct puffs_putreq *ppr;
    398 	int rv;
    399 
    400 	rv = -1;
    401 	pgr = puffs_req_makeget(pu, puffs_getmaxreqlen(pu), 0);
    402 	if (pgr == NULL)
    403 		return -1;
    404 
    405 	ppr = puffs_req_makeput(pu);
    406 	if (ppr == NULL) {
    407 		puffs_req_destroyget(pgr);
    408 		return -1;
    409 	}
    410 
    411 	if ((flags & PUFFSLOOP_NODAEMON) == 0)
    412 		if (daemon(1, 0) == -1)
    413 			goto out;
    414 
    415 	/* XXX: should be a bit more robust with errors here */
    416 	while (puffs_getstate(pu) == PUFFS_STATE_RUNNING
    417 	    || puffs_getstate(pu) == PUFFS_STATE_UNMOUNTING) {
    418 		puffs_req_resetput(ppr);
    419 
    420 		if (puffs_req_handle(pu, pgr, ppr, 0) == -1) {
    421 			rv = -1;
    422 			break;
    423 		}
    424 		if (puffs_req_putput(ppr) == -1) {
    425 			rv = -1;
    426 			break;
    427 		}
    428 	}
    429 
    430  out:
    431 	puffs_req_destroyput(ppr);
    432 	puffs_req_destroyget(pgr);
    433 	return rv;
    434 }
    435 
    436 int
    437 puffs_dopreq(struct puffs_usermount *pu, struct puffs_req *preq,
    438 	struct puffs_putreq *ppr)
    439 {
    440 	struct puffs_cc *pcc;
    441 	int rv;
    442 
    443 	/*
    444 	 * XXX: the structure is currently a mess.  anyway, trap
    445 	 * the cacheops here already, since they don't need a cc.
    446 	 * I really should get around to revamping the operation
    447 	 * dispatching code one of these days.
    448 	 */
    449 	if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_CACHE) {
    450 		struct puffs_cacheinfo *pci = (void *)preq;
    451 
    452 		if (pu->pu_ops.puffs_cache_write == NULL)
    453 			return 0;
    454 
    455 		pu->pu_ops.puffs_cache_write(pu, preq->preq_cookie,
    456 		    pci->pcache_nruns, pci->pcache_runs);
    457 	}
    458 
    459 	if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
    460 		puffsdump_req(preq);
    461 
    462 	pcc = puffs_cc_create(pu);
    463 
    464 	/* XXX: temporary kludging */
    465 	pcc->pcc_preq = malloc(preq->preq_buflen);
    466 	if (pcc->pcc_preq == NULL)
    467 		return -1;
    468 	(void) memcpy(pcc->pcc_preq, preq, preq->preq_buflen);
    469 
    470 	rv = puffs_docc(pcc, ppr);
    471 
    472 	if ((pcc->pcc_flags & PCC_DONE) == 0)
    473 		return 0;
    474 
    475 	return rv;
    476 }
    477 
    478 enum {PUFFCALL_ANSWER, PUFFCALL_IGNORE, PUFFCALL_AGAIN};
    479 
    480 int
    481 puffs_docc(struct puffs_cc *pcc, struct puffs_putreq *ppr)
    482 {
    483 	struct puffs_usermount *pu = pcc->pcc_pu;
    484 	int rv;
    485 
    486 	assert((pcc->pcc_flags & PCC_DONE) == 0);
    487 
    488 	puffs_cc_continue(pcc);
    489 	rv = pcc->pcc_rv;
    490 
    491 	if ((pcc->pcc_flags & PCC_DONE) == 0)
    492 		rv = PUFFCALL_AGAIN;
    493 
    494 	/* check if we need to store this reply */
    495 	switch (rv) {
    496 	case PUFFCALL_ANSWER:
    497 		if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
    498 			puffsdump_rv(pcc->pcc_preq);
    499 
    500 		puffs_req_putcc(ppr, pcc);
    501 		break;
    502 	case PUFFCALL_IGNORE:
    503 		puffs_cc_destroy(pcc);
    504 		break;
    505 	case PUFFCALL_AGAIN:
    506 		break;
    507 	default:
    508 		assert(/*CONSTCOND*/0);
    509 	}
    510 
    511 	return 0;
    512 }
    513 
    514 /* library private, but linked from callcontext.c */
    515 
    516 void
    517 puffs_calldispatcher(struct puffs_cc *pcc)
    518 {
    519 	struct puffs_usermount *pu = pcc->pcc_pu;
    520 	struct puffs_ops *pops = &pu->pu_ops;
    521 	struct puffs_req *preq = pcc->pcc_preq;
    522 	void *auxbuf = preq; /* help with typecasting */
    523 	int error, rv, buildpath;
    524 
    525 	assert(pcc->pcc_flags & (PCC_ONCE | PCC_REALCC));
    526 
    527 	if (PUFFSOP_WANTREPLY(preq->preq_opclass))
    528 		rv = PUFFCALL_ANSWER;
    529 	else
    530 		rv = PUFFCALL_IGNORE;
    531 
    532 	buildpath = pu->pu_flags & PUFFS_FLAG_BUILDPATH;
    533 
    534 	if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) {
    535 		switch (preq->preq_optype) {
    536 		case PUFFS_VFS_UNMOUNT:
    537 		{
    538 			struct puffs_vfsreq_unmount *auxt = auxbuf;
    539 
    540 			pu->pu_state = PUFFS_STATE_UNMOUNTING;
    541 			error = pops->puffs_fs_unmount(pcc,
    542 			    auxt->pvfsr_flags, auxt->pvfsr_pid);
    543 			if (!error)
    544 				pu->pu_state = PUFFS_STATE_UNMOUNTED;
    545 			else
    546 				pu->pu_state = PUFFS_STATE_RUNNING;
    547 			break;
    548 		}
    549 
    550 		case PUFFS_VFS_STATVFS:
    551 		{
    552 			struct puffs_vfsreq_statvfs *auxt = auxbuf;
    553 
    554 			error = pops->puffs_fs_statvfs(pcc,
    555 			    &auxt->pvfsr_sb, auxt->pvfsr_pid);
    556 			break;
    557 		}
    558 
    559 		case PUFFS_VFS_SYNC:
    560 		{
    561 			struct puffs_vfsreq_sync *auxt = auxbuf;
    562 
    563 			error = pops->puffs_fs_sync(pcc,
    564 			    auxt->pvfsr_waitfor, &auxt->pvfsr_cred,
    565 			    auxt->pvfsr_pid);
    566 			break;
    567 		}
    568 
    569 		case PUFFS_VFS_FHTOVP:
    570 		{
    571 			struct puffs_vfsreq_fhtonode *auxt = auxbuf;
    572 
    573 			error = pops->puffs_fs_fhtonode(pcc, auxt->pvfsr_data,
    574 			    auxt->pvfsr_dsize, &auxt->pvfsr_fhcookie,
    575 			    &auxt->pvfsr_vtype, &auxt->pvfsr_size,
    576 			    &auxt->pvfsr_rdev);
    577 
    578 			break;
    579 		}
    580 
    581 		case PUFFS_VFS_VPTOFH:
    582 		{
    583 			struct puffs_vfsreq_nodetofh *auxt = auxbuf;
    584 
    585 			error = pops->puffs_fs_nodetofh(pcc,
    586 			    auxt->pvfsr_fhcookie, auxt->pvfsr_data,
    587 			    &auxt->pvfsr_dsize);
    588 
    589 			break;
    590 		}
    591 
    592 		case PUFFS_VFS_SUSPEND:
    593 		{
    594 			struct puffs_vfsreq_suspend *auxt = auxbuf;
    595 
    596 			error = 0;
    597 			if (pops->puffs_fs_suspend == NULL)
    598 				break;
    599 
    600 			pops->puffs_fs_suspend(pcc, auxt->pvfsr_status);
    601 			break;
    602 		}
    603 
    604 		default:
    605 			/*
    606 			 * I guess the kernel sees this one coming
    607 			 */
    608 			error = EINVAL;
    609 			break;
    610 		}
    611 
    612 	/* XXX: audit return values */
    613 	/* XXX: sync with kernel */
    614 	} else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) {
    615 		switch (preq->preq_optype) {
    616 		case PUFFS_VN_LOOKUP:
    617 		{
    618 			struct puffs_vnreq_lookup *auxt = auxbuf;
    619 			struct puffs_cn pcn;
    620 
    621 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    622 			if (buildpath) {
    623 				error = puffs_path_pcnbuild(pu, &pcn,
    624 				    preq->preq_cookie);
    625 				if (error)
    626 					break;
    627 			}
    628 
    629 			/* lookup *must* be present */
    630 			error = pops->puffs_node_lookup(pcc, preq->preq_cookie,
    631 			    &auxt->pvnr_newnode, &auxt->pvnr_vtype,
    632 			    &auxt->pvnr_size, &auxt->pvnr_rdev, &pcn);
    633 
    634 			if (buildpath) {
    635 				if (error) {
    636 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    637 				} else {
    638 					struct puffs_node *pn;
    639 
    640 					/*
    641 					 * did we get a new node or a
    642 					 * recycled node?
    643 					 */
    644 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    645 					if (pn->pn_po.po_path == NULL)
    646 						pn->pn_po = pcn.pcn_po_full;
    647 					else
    648 						pu->pu_pathfree(pu,
    649 						    &pcn.pcn_po_full);
    650 				}
    651 			}
    652 
    653 			break;
    654 		}
    655 
    656 		case PUFFS_VN_CREATE:
    657 		{
    658 			struct puffs_vnreq_create *auxt = auxbuf;
    659 			struct puffs_cn pcn;
    660 			if (pops->puffs_node_create == NULL) {
    661 				error = 0;
    662 				break;
    663 			}
    664 
    665 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    666 			if (buildpath) {
    667 				error = puffs_path_pcnbuild(pu, &pcn,
    668 				    preq->preq_cookie);
    669 				if (error)
    670 					break;
    671 			}
    672 
    673 			error = pops->puffs_node_create(pcc,
    674 			    preq->preq_cookie, &auxt->pvnr_newnode,
    675 			    &pcn, &auxt->pvnr_va);
    676 
    677 			if (buildpath) {
    678 				if (error) {
    679 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    680 				} else {
    681 					struct puffs_node *pn;
    682 
    683 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    684 					pn->pn_po = pcn.pcn_po_full;
    685 				}
    686 			}
    687 
    688 			break;
    689 		}
    690 
    691 		case PUFFS_VN_MKNOD:
    692 		{
    693 			struct puffs_vnreq_mknod *auxt = auxbuf;
    694 			struct puffs_cn pcn;
    695 			if (pops->puffs_node_mknod == NULL) {
    696 				error = 0;
    697 				break;
    698 			}
    699 
    700 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    701 			if (buildpath) {
    702 				error = puffs_path_pcnbuild(pu, &pcn,
    703 				    preq->preq_cookie);
    704 				if (error)
    705 					break;
    706 			}
    707 
    708 			error = pops->puffs_node_mknod(pcc,
    709 			    preq->preq_cookie, &auxt->pvnr_newnode,
    710 			    &pcn, &auxt->pvnr_va);
    711 
    712 			if (buildpath) {
    713 				if (error) {
    714 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    715 				} else {
    716 					struct puffs_node *pn;
    717 
    718 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    719 					pn->pn_po = pcn.pcn_po_full;
    720 				}
    721 			}
    722 
    723 			break;
    724 		}
    725 
    726 		case PUFFS_VN_OPEN:
    727 		{
    728 			struct puffs_vnreq_open *auxt = auxbuf;
    729 			if (pops->puffs_node_open == NULL) {
    730 				error = 0;
    731 				break;
    732 			}
    733 
    734 			error = pops->puffs_node_open(pcc,
    735 			    preq->preq_cookie, auxt->pvnr_mode,
    736 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    737 			break;
    738 		}
    739 
    740 		case PUFFS_VN_CLOSE:
    741 		{
    742 			struct puffs_vnreq_close *auxt = auxbuf;
    743 			if (pops->puffs_node_close == NULL) {
    744 				error = 0;
    745 				break;
    746 			}
    747 
    748 			error = pops->puffs_node_close(pcc,
    749 			    preq->preq_cookie, auxt->pvnr_fflag,
    750 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    751 			break;
    752 		}
    753 
    754 		case PUFFS_VN_ACCESS:
    755 		{
    756 			struct puffs_vnreq_access *auxt = auxbuf;
    757 			if (pops->puffs_node_access == NULL) {
    758 				error = 0;
    759 				break;
    760 			}
    761 
    762 			error = pops->puffs_node_access(pcc,
    763 			    preq->preq_cookie, auxt->pvnr_mode,
    764 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    765 			break;
    766 		}
    767 
    768 		case PUFFS_VN_GETATTR:
    769 		{
    770 			struct puffs_vnreq_getattr *auxt = auxbuf;
    771 			if (pops->puffs_node_getattr == NULL) {
    772 				error = EOPNOTSUPP;
    773 				break;
    774 			}
    775 
    776 			error = pops->puffs_node_getattr(pcc,
    777 			    preq->preq_cookie, &auxt->pvnr_va,
    778 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    779 			break;
    780 		}
    781 
    782 		case PUFFS_VN_SETATTR:
    783 		{
    784 			struct puffs_vnreq_setattr *auxt = auxbuf;
    785 			if (pops->puffs_node_setattr == NULL) {
    786 				error = EOPNOTSUPP;
    787 				break;
    788 			}
    789 
    790 			error = pops->puffs_node_setattr(pcc,
    791 			    preq->preq_cookie, &auxt->pvnr_va,
    792 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    793 			break;
    794 		}
    795 
    796 		case PUFFS_VN_MMAP:
    797 		{
    798 			struct puffs_vnreq_mmap *auxt = auxbuf;
    799 			if (pops->puffs_node_mmap == NULL) {
    800 				error = 0;
    801 				break;
    802 			}
    803 
    804 			error = pops->puffs_node_mmap(pcc,
    805 			    preq->preq_cookie, auxt->pvnr_fflags,
    806 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    807 			break;
    808 		}
    809 
    810 		case PUFFS_VN_FSYNC:
    811 		{
    812 			struct puffs_vnreq_fsync *auxt = auxbuf;
    813 			if (pops->puffs_node_fsync == NULL) {
    814 				error = 0;
    815 				break;
    816 			}
    817 
    818 			error = pops->puffs_node_fsync(pcc,
    819 			    preq->preq_cookie, &auxt->pvnr_cred,
    820 			    auxt->pvnr_flags, auxt->pvnr_offlo,
    821 			    auxt->pvnr_offhi, auxt->pvnr_pid);
    822 			break;
    823 		}
    824 
    825 		case PUFFS_VN_SEEK:
    826 		{
    827 			struct puffs_vnreq_seek *auxt = auxbuf;
    828 			if (pops->puffs_node_seek == NULL) {
    829 				error = 0;
    830 				break;
    831 			}
    832 
    833 			error = pops->puffs_node_seek(pcc,
    834 			    preq->preq_cookie, auxt->pvnr_oldoff,
    835 			    auxt->pvnr_newoff, &auxt->pvnr_cred);
    836 			break;
    837 		}
    838 
    839 		case PUFFS_VN_REMOVE:
    840 		{
    841 			struct puffs_vnreq_remove *auxt = auxbuf;
    842 			struct puffs_cn pcn;
    843 			if (pops->puffs_node_remove == NULL) {
    844 				error = 0;
    845 				break;
    846 			}
    847 
    848 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    849 
    850 			error = pops->puffs_node_remove(pcc,
    851 			    preq->preq_cookie, auxt->pvnr_cookie_targ, &pcn);
    852 			break;
    853 		}
    854 
    855 		case PUFFS_VN_LINK:
    856 		{
    857 			struct puffs_vnreq_link *auxt = auxbuf;
    858 			struct puffs_cn pcn;
    859 			if (pops->puffs_node_link == NULL) {
    860 				error = 0;
    861 				break;
    862 			}
    863 
    864 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    865 			if (buildpath) {
    866 				error = puffs_path_pcnbuild(pu, &pcn,
    867 				    preq->preq_cookie);
    868 				if (error)
    869 					break;
    870 			}
    871 
    872 			error = pops->puffs_node_link(pcc,
    873 			    preq->preq_cookie, auxt->pvnr_cookie_targ, &pcn);
    874 			if (buildpath)
    875 				pu->pu_pathfree(pu, &pcn.pcn_po_full);
    876 
    877 			break;
    878 		}
    879 
    880 		case PUFFS_VN_RENAME:
    881 		{
    882 			struct puffs_vnreq_rename *auxt = auxbuf;
    883 			struct puffs_cn pcn_src, pcn_targ;
    884 			struct puffs_node *pn_src;
    885 
    886 			if (pops->puffs_node_rename == NULL) {
    887 				error = 0;
    888 				break;
    889 			}
    890 
    891 			pcn_src.pcn_pkcnp = &auxt->pvnr_cn_src;
    892 			pcn_targ.pcn_pkcnp = &auxt->pvnr_cn_targ;
    893 			if (buildpath) {
    894 				pn_src = auxt->pvnr_cookie_src;
    895 				pcn_src.pcn_po_full = pn_src->pn_po;
    896 
    897 				error = puffs_path_pcnbuild(pu, &pcn_targ,
    898 				    auxt->pvnr_cookie_targdir);
    899 				if (error)
    900 					break;
    901 			}
    902 
    903 			error = pops->puffs_node_rename(pcc,
    904 			    preq->preq_cookie, auxt->pvnr_cookie_src,
    905 			    &pcn_src, auxt->pvnr_cookie_targdir,
    906 			    auxt->pvnr_cookie_targ, &pcn_targ);
    907 
    908 			if (buildpath) {
    909 				if (error) {
    910 					pu->pu_pathfree(pu,
    911 					    &pcn_targ.pcn_po_full);
    912 				} else {
    913 					struct puffs_pathinfo pi;
    914 					struct puffs_pathobj po_old;
    915 
    916 					/* handle this node */
    917 					po_old = pn_src->pn_po;
    918 					pn_src->pn_po = pcn_targ.pcn_po_full;
    919 
    920 					if (pn_src->pn_va.va_type != VDIR) {
    921 						pu->pu_pathfree(pu, &po_old);
    922 						break;
    923 					}
    924 
    925 					/* handle all child nodes for DIRs */
    926 					pi.pi_old = &pcn_src.pcn_po_full;
    927 					pi.pi_new = &pcn_targ.pcn_po_full;
    928 
    929 					if (puffs_pn_nodewalk(pu,
    930 					    puffs_path_prefixadj, &pi) != NULL)
    931 						error = ENOMEM;
    932 					pu->pu_pathfree(pu, &po_old);
    933 				}
    934 			}
    935 			break;
    936 		}
    937 
    938 		case PUFFS_VN_MKDIR:
    939 		{
    940 			struct puffs_vnreq_mkdir *auxt = auxbuf;
    941 			struct puffs_cn pcn;
    942 			if (pops->puffs_node_mkdir == NULL) {
    943 				error = 0;
    944 				break;
    945 			}
    946 
    947 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    948 			if (buildpath) {
    949 				error = puffs_path_pcnbuild(pu, &pcn,
    950 				    preq->preq_cookie);
    951 				if (error)
    952 					break;
    953 			}
    954 
    955 			error = pops->puffs_node_mkdir(pcc,
    956 			    preq->preq_cookie, &auxt->pvnr_newnode,
    957 			    &pcn, &auxt->pvnr_va);
    958 
    959 			if (buildpath) {
    960 				if (error) {
    961 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    962 				} else {
    963 					struct puffs_node *pn;
    964 
    965 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    966 					pn->pn_po = pcn.pcn_po_full;
    967 				}
    968 			}
    969 
    970 			break;
    971 		}
    972 
    973 		case PUFFS_VN_RMDIR:
    974 		{
    975 			struct puffs_vnreq_rmdir *auxt = auxbuf;
    976 			struct puffs_cn pcn;
    977 			if (pops->puffs_node_rmdir == NULL) {
    978 				error = 0;
    979 				break;
    980 			}
    981 
    982 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    983 
    984 			error = pops->puffs_node_rmdir(pcc,
    985 			    preq->preq_cookie, auxt->pvnr_cookie_targ, &pcn);
    986 			break;
    987 		}
    988 
    989 		case PUFFS_VN_SYMLINK:
    990 		{
    991 			struct puffs_vnreq_symlink *auxt = auxbuf;
    992 			struct puffs_cn pcn;
    993 			if (pops->puffs_node_symlink == NULL) {
    994 				error = 0;
    995 				break;
    996 			}
    997 
    998 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    999 			if (buildpath) {
   1000 				error = puffs_path_pcnbuild(pu, &pcn,
   1001 				    preq->preq_cookie);
   1002 				if (error)
   1003 					break;
   1004 			}
   1005 
   1006 			error = pops->puffs_node_symlink(pcc,
   1007 			    preq->preq_cookie, &auxt->pvnr_newnode,
   1008 			    &pcn, &auxt->pvnr_va, auxt->pvnr_link);
   1009 
   1010 			if (buildpath) {
   1011 				if (error) {
   1012 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
   1013 				} else {
   1014 					struct puffs_node *pn;
   1015 
   1016 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
   1017 					pn->pn_po = pcn.pcn_po_full;
   1018 				}
   1019 			}
   1020 
   1021 			break;
   1022 		}
   1023 
   1024 		case PUFFS_VN_READDIR:
   1025 		{
   1026 			struct puffs_vnreq_readdir *auxt = auxbuf;
   1027 			struct dirent *dent;
   1028 			off_t *cookies;
   1029 			size_t res;
   1030 
   1031 			if (pops->puffs_node_readdir == NULL) {
   1032 				error = 0;
   1033 				break;
   1034 			}
   1035 
   1036 			if (auxt->pvnr_ncookies) {
   1037 				/* LINTED: pvnr_data is __aligned() */
   1038 				cookies = (off_t *)auxt->pvnr_data;
   1039 			} else {
   1040 				cookies = NULL;
   1041 			}
   1042 			/* LINTED: dentoff is aligned in the kernel */
   1043 			dent = (struct dirent *)
   1044 			    (auxt->pvnr_data + auxt->pvnr_dentoff);
   1045 
   1046 			res = auxt->pvnr_resid;
   1047 			error = pops->puffs_node_readdir(pcc,
   1048 			    preq->preq_cookie, dent, &auxt->pvnr_offset,
   1049 			    &auxt->pvnr_resid, &auxt->pvnr_cred,
   1050 			    &auxt->pvnr_eofflag, cookies, &auxt->pvnr_ncookies);
   1051 
   1052 			/* need to move a bit more */
   1053 			preq->preq_buflen = sizeof(struct puffs_vnreq_readdir)
   1054 			    + auxt->pvnr_dentoff + (res - auxt->pvnr_resid);
   1055 			break;
   1056 		}
   1057 
   1058 		case PUFFS_VN_READLINK:
   1059 		{
   1060 			struct puffs_vnreq_readlink *auxt = auxbuf;
   1061 			if (pops->puffs_node_readlink == NULL) {
   1062 				error = EOPNOTSUPP;
   1063 				break;
   1064 			}
   1065 
   1066 			error = pops->puffs_node_readlink(pcc,
   1067 			    preq->preq_cookie, &auxt->pvnr_cred,
   1068 			    auxt->pvnr_link, &auxt->pvnr_linklen);
   1069 			break;
   1070 		}
   1071 
   1072 		case PUFFS_VN_RECLAIM:
   1073 		{
   1074 			struct puffs_vnreq_reclaim *auxt = auxbuf;
   1075 			if (pops->puffs_node_reclaim == NULL) {
   1076 				error = 0;
   1077 				break;
   1078 			}
   1079 
   1080 			error = pops->puffs_node_reclaim(pcc,
   1081 			    preq->preq_cookie, auxt->pvnr_pid);
   1082 			break;
   1083 		}
   1084 
   1085 		case PUFFS_VN_INACTIVE:
   1086 		{
   1087 			struct puffs_vnreq_inactive *auxt = auxbuf;
   1088 			if (pops->puffs_node_inactive == NULL) {
   1089 				error = EOPNOTSUPP;
   1090 				break;
   1091 			}
   1092 
   1093 			error = pops->puffs_node_inactive(pcc,
   1094 			    preq->preq_cookie, auxt->pvnr_pid,
   1095 			    &auxt->pvnr_backendrefs);
   1096 			break;
   1097 		}
   1098 
   1099 		case PUFFS_VN_PATHCONF:
   1100 		{
   1101 			struct puffs_vnreq_pathconf *auxt = auxbuf;
   1102 			if (pops->puffs_node_pathconf == NULL) {
   1103 				error = 0;
   1104 				break;
   1105 			}
   1106 
   1107 			error = pops->puffs_node_pathconf(pcc,
   1108 			    preq->preq_cookie, auxt->pvnr_name,
   1109 			    &auxt->pvnr_retval);
   1110 			break;
   1111 		}
   1112 
   1113 		case PUFFS_VN_ADVLOCK:
   1114 		{
   1115 			struct puffs_vnreq_advlock *auxt = auxbuf;
   1116 			if (pops->puffs_node_advlock == NULL) {
   1117 				error = 0;
   1118 				break;
   1119 			}
   1120 
   1121 			error = pops->puffs_node_advlock(pcc,
   1122 			    preq->preq_cookie, auxt->pvnr_id, auxt->pvnr_op,
   1123 			    &auxt->pvnr_fl, auxt->pvnr_flags);
   1124 			break;
   1125 		}
   1126 
   1127 		case PUFFS_VN_PRINT:
   1128 		{
   1129 			if (pops->puffs_node_print == NULL) {
   1130 				error = 0;
   1131 				break;
   1132 			}
   1133 
   1134 			error = pops->puffs_node_print(pcc,
   1135 			    preq->preq_cookie);
   1136 			break;
   1137 		}
   1138 
   1139 		case PUFFS_VN_READ:
   1140 		{
   1141 			struct puffs_vnreq_read *auxt = auxbuf;
   1142 			size_t res;
   1143 
   1144 			if (pops->puffs_node_read == NULL) {
   1145 				error = EIO;
   1146 				break;
   1147 			}
   1148 
   1149 			res = auxt->pvnr_resid;
   1150 			error = pops->puffs_node_read(pcc,
   1151 			    preq->preq_cookie, auxt->pvnr_data,
   1152 			    auxt->pvnr_offset, &auxt->pvnr_resid,
   1153 			    &auxt->pvnr_cred, auxt->pvnr_ioflag);
   1154 
   1155 			/* need to move a bit more */
   1156 			preq->preq_buflen = sizeof(struct puffs_vnreq_read)
   1157 			    + (res - auxt->pvnr_resid);
   1158 			break;
   1159 		}
   1160 
   1161 		case PUFFS_VN_WRITE:
   1162 		{
   1163 			struct puffs_vnreq_write *auxt = auxbuf;
   1164 
   1165 			if (pops->puffs_node_write == NULL) {
   1166 				error = EIO;
   1167 				break;
   1168 			}
   1169 
   1170 			error = pops->puffs_node_write(pcc,
   1171 			    preq->preq_cookie, auxt->pvnr_data,
   1172 			    auxt->pvnr_offset, &auxt->pvnr_resid,
   1173 			    &auxt->pvnr_cred, auxt->pvnr_ioflag);
   1174 
   1175 			/* don't need to move data back to the kernel */
   1176 			preq->preq_buflen = sizeof(struct puffs_vnreq_write);
   1177 			break;
   1178 		}
   1179 
   1180 /* holy bitrot, ryydman! */
   1181 #if 0
   1182 		case PUFFS_VN_IOCTL:
   1183 			error = pops->puffs_node_ioctl1(pcc, preq->preq_cookie,
   1184 			     (struct puffs_vnreq_ioctl *)auxbuf, &pop);
   1185 			if (error != 0)
   1186 				break;
   1187 			pop.pso_reqid = preq->preq_id;
   1188 
   1189 			/* let the kernel do it's intermediate duty */
   1190 			error = ioctl(pu->pu_kargs.pa_fd, PUFFSSIZEOP, &pop);
   1191 			/*
   1192 			 * XXX: I don't actually know what the correct
   1193 			 * thing to do in case of an error is, so I'll
   1194 			 * just ignore it for the time being.
   1195 			 */
   1196 			error = pops->puffs_node_ioctl2(pcc, preq->preq_cookie,
   1197 			    (struct puffs_vnreq_ioctl *)auxbuf, &pop);
   1198 			break;
   1199 
   1200 		case PUFFS_VN_FCNTL:
   1201 			error = pops->puffs_node_fcntl1(pcc, preq->preq_cookie,
   1202 			     (struct puffs_vnreq_fcntl *)auxbuf, &pop);
   1203 			if (error != 0)
   1204 				break;
   1205 			pop.pso_reqid = preq->preq_id;
   1206 
   1207 			/* let the kernel do it's intermediate duty */
   1208 			error = ioctl(pu->pu_kargs.pa_fd, PUFFSSIZEOP, &pop);
   1209 			/*
   1210 			 * XXX: I don't actually know what the correct
   1211 			 * thing to do in case of an error is, so I'll
   1212 			 * just ignore it for the time being.
   1213 			 */
   1214 			error = pops->puffs_node_fcntl2(pcc, preq->preq_cookie,
   1215 			    (struct puffs_vnreq_fcntl *)auxbuf, &pop);
   1216 			break;
   1217 #endif
   1218 
   1219 		default:
   1220 			printf("inval op %d\n", preq->preq_optype);
   1221 			error = EINVAL;
   1222 			break;
   1223 		}
   1224 	} else {
   1225 		/*
   1226 		 * this one also
   1227 		 */
   1228 		error = EINVAL;
   1229 	}
   1230 
   1231 	preq->preq_rv = error;
   1232 
   1233 	pcc->pcc_rv = rv;
   1234 	pcc->pcc_flags |= PCC_DONE;
   1235 }
   1236 
   1237 
   1238 #if 0
   1239 		case PUFFS_VN_POLL:
   1240 		{
   1241 			struct puffs_vnreq_poll *auxt = auxbuf;
   1242 			if (pops->puffs_node_poll == NULL) {
   1243 				error = 0;
   1244 				break;
   1245 			}
   1246 
   1247 			error = pops->puffs_node_poll(pcc,
   1248 			    preq->preq_cookie, preq-);
   1249 			break;
   1250 		}
   1251 
   1252 		case PUFFS_VN_KQFILTER:
   1253 		{
   1254 			struct puffs_vnreq_kqfilter *auxt = auxbuf;
   1255 			if (pops->puffs_node_kqfilter == NULL) {
   1256 				error = 0;
   1257 				break;
   1258 			}
   1259 
   1260 			error = pops->puffs_node_kqfilter(pcc,
   1261 			    preq->preq_cookie, );
   1262 			break;
   1263 		}
   1264 
   1265 		case PUFFS_VN_CLOSEEXTATTR:
   1266 		{
   1267 			struct puffs_vnreq_closeextattr *auxt = auxbuf;
   1268 			if (pops->puffs_closeextattr == NULL) {
   1269 				error = 0;
   1270 				break;
   1271 			}
   1272 
   1273 			error = pops->puffs_closeextattr(pcc,
   1274 			    preq->preq_cookie, );
   1275 			break;
   1276 		}
   1277 
   1278 		case PUFFS_VN_GETEXTATTR:
   1279 		{
   1280 			struct puffs_vnreq_getextattr *auxt = auxbuf;
   1281 			if (pops->puffs_getextattr == NULL) {
   1282 				error = 0;
   1283 				break;
   1284 			}
   1285 
   1286 			error = pops->puffs_getextattr(pcc,
   1287 			    preq->preq_cookie, );
   1288 			break;
   1289 		}
   1290 
   1291 		case PUFFS_VN_LISTEXTATTR:
   1292 		{
   1293 			struct puffs_vnreq_listextattr *auxt = auxbuf;
   1294 			if (pops->puffs_listextattr == NULL) {
   1295 				error = 0;
   1296 				break;
   1297 			}
   1298 
   1299 			error = pops->puffs_listextattr(pcc,
   1300 			    preq->preq_cookie, );
   1301 			break;
   1302 		}
   1303 
   1304 		case PUFFS_VN_OPENEXTATTR:
   1305 		{
   1306 			struct puffs_vnreq_openextattr *auxt = auxbuf;
   1307 			if (pops->puffs_openextattr == NULL) {
   1308 				error = 0;
   1309 				break;
   1310 			}
   1311 
   1312 			error = pops->puffs_openextattr(pcc,
   1313 			    preq->preq_cookie, );
   1314 			break;
   1315 		}
   1316 
   1317 		case PUFFS_VN_DELETEEXTATTR:
   1318 		{
   1319 			struct puffs_vnreq_deleteextattr *auxt = auxbuf;
   1320 			if (pops->puffs_deleteextattr == NULL) {
   1321 				error = 0;
   1322 				break;
   1323 			}
   1324 
   1325 			error = pops->puffs_deleteextattr(pcc,
   1326 			    preq->preq_cookie, );
   1327 			break;
   1328 		}
   1329 
   1330 		case PUFFS_VN_SETEXTATTR:
   1331 		{
   1332 			struct puffs_vnreq_setextattr *auxt = auxbuf;
   1333 			if (pops->puffs_setextattr == NULL) {
   1334 				error = 0;
   1335 				break;
   1336 			}
   1337 
   1338 			error = pops->puffs_setextattr(pcc,
   1339 			    preq->preq_cookie, );
   1340 			break;
   1341 		}
   1342 
   1343 #endif
   1344