Home | History | Annotate | Line # | Download | only in libpuffs
puffs.c revision 1.14
      1 /*	$NetBSD: puffs.c,v 1.14 2006/12/07 16:13:51 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.14 2006/12/07 16:13:51 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); /* 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_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_reqh_get phg;
    196 	struct puffs_reqh_put php;
    197 	struct puffs_req *preq;
    198 	uint64_t *resp_idp;
    199 	void **resp_bufp;
    200 	size_t handler_blen, *resp_blenp;
    201 	int rv, unmounting = 0;
    202 
    203 	/* setup fetch */
    204 	phg.phg_buf = buf;
    205 	phg.phg_buflen = buflen;
    206 	phg.phg_nops = 0;
    207 
    208 	/* setup reply essentials */
    209 	php.php_nops = 0;
    210 	resp_bufp = &php.php_buf;
    211 	resp_blenp = &php.php_buflen;
    212 	resp_idp = &php.php_id;
    213 
    214 	/* get op from kernel */
    215 	if (ioctl(pu->pu_fd, PUFFSGETOP, &phg) == -1)
    216 		return -1;
    217 	preq = phg.phg_buf;
    218 
    219 	while (phg.phg_nops-- && unmounting == 0) {
    220 		/* deal with it */
    221 		handler_blen = preq->preq_buflen;
    222 		rv = puffcall(pu, preq, &handler_blen);
    223 
    224 		/* check if we need to store this reply */
    225 		switch (rv) {
    226 		case PUFFCALL_UNMOUNT:
    227 			unmounting = 1;
    228 			/* FALLTHROUGH */
    229 		case PUFFCALL_ANSWER:
    230 			php.php_nops++;
    231 
    232 			/* store data */
    233 			*resp_bufp = preq;
    234 			*resp_blenp = handler_blen;
    235 			*resp_idp = preq->preq_id;
    236 
    237 			/* and roll pointers forward */
    238 			resp_bufp = &preq->preq_nextbuf;
    239 			resp_blenp = &preq->preq_buflen;
    240 			resp_idp = &preq->preq_id;
    241 
    242 			break;
    243 		case PUFFCALL_IGNORE:
    244 			break;
    245 
    246 		default:
    247 			return -1;
    248 		}
    249 
    250 		/* roll buffer forward */
    251 		/* LINTED */
    252 		preq = (struct puffs_req *)((uint8_t *)preq+preq->preq_buflen);
    253 	}
    254 
    255 	if (php.php_nops)
    256 		if (ioctl(pu->pu_fd, PUFFSPUTOP, &php) == -1)
    257 			return -1;
    258 
    259 	return 0;
    260 }
    261 
    262 int
    263 puffs_getselectable(struct puffs_usermount *pu)
    264 {
    265 
    266 	return pu->pu_fd;
    267 }
    268 
    269 int
    270 puffs_setblockingmode(struct puffs_usermount *pu, int mode)
    271 {
    272 	int x;
    273 
    274 	x = mode;
    275 	return ioctl(pu->pu_fd, FIONBIO, &x);
    276 }
    277 
    278 static int
    279 puffcall(struct puffs_usermount *pu, struct puffs_req *preq, size_t *blenp)
    280 {
    281 	struct puffs_ops *pops = &pu->pu_ops;
    282 	struct puffs_sizeop pop;
    283 	void *auxbuf;
    284 	int error, rv;
    285 
    286 	if (PUFFSOP_WANTREPLY(preq->preq_opclass))
    287 		rv = PUFFCALL_ANSWER;
    288 	else
    289 		rv = PUFFCALL_IGNORE;
    290 	auxbuf = preq;
    291 
    292 	if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
    293 		puffsdump_req(preq);
    294 
    295 	*blenp = 0; /* default: "let kernel decide" */
    296 
    297 	if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) {
    298 		switch (preq->preq_optype) {
    299 		case PUFFS_VFS_UNMOUNT:
    300 		{
    301 			struct puffs_vfsreq_unmount *auxt = auxbuf;
    302 
    303 			error = pops->puffs_fs_unmount(pu,
    304 			    auxt->pvfsr_flags, auxt->pvfsr_pid);
    305 			rv = PUFFCALL_UNMOUNT;
    306 			break;
    307 		}
    308 		case PUFFS_VFS_STATVFS:
    309 		{
    310 			struct puffs_vfsreq_statvfs *auxt = auxbuf;
    311 
    312 			error = pops->puffs_fs_statvfs(pu,
    313 			    &auxt->pvfsr_sb, auxt->pvfsr_pid);
    314 			break;
    315 		}
    316 		case PUFFS_VFS_SYNC:
    317 		{
    318 			struct puffs_vfsreq_sync *auxt = auxbuf;
    319 
    320 			error = pops->puffs_fs_sync(pu,
    321 			    auxt->pvfsr_waitfor, &auxt->pvfsr_cred,
    322 			    auxt->pvfsr_pid);
    323 			break;
    324 		}
    325 		default:
    326 			/*
    327 			 * I guess the kernel sees this one coming
    328 			 */
    329 			error = EINVAL;
    330 			break;
    331 		}
    332 
    333 	/* XXX: audit return values */
    334 	/* XXX: sync with kernel */
    335 	} else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) {
    336 		switch (preq->preq_optype) {
    337 		case PUFFS_VN_LOOKUP:
    338 		{
    339 			struct puffs_vnreq_lookup *auxt = auxbuf;
    340 
    341 			/* lookup *must* be present */
    342 			error = pops->puffs_node_lookup(pu, preq->preq_cookie,
    343 			    &auxt->pvnr_newnode, &auxt->pvnr_vtype,
    344 			    &auxt->pvnr_size, &auxt->pvnr_rdev,
    345 			    &auxt->pvnr_cn);
    346 			break;
    347 		}
    348 
    349 		case PUFFS_VN_CREATE:
    350 		{
    351 			struct puffs_vnreq_create *auxt = auxbuf;
    352 			if (pops->puffs_node_create == NULL) {
    353 				error = 0;
    354 				break;
    355 			}
    356 
    357 			error = pops->puffs_node_create(pu,
    358 			    preq->preq_cookie, &auxt->pvnr_newnode,
    359 			    &auxt->pvnr_cn, &auxt->pvnr_va);
    360 			break;
    361 		}
    362 
    363 		case PUFFS_VN_MKNOD:
    364 		{
    365 			struct puffs_vnreq_mknod *auxt = auxbuf;
    366 			if (pops->puffs_node_mknod == NULL) {
    367 				error = 0;
    368 				break;
    369 			}
    370 
    371 			error = pops->puffs_node_mknod(pu,
    372 			    preq->preq_cookie, &auxt->pvnr_newnode,
    373 			    &auxt->pvnr_cn, &auxt->pvnr_va);
    374 			break;
    375 		}
    376 
    377 		case PUFFS_VN_OPEN:
    378 		{
    379 			struct puffs_vnreq_open *auxt = auxbuf;
    380 			if (pops->puffs_node_open == NULL) {
    381 				error = 0;
    382 				break;
    383 			}
    384 
    385 			error = pops->puffs_node_open(pu,
    386 			    preq->preq_cookie, auxt->pvnr_mode,
    387 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    388 			break;
    389 		}
    390 
    391 		case PUFFS_VN_CLOSE:
    392 		{
    393 			struct puffs_vnreq_close *auxt = auxbuf;
    394 			if (pops->puffs_node_close == NULL) {
    395 				error = 0;
    396 				break;
    397 			}
    398 
    399 			error = pops->puffs_node_close(pu,
    400 			    preq->preq_cookie, auxt->pvnr_fflag,
    401 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    402 			break;
    403 		}
    404 
    405 		case PUFFS_VN_ACCESS:
    406 		{
    407 			struct puffs_vnreq_access *auxt = auxbuf;
    408 			if (pops->puffs_node_access == NULL) {
    409 				error = 0;
    410 				break;
    411 			}
    412 
    413 			error = pops->puffs_node_access(pu,
    414 			    preq->preq_cookie, auxt->pvnr_mode,
    415 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    416 			break;
    417 		}
    418 
    419 		case PUFFS_VN_GETATTR:
    420 		{
    421 			struct puffs_vnreq_getattr *auxt = auxbuf;
    422 			if (pops->puffs_node_getattr == NULL) {
    423 				error = EOPNOTSUPP;
    424 				break;
    425 			}
    426 
    427 			error = pops->puffs_node_getattr(pu,
    428 			    preq->preq_cookie, &auxt->pvnr_va,
    429 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    430 			break;
    431 		}
    432 
    433 		case PUFFS_VN_SETATTR:
    434 		{
    435 			struct puffs_vnreq_setattr *auxt = auxbuf;
    436 			if (pops->puffs_node_setattr == NULL) {
    437 				error = EOPNOTSUPP;
    438 				break;
    439 			}
    440 
    441 			error = pops->puffs_node_setattr(pu,
    442 			    preq->preq_cookie, &auxt->pvnr_va,
    443 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    444 			break;
    445 		}
    446 
    447 /* notyet */
    448 #if 0
    449 		case PUFFS_VN_MMAP:
    450 		{
    451 			struct puffs_vnreq_mmap *auxt = auxbuf;
    452 			if (pops->puffs_node_mmap == NULL) {
    453 				error = 0;
    454 				break;
    455 			}
    456 
    457 			error = pops->puffs_node_mmap(pu,
    458 			    preq->preq_cookie, );
    459 			break;
    460 		}
    461 #endif
    462 
    463 		case PUFFS_VN_REVOKE:
    464 		{
    465 			struct puffs_vnreq_revoke *auxt = auxbuf;
    466 			if (pops->puffs_node_revoke == NULL) {
    467 				error = 0;
    468 				break;
    469 			}
    470 
    471 			error = pops->puffs_node_revoke(pu,
    472 			    preq->preq_cookie, auxt->pvnr_flags);
    473 			break;
    474 		}
    475 
    476 		case PUFFS_VN_FSYNC:
    477 		{
    478 			struct puffs_vnreq_fsync *auxt = auxbuf;
    479 			if (pops->puffs_node_fsync == NULL) {
    480 				error = 0;
    481 				break;
    482 			}
    483 
    484 			error = pops->puffs_node_fsync(pu,
    485 			    preq->preq_cookie, &auxt->pvnr_cred,
    486 			    auxt->pvnr_flags, auxt->pvnr_offlo,
    487 			    auxt->pvnr_offhi, auxt->pvnr_pid);
    488 			break;
    489 		}
    490 
    491 		case PUFFS_VN_SEEK:
    492 		{
    493 			struct puffs_vnreq_seek *auxt = auxbuf;
    494 			if (pops->puffs_node_seek == NULL) {
    495 				error = 0;
    496 				break;
    497 			}
    498 
    499 			error = pops->puffs_node_seek(pu,
    500 			    preq->preq_cookie, auxt->pvnr_oldoff,
    501 			    auxt->pvnr_newoff, &auxt->pvnr_cred);
    502 			break;
    503 		}
    504 
    505 		case PUFFS_VN_REMOVE:
    506 		{
    507 			struct puffs_vnreq_remove *auxt = auxbuf;
    508 			if (pops->puffs_node_remove == NULL) {
    509 				error = 0;
    510 				break;
    511 			}
    512 
    513 			error = pops->puffs_node_remove(pu,
    514 			    preq->preq_cookie, auxt->pvnr_cookie_targ,
    515 			    &auxt->pvnr_cn);
    516 			break;
    517 		}
    518 
    519 		case PUFFS_VN_LINK:
    520 		{
    521 			struct puffs_vnreq_link *auxt = auxbuf;
    522 			if (pops->puffs_node_link == NULL) {
    523 				error = 0;
    524 				break;
    525 			}
    526 
    527 			error = pops->puffs_node_link(pu,
    528 			    preq->preq_cookie, auxt->pvnr_cookie_targ,
    529 			    &auxt->pvnr_cn);
    530 			break;
    531 		}
    532 
    533 		case PUFFS_VN_RENAME:
    534 		{
    535 			struct puffs_vnreq_rename *auxt = auxbuf;
    536 			if (pops->puffs_node_rename == NULL) {
    537 				error = 0;
    538 				break;
    539 			}
    540 
    541 			error = pops->puffs_node_rename(pu,
    542 			    preq->preq_cookie, auxt->pvnr_cookie_src,
    543 			    &auxt->pvnr_cn_src, auxt->pvnr_cookie_targdir,
    544 			    auxt->pvnr_cookie_targ, &auxt->pvnr_cn_targ);
    545 			break;
    546 		}
    547 
    548 		case PUFFS_VN_MKDIR:
    549 		{
    550 			struct puffs_vnreq_mkdir *auxt = auxbuf;
    551 			if (pops->puffs_node_mkdir == NULL) {
    552 				error = 0;
    553 				break;
    554 			}
    555 
    556 			error = pops->puffs_node_mkdir(pu,
    557 			    preq->preq_cookie, &auxt->pvnr_newnode,
    558 			    &auxt->pvnr_cn, &auxt->pvnr_va);
    559 			break;
    560 		}
    561 
    562 		case PUFFS_VN_RMDIR:
    563 		{
    564 			struct puffs_vnreq_rmdir *auxt = auxbuf;
    565 			if (pops->puffs_node_rmdir == NULL) {
    566 				error = 0;
    567 				break;
    568 			}
    569 
    570 			error = pops->puffs_node_rmdir(pu,
    571 			    preq->preq_cookie, auxt->pvnr_cookie_targ,
    572 			    &auxt->pvnr_cn);
    573 			break;
    574 		}
    575 
    576 		case PUFFS_VN_SYMLINK:
    577 		{
    578 			struct puffs_vnreq_symlink *auxt = auxbuf;
    579 			if (pops->puffs_node_symlink == NULL) {
    580 				error = 0;
    581 				break;
    582 			}
    583 
    584 			error = pops->puffs_node_symlink(pu,
    585 			    preq->preq_cookie, &auxt->pvnr_newnode,
    586 			    &auxt->pvnr_cn, &auxt->pvnr_va, auxt->pvnr_link);
    587 			break;
    588 		}
    589 
    590 		case PUFFS_VN_READDIR:
    591 		{
    592 			struct puffs_vnreq_readdir *auxt = auxbuf;
    593 			size_t res;
    594 
    595 			if (pops->puffs_node_readdir == NULL) {
    596 				error = 0;
    597 				break;
    598 			}
    599 
    600 			res = auxt->pvnr_resid;
    601 			error = pops->puffs_node_readdir(pu,
    602 			    preq->preq_cookie, auxt->pvnr_dent,
    603 			    &auxt->pvnr_cred, &auxt->pvnr_offset,
    604 			    &auxt->pvnr_resid);
    605 
    606 			/* need to move a bit more */
    607 			*blenp = sizeof(struct puffs_vnreq_readdir)
    608 			    + (res - auxt->pvnr_resid);
    609 			break;
    610 		}
    611 
    612 		case PUFFS_VN_READLINK:
    613 		{
    614 			struct puffs_vnreq_readlink *auxt = auxbuf;
    615 			if (pops->puffs_node_readlink == NULL) {
    616 				error = EOPNOTSUPP;
    617 				break;
    618 			}
    619 
    620 			error = pops->puffs_node_readlink(pu,
    621 			    preq->preq_cookie, &auxt->pvnr_cred,
    622 			    auxt->pvnr_link, &auxt->pvnr_linklen);
    623 			break;
    624 		}
    625 
    626 		case PUFFS_VN_RECLAIM:
    627 		{
    628 			struct puffs_vnreq_reclaim *auxt = auxbuf;
    629 			if (pops->puffs_node_reclaim == NULL) {
    630 				error = 0;
    631 				break;
    632 			}
    633 
    634 			error = pops->puffs_node_reclaim(pu,
    635 			    preq->preq_cookie, auxt->pvnr_pid);
    636 			break;
    637 		}
    638 
    639 		case PUFFS_VN_INACTIVE:
    640 		{
    641 			struct puffs_vnreq_inactive *auxt = auxbuf;
    642 			if (pops->puffs_node_inactive == NULL) {
    643 				error = EOPNOTSUPP;
    644 				break;
    645 			}
    646 
    647 			error = pops->puffs_node_inactive(pu,
    648 			    preq->preq_cookie, auxt->pvnr_pid,
    649 			    &auxt->pvnr_backendrefs);
    650 			break;
    651 		}
    652 
    653 		case PUFFS_VN_PATHCONF:
    654 		{
    655 			struct puffs_vnreq_pathconf *auxt = auxbuf;
    656 			if (pops->puffs_node_pathconf == NULL) {
    657 				error = 0;
    658 				break;
    659 			}
    660 
    661 			error = pops->puffs_node_pathconf(pu,
    662 			    preq->preq_cookie, auxt->pvnr_name,
    663 			    &auxt->pvnr_retval);
    664 			break;
    665 		}
    666 
    667 		case PUFFS_VN_ADVLOCK:
    668 		{
    669 			struct puffs_vnreq_advlock *auxt = auxbuf;
    670 			if (pops->puffs_node_advlock == NULL) {
    671 				error = 0;
    672 				break;
    673 			}
    674 
    675 			error = pops->puffs_node_advlock(pu,
    676 			    preq->preq_cookie, auxt->pvnr_id, auxt->pvnr_op,
    677 			    &auxt->pvnr_fl, auxt->pvnr_flags);
    678 			break;
    679 		}
    680 
    681 		case PUFFS_VN_PRINT:
    682 		{
    683 			if (pops->puffs_node_print == NULL) {
    684 				error = 0;
    685 				break;
    686 			}
    687 
    688 			error = pops->puffs_node_print(pu,
    689 			    preq->preq_cookie);
    690 			break;
    691 		}
    692 
    693 		case PUFFS_VN_READ:
    694 		{
    695 			struct puffs_vnreq_read *auxt = auxbuf;
    696 			size_t res;
    697 
    698 			if (pops->puffs_node_read == NULL) {
    699 				error = EIO;
    700 				break;
    701 			}
    702 
    703 			res = auxt->pvnr_resid;
    704 			error = pops->puffs_node_read(pu,
    705 			    preq->preq_cookie, auxt->pvnr_data,
    706 			    auxt->pvnr_offset, &auxt->pvnr_resid,
    707 			    &auxt->pvnr_cred, auxt->pvnr_ioflag);
    708 
    709 			/* need to move a bit more */
    710 			*blenp = sizeof(struct puffs_vnreq_read)
    711 			    + (res - auxt->pvnr_resid);
    712 			break;
    713 		}
    714 
    715 		case PUFFS_VN_WRITE:
    716 		{
    717 			struct puffs_vnreq_write *auxt = auxbuf;
    718 
    719 			if (pops->puffs_node_write == NULL) {
    720 				error = EIO;
    721 				break;
    722 			}
    723 
    724 			error = pops->puffs_node_write(pu,
    725 			    preq->preq_cookie, auxt->pvnr_data,
    726 			    auxt->pvnr_offset, &auxt->pvnr_resid,
    727 			    &auxt->pvnr_cred, auxt->pvnr_ioflag);
    728 
    729 			/* don't need to move data back to the kernel */
    730 			*blenp = sizeof(struct puffs_vnreq_write);
    731 			break;
    732 		}
    733 
    734 		case PUFFS_VN_IOCTL:
    735 			error = pops->puffs_node_ioctl1(pu, preq->preq_cookie,
    736 			     (struct puffs_vnreq_ioctl *)auxbuf, &pop);
    737 			if (error != 0)
    738 				break;
    739 			pop.pso_reqid = preq->preq_id;
    740 
    741 			/* let the kernel do it's intermediate duty */
    742 			error = ioctl(pu->pu_fd, PUFFSSIZEOP, &pop);
    743 			/*
    744 			 * XXX: I don't actually know what the correct
    745 			 * thing to do in case of an error is, so I'll
    746 			 * just ignore it for the time being.
    747 			 */
    748 			error = pops->puffs_node_ioctl2(pu, preq->preq_cookie,
    749 			    (struct puffs_vnreq_ioctl *)auxbuf, &pop);
    750 			break;
    751 
    752 		case PUFFS_VN_FCNTL:
    753 			error = pops->puffs_node_fcntl1(pu, preq->preq_cookie,
    754 			     (struct puffs_vnreq_fcntl *)auxbuf, &pop);
    755 			if (error != 0)
    756 				break;
    757 			pop.pso_reqid = preq->preq_id;
    758 
    759 			/* let the kernel do it's intermediate duty */
    760 			error = ioctl(pu->pu_fd, PUFFSSIZEOP, &pop);
    761 			/*
    762 			 * XXX: I don't actually know what the correct
    763 			 * thing to do in case of an error is, so I'll
    764 			 * just ignore it for the time being.
    765 			 */
    766 			error = pops->puffs_node_fcntl2(pu, preq->preq_cookie,
    767 			    (struct puffs_vnreq_fcntl *)auxbuf, &pop);
    768 			break;
    769 
    770 		default:
    771 			printf("inval op %d\n", preq->preq_optype);
    772 			error = EINVAL;
    773 			break;
    774 		}
    775 	} else {
    776 		/*
    777 		 * this one also
    778 		 */
    779 		error = EINVAL;
    780 	}
    781 
    782 	preq->preq_rv = error;
    783 	return rv;
    784 }
    785 
    786 
    787 #if 0
    788 		case PUFFS_VN_POLL:
    789 		{
    790 			struct puffs_vnreq_poll *auxt = auxbuf;
    791 			if (pops->puffs_node_poll == NULL) {
    792 				error = 0;
    793 				break;
    794 			}
    795 
    796 			error = pops->puffs_node_poll(pu,
    797 			    preq->preq_cookie, preq-);
    798 			break;
    799 		}
    800 
    801 		case PUFFS_VN_KQFILTER:
    802 		{
    803 			struct puffs_vnreq_kqfilter *auxt = auxbuf;
    804 			if (pops->puffs_node_kqfilter == NULL) {
    805 				error = 0;
    806 				break;
    807 			}
    808 
    809 			error = pops->puffs_node_kqfilter(pu,
    810 			    preq->preq_cookie, );
    811 			break;
    812 		}
    813 
    814 		case PUFFS_VN_CLOSEEXTATTR:
    815 		{
    816 			struct puffs_vnreq_closeextattr *auxt = auxbuf;
    817 			if (pops->puffs_closeextattr == NULL) {
    818 				error = 0;
    819 				break;
    820 			}
    821 
    822 			error = pops->puffs_closeextattr(pu,
    823 			    preq->preq_cookie, );
    824 			break;
    825 		}
    826 
    827 		case PUFFS_VN_GETEXTATTR:
    828 		{
    829 			struct puffs_vnreq_getextattr *auxt = auxbuf;
    830 			if (pops->puffs_getextattr == NULL) {
    831 				error = 0;
    832 				break;
    833 			}
    834 
    835 			error = pops->puffs_getextattr(pu,
    836 			    preq->preq_cookie, );
    837 			break;
    838 		}
    839 
    840 		case PUFFS_VN_LISTEXTATTR:
    841 		{
    842 			struct puffs_vnreq_listextattr *auxt = auxbuf;
    843 			if (pops->puffs_listextattr == NULL) {
    844 				error = 0;
    845 				break;
    846 			}
    847 
    848 			error = pops->puffs_listextattr(pu,
    849 			    preq->preq_cookie, );
    850 			break;
    851 		}
    852 
    853 		case PUFFS_VN_OPENEXTATTR:
    854 		{
    855 			struct puffs_vnreq_openextattr *auxt = auxbuf;
    856 			if (pops->puffs_openextattr == NULL) {
    857 				error = 0;
    858 				break;
    859 			}
    860 
    861 			error = pops->puffs_openextattr(pu,
    862 			    preq->preq_cookie, );
    863 			break;
    864 		}
    865 
    866 		case PUFFS_VN_DELETEEXTATTR:
    867 		{
    868 			struct puffs_vnreq_deleteextattr *auxt = auxbuf;
    869 			if (pops->puffs_deleteextattr == NULL) {
    870 				error = 0;
    871 				break;
    872 			}
    873 
    874 			error = pops->puffs_deleteextattr(pu,
    875 			    preq->preq_cookie, );
    876 			break;
    877 		}
    878 
    879 		case PUFFS_VN_SETEXTATTR:
    880 		{
    881 			struct puffs_vnreq_setextattr *auxt = auxbuf;
    882 			if (pops->puffs_setextattr == NULL) {
    883 				error = 0;
    884 				break;
    885 			}
    886 
    887 			error = pops->puffs_setextattr(pu,
    888 			    preq->preq_cookie, );
    889 			break;
    890 		}
    891 
    892 #endif
    893