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