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