Home | History | Annotate | Line # | Download | only in libpuffs
puffs.c revision 1.17
      1 /*	$NetBSD: puffs.c,v 1.17 2006/12/07 23:15:20 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.17 2006/12/07 23:15:20 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 <puffs.h>
     48 #include <puffsdump.h>
     49 #include <stdio.h>
     50 #include <stdlib.h>
     51 #include <string.h>
     52 #include <syslog.h>
     53 #include <unistd.h>
     54 
     55 static int puffcall(struct puffs_usermount *, struct puffs_req *, size_t *);
     56 
     57 #define FILLOP(lower, upper)						\
     58 do {									\
     59 	if (pops->puffs_node_##lower)					\
     60 		opmask[PUFFS_VN_##upper] = 1;				\
     61 } while (/*CONSTCOND*/0)
     62 static void
     63 fillvnopmask(struct puffs_ops *pops, uint8_t *opmask)
     64 {
     65 
     66 	memset(opmask, 0, PUFFS_VN_MAX);
     67 
     68 	FILLOP(create,   CREATE);
     69 	FILLOP(mknod,    MKNOD);
     70 	FILLOP(open,     OPEN);
     71 	FILLOP(close,    CLOSE);
     72 	FILLOP(access,   ACCESS);
     73 	FILLOP(getattr,  GETATTR);
     74 	FILLOP(setattr,  SETATTR);
     75 	FILLOP(poll,     POLL); /* XXX: not ready in kernel */
     76 	FILLOP(revoke,   REVOKE);
     77 	FILLOP(mmap,     MMAP);
     78 	FILLOP(fsync,    FSYNC);
     79 	FILLOP(seek,     SEEK);
     80 	FILLOP(remove,   REMOVE);
     81 	FILLOP(link,     LINK);
     82 	FILLOP(rename,   RENAME);
     83 	FILLOP(mkdir,    MKDIR);
     84 	FILLOP(rmdir,    RMDIR);
     85 	FILLOP(symlink,  SYMLINK);
     86 	FILLOP(readdir,  READDIR);
     87 	FILLOP(readlink, READLINK);
     88 	FILLOP(reclaim,  RECLAIM);
     89 	FILLOP(inactive, INACTIVE);
     90 	FILLOP(print,    PRINT);
     91 	FILLOP(read,     READ);
     92 	FILLOP(write,    WRITE);
     93 
     94 	/* XXX: not implemented in the kernel */
     95 	FILLOP(getextattr, GETEXTATTR);
     96 	FILLOP(setextattr, SETEXTATTR);
     97 	FILLOP(listextattr, LISTEXTATTR);
     98 
     99 	/* XXX */
    100 	FILLOP(ioctl1, IOCTL);
    101 	FILLOP(fcntl1, FCNTL);
    102 }
    103 #undef FILLOP
    104 
    105 struct puffs_usermount *
    106 puffs_mount(struct puffs_ops *pops, const char *dir, int mntflags,
    107 	const char *puffsname, uint32_t pflags, size_t maxreqlen)
    108 {
    109 	struct puffs_startreq sreq;
    110 	struct puffs_args pargs;
    111 	struct puffs_usermount *pu;
    112 	int fd = 0, rv;
    113 
    114 	if (pops->puffs_fs_mount == NULL) {
    115 		errno = EINVAL;
    116 		return NULL;
    117 	}
    118 
    119 	fd = open("/dev/puffs", O_RDONLY);
    120 	if (fd == -1)
    121 		return NULL;
    122 	if (fd <= 2)
    123 		warnx("puffs_mount: device fd %d (<= 2), sure this is "
    124 		    "what you want?", fd);
    125 
    126 	pargs.pa_vers = 0; /* XXX: for now */
    127 	pargs.pa_flags = PUFFS_FLAG_KERN(pflags);
    128 	pargs.pa_fd = fd;
    129 	pargs.pa_maxreqlen = maxreqlen;
    130 	fillvnopmask(pops, pargs.pa_vnopmask);
    131 	(void)strlcpy(pargs.pa_name, puffsname, sizeof(pargs.pa_name));
    132 
    133 	pu = malloc(sizeof(struct puffs_usermount));
    134 	if (!pu)
    135 		return NULL;
    136 
    137 	pu->pu_flags = pflags;
    138 	pu->pu_ops = *pops;
    139 	pu->pu_fd = fd;
    140 	if ((pu->pu_rootpath = strdup(dir)) == NULL)
    141 		goto failfree;
    142 	LIST_INIT(&pu->pu_pnodelst);
    143 
    144 	if (mount(MOUNT_PUFFS, dir, mntflags, &pargs) == -1)
    145 		goto failfree;
    146 	pu->pu_maxreqlen = pargs.pa_maxreqlen;
    147 
    148 	if ((rv = pops->puffs_fs_mount(pu, &sreq.psr_cookie)) != 0) {
    149 		errno = rv;
    150 		goto failfree;
    151 	}
    152 
    153 	if ((rv = pops->puffs_fs_statvfs(pu, &sreq.psr_sb, 0)) != 0) {
    154 		errno = rv;
    155 		goto failfree;
    156 	}
    157 
    158 	/* tell kernel we're flying */
    159 	if (ioctl(pu->pu_fd, PUFFSSTARTOP, &sreq) == -1)
    160 		goto failfree;
    161 
    162 	return pu;
    163 
    164  failfree:
    165 	/* can't unmount() from here for obvious reasons */
    166 	if (fd)
    167 		close(fd);
    168 	free(pu);
    169 	return NULL;
    170 }
    171 
    172 int
    173 puffs_mainloop(struct puffs_usermount *pu, int flags)
    174 {
    175 	uint8_t *buf;
    176 	int rv;
    177 
    178 	buf = malloc(pu->pu_maxreqlen);
    179 	if (!buf)
    180 		return -1;
    181 
    182 	if ((flags & PUFFSLOOP_NODAEMON) == 0)
    183 		if (daemon(0, 0) == -1)
    184 			return -1;
    185 
    186 	for (;;)
    187 		if ((rv = puffs_oneop(pu, buf, pu->pu_maxreqlen)) != 0)
    188 			return rv;
    189 }
    190 
    191 enum {PUFFCALL_ANSWER, PUFFCALL_IGNORE, PUFFCALL_UNMOUNT};
    192 int
    193 puffs_oneop(struct puffs_usermount *pu, uint8_t *buf, size_t buflen)
    194 {
    195 	struct puffs_getreq *pgr;
    196 	struct puffs_putreq *ppr;
    197 	struct puffs_req *preq;
    198 	int rv, unmounting, pval;
    199 
    200 	rv = unmounting = 0;
    201 
    202 	/* setup fetch */
    203 	pgr = puffs_makegetreq(pu, buf, buflen, 0);
    204 	if (!pgr)
    205 		return -1;
    206 
    207 	/* setup reply essentials */
    208 	ppr = puffs_makeputreq(pu);
    209 	if (!ppr) {
    210 		puffs_destroygetreq(pgr);
    211 		return -1;
    212 	}
    213 
    214 	while ((preq = puffs_getreq(pgr)) != NULL && unmounting == 0) {
    215 		pval = puffcall(pu, preq, &preq->preq_buflen);
    216 
    217 		/* check if we need to store this reply */
    218 		switch (pval) {
    219 		case PUFFCALL_UNMOUNT:
    220 			unmounting = 1;
    221 			/* FALLTHROUGH */
    222 		case PUFFCALL_ANSWER:
    223 			puffs_putreq(ppr, preq);
    224 			break;
    225 		case PUFFCALL_IGNORE:
    226 			break;
    227 
    228 		default:
    229 			assert(/*CONSTCOND*/0);
    230 		}
    231 	}
    232 	puffs_destroygetreq(pgr);
    233 
    234 	if (puffs_putputreq(ppr) == -1)
    235 		rv = -1;
    236 	puffs_destroyputreq(ppr);
    237 
    238 	return rv;
    239 }
    240 
    241 int
    242 puffs_getselectable(struct puffs_usermount *pu)
    243 {
    244 
    245 	return pu->pu_fd;
    246 }
    247 
    248 int
    249 puffs_setblockingmode(struct puffs_usermount *pu, int mode)
    250 {
    251 	int x;
    252 
    253 	x = mode;
    254 	return ioctl(pu->pu_fd, FIONBIO, &x);
    255 }
    256 
    257 static int
    258 puffcall(struct puffs_usermount *pu, struct puffs_req *preq, size_t *blenp)
    259 {
    260 	struct puffs_ops *pops = &pu->pu_ops;
    261 	struct puffs_sizeop pop;
    262 	void *auxbuf;
    263 	int error, rv;
    264 
    265 	if (PUFFSOP_WANTREPLY(preq->preq_opclass))
    266 		rv = PUFFCALL_ANSWER;
    267 	else
    268 		rv = PUFFCALL_IGNORE;
    269 	auxbuf = preq;
    270 
    271 	if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
    272 		puffsdump_req(preq);
    273 
    274 	*blenp = 0; /* default: "let kernel decide" */
    275 
    276 	if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) {
    277 		switch (preq->preq_optype) {
    278 		case PUFFS_VFS_UNMOUNT:
    279 		{
    280 			struct puffs_vfsreq_unmount *auxt = auxbuf;
    281 
    282 			error = pops->puffs_fs_unmount(pu,
    283 			    auxt->pvfsr_flags, auxt->pvfsr_pid);
    284 			rv = PUFFCALL_UNMOUNT;
    285 			break;
    286 		}
    287 		case PUFFS_VFS_STATVFS:
    288 		{
    289 			struct puffs_vfsreq_statvfs *auxt = auxbuf;
    290 
    291 			error = pops->puffs_fs_statvfs(pu,
    292 			    &auxt->pvfsr_sb, auxt->pvfsr_pid);
    293 			break;
    294 		}
    295 		case PUFFS_VFS_SYNC:
    296 		{
    297 			struct puffs_vfsreq_sync *auxt = auxbuf;
    298 
    299 			error = pops->puffs_fs_sync(pu,
    300 			    auxt->pvfsr_waitfor, &auxt->pvfsr_cred,
    301 			    auxt->pvfsr_pid);
    302 			break;
    303 		}
    304 		default:
    305 			/*
    306 			 * I guess the kernel sees this one coming
    307 			 */
    308 			error = EINVAL;
    309 			break;
    310 		}
    311 
    312 	/* XXX: audit return values */
    313 	/* XXX: sync with kernel */
    314 	} else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) {
    315 		switch (preq->preq_optype) {
    316 		case PUFFS_VN_LOOKUP:
    317 		{
    318 			struct puffs_vnreq_lookup *auxt = auxbuf;
    319 
    320 			/* lookup *must* be present */
    321 			error = pops->puffs_node_lookup(pu, preq->preq_cookie,
    322 			    &auxt->pvnr_newnode, &auxt->pvnr_vtype,
    323 			    &auxt->pvnr_size, &auxt->pvnr_rdev,
    324 			    &auxt->pvnr_cn);
    325 			break;
    326 		}
    327 
    328 		case PUFFS_VN_CREATE:
    329 		{
    330 			struct puffs_vnreq_create *auxt = auxbuf;
    331 			if (pops->puffs_node_create == NULL) {
    332 				error = 0;
    333 				break;
    334 			}
    335 
    336 			error = pops->puffs_node_create(pu,
    337 			    preq->preq_cookie, &auxt->pvnr_newnode,
    338 			    &auxt->pvnr_cn, &auxt->pvnr_va);
    339 			break;
    340 		}
    341 
    342 		case PUFFS_VN_MKNOD:
    343 		{
    344 			struct puffs_vnreq_mknod *auxt = auxbuf;
    345 			if (pops->puffs_node_mknod == NULL) {
    346 				error = 0;
    347 				break;
    348 			}
    349 
    350 			error = pops->puffs_node_mknod(pu,
    351 			    preq->preq_cookie, &auxt->pvnr_newnode,
    352 			    &auxt->pvnr_cn, &auxt->pvnr_va);
    353 			break;
    354 		}
    355 
    356 		case PUFFS_VN_OPEN:
    357 		{
    358 			struct puffs_vnreq_open *auxt = auxbuf;
    359 			if (pops->puffs_node_open == NULL) {
    360 				error = 0;
    361 				break;
    362 			}
    363 
    364 			error = pops->puffs_node_open(pu,
    365 			    preq->preq_cookie, auxt->pvnr_mode,
    366 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    367 			break;
    368 		}
    369 
    370 		case PUFFS_VN_CLOSE:
    371 		{
    372 			struct puffs_vnreq_close *auxt = auxbuf;
    373 			if (pops->puffs_node_close == NULL) {
    374 				error = 0;
    375 				break;
    376 			}
    377 
    378 			error = pops->puffs_node_close(pu,
    379 			    preq->preq_cookie, auxt->pvnr_fflag,
    380 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    381 			break;
    382 		}
    383 
    384 		case PUFFS_VN_ACCESS:
    385 		{
    386 			struct puffs_vnreq_access *auxt = auxbuf;
    387 			if (pops->puffs_node_access == NULL) {
    388 				error = 0;
    389 				break;
    390 			}
    391 
    392 			error = pops->puffs_node_access(pu,
    393 			    preq->preq_cookie, auxt->pvnr_mode,
    394 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    395 			break;
    396 		}
    397 
    398 		case PUFFS_VN_GETATTR:
    399 		{
    400 			struct puffs_vnreq_getattr *auxt = auxbuf;
    401 			if (pops->puffs_node_getattr == NULL) {
    402 				error = EOPNOTSUPP;
    403 				break;
    404 			}
    405 
    406 			error = pops->puffs_node_getattr(pu,
    407 			    preq->preq_cookie, &auxt->pvnr_va,
    408 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    409 			break;
    410 		}
    411 
    412 		case PUFFS_VN_SETATTR:
    413 		{
    414 			struct puffs_vnreq_setattr *auxt = auxbuf;
    415 			if (pops->puffs_node_setattr == NULL) {
    416 				error = EOPNOTSUPP;
    417 				break;
    418 			}
    419 
    420 			error = pops->puffs_node_setattr(pu,
    421 			    preq->preq_cookie, &auxt->pvnr_va,
    422 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    423 			break;
    424 		}
    425 
    426 		case PUFFS_VN_MMAP:
    427 		{
    428 			struct puffs_vnreq_mmap *auxt = auxbuf;
    429 			if (pops->puffs_node_mmap == NULL) {
    430 				error = 0;
    431 				break;
    432 			}
    433 
    434 			error = pops->puffs_node_mmap(pu,
    435 			    preq->preq_cookie, auxt->pvnr_fflags,
    436 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    437 			break;
    438 		}
    439 
    440 		case PUFFS_VN_REVOKE:
    441 		{
    442 			struct puffs_vnreq_revoke *auxt = auxbuf;
    443 			if (pops->puffs_node_revoke == NULL) {
    444 				error = 0;
    445 				break;
    446 			}
    447 
    448 			error = pops->puffs_node_revoke(pu,
    449 			    preq->preq_cookie, auxt->pvnr_flags);
    450 			break;
    451 		}
    452 
    453 		case PUFFS_VN_FSYNC:
    454 		{
    455 			struct puffs_vnreq_fsync *auxt = auxbuf;
    456 			if (pops->puffs_node_fsync == NULL) {
    457 				error = 0;
    458 				break;
    459 			}
    460 
    461 			error = pops->puffs_node_fsync(pu,
    462 			    preq->preq_cookie, &auxt->pvnr_cred,
    463 			    auxt->pvnr_flags, auxt->pvnr_offlo,
    464 			    auxt->pvnr_offhi, auxt->pvnr_pid);
    465 			break;
    466 		}
    467 
    468 		case PUFFS_VN_SEEK:
    469 		{
    470 			struct puffs_vnreq_seek *auxt = auxbuf;
    471 			if (pops->puffs_node_seek == NULL) {
    472 				error = 0;
    473 				break;
    474 			}
    475 
    476 			error = pops->puffs_node_seek(pu,
    477 			    preq->preq_cookie, auxt->pvnr_oldoff,
    478 			    auxt->pvnr_newoff, &auxt->pvnr_cred);
    479 			break;
    480 		}
    481 
    482 		case PUFFS_VN_REMOVE:
    483 		{
    484 			struct puffs_vnreq_remove *auxt = auxbuf;
    485 			if (pops->puffs_node_remove == NULL) {
    486 				error = 0;
    487 				break;
    488 			}
    489 
    490 			error = pops->puffs_node_remove(pu,
    491 			    preq->preq_cookie, auxt->pvnr_cookie_targ,
    492 			    &auxt->pvnr_cn);
    493 			break;
    494 		}
    495 
    496 		case PUFFS_VN_LINK:
    497 		{
    498 			struct puffs_vnreq_link *auxt = auxbuf;
    499 			if (pops->puffs_node_link == NULL) {
    500 				error = 0;
    501 				break;
    502 			}
    503 
    504 			error = pops->puffs_node_link(pu,
    505 			    preq->preq_cookie, auxt->pvnr_cookie_targ,
    506 			    &auxt->pvnr_cn);
    507 			break;
    508 		}
    509 
    510 		case PUFFS_VN_RENAME:
    511 		{
    512 			struct puffs_vnreq_rename *auxt = auxbuf;
    513 			if (pops->puffs_node_rename == NULL) {
    514 				error = 0;
    515 				break;
    516 			}
    517 
    518 			error = pops->puffs_node_rename(pu,
    519 			    preq->preq_cookie, auxt->pvnr_cookie_src,
    520 			    &auxt->pvnr_cn_src, auxt->pvnr_cookie_targdir,
    521 			    auxt->pvnr_cookie_targ, &auxt->pvnr_cn_targ);
    522 			break;
    523 		}
    524 
    525 		case PUFFS_VN_MKDIR:
    526 		{
    527 			struct puffs_vnreq_mkdir *auxt = auxbuf;
    528 			if (pops->puffs_node_mkdir == NULL) {
    529 				error = 0;
    530 				break;
    531 			}
    532 
    533 			error = pops->puffs_node_mkdir(pu,
    534 			    preq->preq_cookie, &auxt->pvnr_newnode,
    535 			    &auxt->pvnr_cn, &auxt->pvnr_va);
    536 			break;
    537 		}
    538 
    539 		case PUFFS_VN_RMDIR:
    540 		{
    541 			struct puffs_vnreq_rmdir *auxt = auxbuf;
    542 			if (pops->puffs_node_rmdir == NULL) {
    543 				error = 0;
    544 				break;
    545 			}
    546 
    547 			error = pops->puffs_node_rmdir(pu,
    548 			    preq->preq_cookie, auxt->pvnr_cookie_targ,
    549 			    &auxt->pvnr_cn);
    550 			break;
    551 		}
    552 
    553 		case PUFFS_VN_SYMLINK:
    554 		{
    555 			struct puffs_vnreq_symlink *auxt = auxbuf;
    556 			if (pops->puffs_node_symlink == NULL) {
    557 				error = 0;
    558 				break;
    559 			}
    560 
    561 			error = pops->puffs_node_symlink(pu,
    562 			    preq->preq_cookie, &auxt->pvnr_newnode,
    563 			    &auxt->pvnr_cn, &auxt->pvnr_va, auxt->pvnr_link);
    564 			break;
    565 		}
    566 
    567 		case PUFFS_VN_READDIR:
    568 		{
    569 			struct puffs_vnreq_readdir *auxt = auxbuf;
    570 			size_t res;
    571 
    572 			if (pops->puffs_node_readdir == NULL) {
    573 				error = 0;
    574 				break;
    575 			}
    576 
    577 			res = auxt->pvnr_resid;
    578 			error = pops->puffs_node_readdir(pu,
    579 			    preq->preq_cookie, auxt->pvnr_dent,
    580 			    &auxt->pvnr_cred, &auxt->pvnr_offset,
    581 			    &auxt->pvnr_resid);
    582 
    583 			/* need to move a bit more */
    584 			*blenp = sizeof(struct puffs_vnreq_readdir)
    585 			    + (res - auxt->pvnr_resid);
    586 			break;
    587 		}
    588 
    589 		case PUFFS_VN_READLINK:
    590 		{
    591 			struct puffs_vnreq_readlink *auxt = auxbuf;
    592 			if (pops->puffs_node_readlink == NULL) {
    593 				error = EOPNOTSUPP;
    594 				break;
    595 			}
    596 
    597 			error = pops->puffs_node_readlink(pu,
    598 			    preq->preq_cookie, &auxt->pvnr_cred,
    599 			    auxt->pvnr_link, &auxt->pvnr_linklen);
    600 			break;
    601 		}
    602 
    603 		case PUFFS_VN_RECLAIM:
    604 		{
    605 			struct puffs_vnreq_reclaim *auxt = auxbuf;
    606 			if (pops->puffs_node_reclaim == NULL) {
    607 				error = 0;
    608 				break;
    609 			}
    610 
    611 			error = pops->puffs_node_reclaim(pu,
    612 			    preq->preq_cookie, auxt->pvnr_pid);
    613 			break;
    614 		}
    615 
    616 		case PUFFS_VN_INACTIVE:
    617 		{
    618 			struct puffs_vnreq_inactive *auxt = auxbuf;
    619 			if (pops->puffs_node_inactive == NULL) {
    620 				error = EOPNOTSUPP;
    621 				break;
    622 			}
    623 
    624 			error = pops->puffs_node_inactive(pu,
    625 			    preq->preq_cookie, auxt->pvnr_pid,
    626 			    &auxt->pvnr_backendrefs);
    627 			break;
    628 		}
    629 
    630 		case PUFFS_VN_PATHCONF:
    631 		{
    632 			struct puffs_vnreq_pathconf *auxt = auxbuf;
    633 			if (pops->puffs_node_pathconf == NULL) {
    634 				error = 0;
    635 				break;
    636 			}
    637 
    638 			error = pops->puffs_node_pathconf(pu,
    639 			    preq->preq_cookie, auxt->pvnr_name,
    640 			    &auxt->pvnr_retval);
    641 			break;
    642 		}
    643 
    644 		case PUFFS_VN_ADVLOCK:
    645 		{
    646 			struct puffs_vnreq_advlock *auxt = auxbuf;
    647 			if (pops->puffs_node_advlock == NULL) {
    648 				error = 0;
    649 				break;
    650 			}
    651 
    652 			error = pops->puffs_node_advlock(pu,
    653 			    preq->preq_cookie, auxt->pvnr_id, auxt->pvnr_op,
    654 			    &auxt->pvnr_fl, auxt->pvnr_flags);
    655 			break;
    656 		}
    657 
    658 		case PUFFS_VN_PRINT:
    659 		{
    660 			if (pops->puffs_node_print == NULL) {
    661 				error = 0;
    662 				break;
    663 			}
    664 
    665 			error = pops->puffs_node_print(pu,
    666 			    preq->preq_cookie);
    667 			break;
    668 		}
    669 
    670 		case PUFFS_VN_READ:
    671 		{
    672 			struct puffs_vnreq_read *auxt = auxbuf;
    673 			size_t res;
    674 
    675 			if (pops->puffs_node_read == NULL) {
    676 				error = EIO;
    677 				break;
    678 			}
    679 
    680 			res = auxt->pvnr_resid;
    681 			error = pops->puffs_node_read(pu,
    682 			    preq->preq_cookie, auxt->pvnr_data,
    683 			    auxt->pvnr_offset, &auxt->pvnr_resid,
    684 			    &auxt->pvnr_cred, auxt->pvnr_ioflag);
    685 
    686 			/* need to move a bit more */
    687 			*blenp = sizeof(struct puffs_vnreq_read)
    688 			    + (res - auxt->pvnr_resid);
    689 			break;
    690 		}
    691 
    692 		case PUFFS_VN_WRITE:
    693 		{
    694 			struct puffs_vnreq_write *auxt = auxbuf;
    695 
    696 			if (pops->puffs_node_write == NULL) {
    697 				error = EIO;
    698 				break;
    699 			}
    700 
    701 			error = pops->puffs_node_write(pu,
    702 			    preq->preq_cookie, auxt->pvnr_data,
    703 			    auxt->pvnr_offset, &auxt->pvnr_resid,
    704 			    &auxt->pvnr_cred, auxt->pvnr_ioflag);
    705 
    706 			/* don't need to move data back to the kernel */
    707 			*blenp = sizeof(struct puffs_vnreq_write);
    708 			break;
    709 		}
    710 
    711 		case PUFFS_VN_IOCTL:
    712 			error = pops->puffs_node_ioctl1(pu, preq->preq_cookie,
    713 			     (struct puffs_vnreq_ioctl *)auxbuf, &pop);
    714 			if (error != 0)
    715 				break;
    716 			pop.pso_reqid = preq->preq_id;
    717 
    718 			/* let the kernel do it's intermediate duty */
    719 			error = ioctl(pu->pu_fd, PUFFSSIZEOP, &pop);
    720 			/*
    721 			 * XXX: I don't actually know what the correct
    722 			 * thing to do in case of an error is, so I'll
    723 			 * just ignore it for the time being.
    724 			 */
    725 			error = pops->puffs_node_ioctl2(pu, preq->preq_cookie,
    726 			    (struct puffs_vnreq_ioctl *)auxbuf, &pop);
    727 			break;
    728 
    729 		case PUFFS_VN_FCNTL:
    730 			error = pops->puffs_node_fcntl1(pu, preq->preq_cookie,
    731 			     (struct puffs_vnreq_fcntl *)auxbuf, &pop);
    732 			if (error != 0)
    733 				break;
    734 			pop.pso_reqid = preq->preq_id;
    735 
    736 			/* let the kernel do it's intermediate duty */
    737 			error = ioctl(pu->pu_fd, PUFFSSIZEOP, &pop);
    738 			/*
    739 			 * XXX: I don't actually know what the correct
    740 			 * thing to do in case of an error is, so I'll
    741 			 * just ignore it for the time being.
    742 			 */
    743 			error = pops->puffs_node_fcntl2(pu, preq->preq_cookie,
    744 			    (struct puffs_vnreq_fcntl *)auxbuf, &pop);
    745 			break;
    746 
    747 		default:
    748 			printf("inval op %d\n", preq->preq_optype);
    749 			error = EINVAL;
    750 			break;
    751 		}
    752 	} else {
    753 		/*
    754 		 * this one also
    755 		 */
    756 		error = EINVAL;
    757 	}
    758 
    759 	preq->preq_rv = error;
    760 	return rv;
    761 }
    762 
    763 
    764 #if 0
    765 		case PUFFS_VN_POLL:
    766 		{
    767 			struct puffs_vnreq_poll *auxt = auxbuf;
    768 			if (pops->puffs_node_poll == NULL) {
    769 				error = 0;
    770 				break;
    771 			}
    772 
    773 			error = pops->puffs_node_poll(pu,
    774 			    preq->preq_cookie, preq-);
    775 			break;
    776 		}
    777 
    778 		case PUFFS_VN_KQFILTER:
    779 		{
    780 			struct puffs_vnreq_kqfilter *auxt = auxbuf;
    781 			if (pops->puffs_node_kqfilter == NULL) {
    782 				error = 0;
    783 				break;
    784 			}
    785 
    786 			error = pops->puffs_node_kqfilter(pu,
    787 			    preq->preq_cookie, );
    788 			break;
    789 		}
    790 
    791 		case PUFFS_VN_CLOSEEXTATTR:
    792 		{
    793 			struct puffs_vnreq_closeextattr *auxt = auxbuf;
    794 			if (pops->puffs_closeextattr == NULL) {
    795 				error = 0;
    796 				break;
    797 			}
    798 
    799 			error = pops->puffs_closeextattr(pu,
    800 			    preq->preq_cookie, );
    801 			break;
    802 		}
    803 
    804 		case PUFFS_VN_GETEXTATTR:
    805 		{
    806 			struct puffs_vnreq_getextattr *auxt = auxbuf;
    807 			if (pops->puffs_getextattr == NULL) {
    808 				error = 0;
    809 				break;
    810 			}
    811 
    812 			error = pops->puffs_getextattr(pu,
    813 			    preq->preq_cookie, );
    814 			break;
    815 		}
    816 
    817 		case PUFFS_VN_LISTEXTATTR:
    818 		{
    819 			struct puffs_vnreq_listextattr *auxt = auxbuf;
    820 			if (pops->puffs_listextattr == NULL) {
    821 				error = 0;
    822 				break;
    823 			}
    824 
    825 			error = pops->puffs_listextattr(pu,
    826 			    preq->preq_cookie, );
    827 			break;
    828 		}
    829 
    830 		case PUFFS_VN_OPENEXTATTR:
    831 		{
    832 			struct puffs_vnreq_openextattr *auxt = auxbuf;
    833 			if (pops->puffs_openextattr == NULL) {
    834 				error = 0;
    835 				break;
    836 			}
    837 
    838 			error = pops->puffs_openextattr(pu,
    839 			    preq->preq_cookie, );
    840 			break;
    841 		}
    842 
    843 		case PUFFS_VN_DELETEEXTATTR:
    844 		{
    845 			struct puffs_vnreq_deleteextattr *auxt = auxbuf;
    846 			if (pops->puffs_deleteextattr == NULL) {
    847 				error = 0;
    848 				break;
    849 			}
    850 
    851 			error = pops->puffs_deleteextattr(pu,
    852 			    preq->preq_cookie, );
    853 			break;
    854 		}
    855 
    856 		case PUFFS_VN_SETEXTATTR:
    857 		{
    858 			struct puffs_vnreq_setextattr *auxt = auxbuf;
    859 			if (pops->puffs_setextattr == NULL) {
    860 				error = 0;
    861 				break;
    862 			}
    863 
    864 			error = pops->puffs_setextattr(pu,
    865 			    preq->preq_cookie, );
    866 			break;
    867 		}
    868 
    869 #endif
    870