Home | History | Annotate | Line # | Download | only in libpuffs
puffs.c revision 1.15
      1 /*	$NetBSD: puffs.c,v 1.15 2006/12/07 16:59:14 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.15 2006/12/07 16:59:14 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 		case PUFFS_VN_MMAP:
    448 		{
    449 			struct puffs_vnreq_mmap *auxt = auxbuf;
    450 			if (pops->puffs_node_mmap == NULL) {
    451 				error = 0;
    452 				break;
    453 			}
    454 
    455 			error = pops->puffs_node_mmap(pu,
    456 			    preq->preq_cookie, auxt->pvnr_fflags,
    457 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    458 			break;
    459 		}
    460 
    461 		case PUFFS_VN_REVOKE:
    462 		{
    463 			struct puffs_vnreq_revoke *auxt = auxbuf;
    464 			if (pops->puffs_node_revoke == NULL) {
    465 				error = 0;
    466 				break;
    467 			}
    468 
    469 			error = pops->puffs_node_revoke(pu,
    470 			    preq->preq_cookie, auxt->pvnr_flags);
    471 			break;
    472 		}
    473 
    474 		case PUFFS_VN_FSYNC:
    475 		{
    476 			struct puffs_vnreq_fsync *auxt = auxbuf;
    477 			if (pops->puffs_node_fsync == NULL) {
    478 				error = 0;
    479 				break;
    480 			}
    481 
    482 			error = pops->puffs_node_fsync(pu,
    483 			    preq->preq_cookie, &auxt->pvnr_cred,
    484 			    auxt->pvnr_flags, auxt->pvnr_offlo,
    485 			    auxt->pvnr_offhi, auxt->pvnr_pid);
    486 			break;
    487 		}
    488 
    489 		case PUFFS_VN_SEEK:
    490 		{
    491 			struct puffs_vnreq_seek *auxt = auxbuf;
    492 			if (pops->puffs_node_seek == NULL) {
    493 				error = 0;
    494 				break;
    495 			}
    496 
    497 			error = pops->puffs_node_seek(pu,
    498 			    preq->preq_cookie, auxt->pvnr_oldoff,
    499 			    auxt->pvnr_newoff, &auxt->pvnr_cred);
    500 			break;
    501 		}
    502 
    503 		case PUFFS_VN_REMOVE:
    504 		{
    505 			struct puffs_vnreq_remove *auxt = auxbuf;
    506 			if (pops->puffs_node_remove == NULL) {
    507 				error = 0;
    508 				break;
    509 			}
    510 
    511 			error = pops->puffs_node_remove(pu,
    512 			    preq->preq_cookie, auxt->pvnr_cookie_targ,
    513 			    &auxt->pvnr_cn);
    514 			break;
    515 		}
    516 
    517 		case PUFFS_VN_LINK:
    518 		{
    519 			struct puffs_vnreq_link *auxt = auxbuf;
    520 			if (pops->puffs_node_link == NULL) {
    521 				error = 0;
    522 				break;
    523 			}
    524 
    525 			error = pops->puffs_node_link(pu,
    526 			    preq->preq_cookie, auxt->pvnr_cookie_targ,
    527 			    &auxt->pvnr_cn);
    528 			break;
    529 		}
    530 
    531 		case PUFFS_VN_RENAME:
    532 		{
    533 			struct puffs_vnreq_rename *auxt = auxbuf;
    534 			if (pops->puffs_node_rename == NULL) {
    535 				error = 0;
    536 				break;
    537 			}
    538 
    539 			error = pops->puffs_node_rename(pu,
    540 			    preq->preq_cookie, auxt->pvnr_cookie_src,
    541 			    &auxt->pvnr_cn_src, auxt->pvnr_cookie_targdir,
    542 			    auxt->pvnr_cookie_targ, &auxt->pvnr_cn_targ);
    543 			break;
    544 		}
    545 
    546 		case PUFFS_VN_MKDIR:
    547 		{
    548 			struct puffs_vnreq_mkdir *auxt = auxbuf;
    549 			if (pops->puffs_node_mkdir == NULL) {
    550 				error = 0;
    551 				break;
    552 			}
    553 
    554 			error = pops->puffs_node_mkdir(pu,
    555 			    preq->preq_cookie, &auxt->pvnr_newnode,
    556 			    &auxt->pvnr_cn, &auxt->pvnr_va);
    557 			break;
    558 		}
    559 
    560 		case PUFFS_VN_RMDIR:
    561 		{
    562 			struct puffs_vnreq_rmdir *auxt = auxbuf;
    563 			if (pops->puffs_node_rmdir == NULL) {
    564 				error = 0;
    565 				break;
    566 			}
    567 
    568 			error = pops->puffs_node_rmdir(pu,
    569 			    preq->preq_cookie, auxt->pvnr_cookie_targ,
    570 			    &auxt->pvnr_cn);
    571 			break;
    572 		}
    573 
    574 		case PUFFS_VN_SYMLINK:
    575 		{
    576 			struct puffs_vnreq_symlink *auxt = auxbuf;
    577 			if (pops->puffs_node_symlink == NULL) {
    578 				error = 0;
    579 				break;
    580 			}
    581 
    582 			error = pops->puffs_node_symlink(pu,
    583 			    preq->preq_cookie, &auxt->pvnr_newnode,
    584 			    &auxt->pvnr_cn, &auxt->pvnr_va, auxt->pvnr_link);
    585 			break;
    586 		}
    587 
    588 		case PUFFS_VN_READDIR:
    589 		{
    590 			struct puffs_vnreq_readdir *auxt = auxbuf;
    591 			size_t res;
    592 
    593 			if (pops->puffs_node_readdir == NULL) {
    594 				error = 0;
    595 				break;
    596 			}
    597 
    598 			res = auxt->pvnr_resid;
    599 			error = pops->puffs_node_readdir(pu,
    600 			    preq->preq_cookie, auxt->pvnr_dent,
    601 			    &auxt->pvnr_cred, &auxt->pvnr_offset,
    602 			    &auxt->pvnr_resid);
    603 
    604 			/* need to move a bit more */
    605 			*blenp = sizeof(struct puffs_vnreq_readdir)
    606 			    + (res - auxt->pvnr_resid);
    607 			break;
    608 		}
    609 
    610 		case PUFFS_VN_READLINK:
    611 		{
    612 			struct puffs_vnreq_readlink *auxt = auxbuf;
    613 			if (pops->puffs_node_readlink == NULL) {
    614 				error = EOPNOTSUPP;
    615 				break;
    616 			}
    617 
    618 			error = pops->puffs_node_readlink(pu,
    619 			    preq->preq_cookie, &auxt->pvnr_cred,
    620 			    auxt->pvnr_link, &auxt->pvnr_linklen);
    621 			break;
    622 		}
    623 
    624 		case PUFFS_VN_RECLAIM:
    625 		{
    626 			struct puffs_vnreq_reclaim *auxt = auxbuf;
    627 			if (pops->puffs_node_reclaim == NULL) {
    628 				error = 0;
    629 				break;
    630 			}
    631 
    632 			error = pops->puffs_node_reclaim(pu,
    633 			    preq->preq_cookie, auxt->pvnr_pid);
    634 			break;
    635 		}
    636 
    637 		case PUFFS_VN_INACTIVE:
    638 		{
    639 			struct puffs_vnreq_inactive *auxt = auxbuf;
    640 			if (pops->puffs_node_inactive == NULL) {
    641 				error = EOPNOTSUPP;
    642 				break;
    643 			}
    644 
    645 			error = pops->puffs_node_inactive(pu,
    646 			    preq->preq_cookie, auxt->pvnr_pid,
    647 			    &auxt->pvnr_backendrefs);
    648 			break;
    649 		}
    650 
    651 		case PUFFS_VN_PATHCONF:
    652 		{
    653 			struct puffs_vnreq_pathconf *auxt = auxbuf;
    654 			if (pops->puffs_node_pathconf == NULL) {
    655 				error = 0;
    656 				break;
    657 			}
    658 
    659 			error = pops->puffs_node_pathconf(pu,
    660 			    preq->preq_cookie, auxt->pvnr_name,
    661 			    &auxt->pvnr_retval);
    662 			break;
    663 		}
    664 
    665 		case PUFFS_VN_ADVLOCK:
    666 		{
    667 			struct puffs_vnreq_advlock *auxt = auxbuf;
    668 			if (pops->puffs_node_advlock == NULL) {
    669 				error = 0;
    670 				break;
    671 			}
    672 
    673 			error = pops->puffs_node_advlock(pu,
    674 			    preq->preq_cookie, auxt->pvnr_id, auxt->pvnr_op,
    675 			    &auxt->pvnr_fl, auxt->pvnr_flags);
    676 			break;
    677 		}
    678 
    679 		case PUFFS_VN_PRINT:
    680 		{
    681 			if (pops->puffs_node_print == NULL) {
    682 				error = 0;
    683 				break;
    684 			}
    685 
    686 			error = pops->puffs_node_print(pu,
    687 			    preq->preq_cookie);
    688 			break;
    689 		}
    690 
    691 		case PUFFS_VN_READ:
    692 		{
    693 			struct puffs_vnreq_read *auxt = auxbuf;
    694 			size_t res;
    695 
    696 			if (pops->puffs_node_read == NULL) {
    697 				error = EIO;
    698 				break;
    699 			}
    700 
    701 			res = auxt->pvnr_resid;
    702 			error = pops->puffs_node_read(pu,
    703 			    preq->preq_cookie, auxt->pvnr_data,
    704 			    auxt->pvnr_offset, &auxt->pvnr_resid,
    705 			    &auxt->pvnr_cred, auxt->pvnr_ioflag);
    706 
    707 			/* need to move a bit more */
    708 			*blenp = sizeof(struct puffs_vnreq_read)
    709 			    + (res - auxt->pvnr_resid);
    710 			break;
    711 		}
    712 
    713 		case PUFFS_VN_WRITE:
    714 		{
    715 			struct puffs_vnreq_write *auxt = auxbuf;
    716 
    717 			if (pops->puffs_node_write == NULL) {
    718 				error = EIO;
    719 				break;
    720 			}
    721 
    722 			error = pops->puffs_node_write(pu,
    723 			    preq->preq_cookie, auxt->pvnr_data,
    724 			    auxt->pvnr_offset, &auxt->pvnr_resid,
    725 			    &auxt->pvnr_cred, auxt->pvnr_ioflag);
    726 
    727 			/* don't need to move data back to the kernel */
    728 			*blenp = sizeof(struct puffs_vnreq_write);
    729 			break;
    730 		}
    731 
    732 		case PUFFS_VN_IOCTL:
    733 			error = pops->puffs_node_ioctl1(pu, preq->preq_cookie,
    734 			     (struct puffs_vnreq_ioctl *)auxbuf, &pop);
    735 			if (error != 0)
    736 				break;
    737 			pop.pso_reqid = preq->preq_id;
    738 
    739 			/* let the kernel do it's intermediate duty */
    740 			error = ioctl(pu->pu_fd, PUFFSSIZEOP, &pop);
    741 			/*
    742 			 * XXX: I don't actually know what the correct
    743 			 * thing to do in case of an error is, so I'll
    744 			 * just ignore it for the time being.
    745 			 */
    746 			error = pops->puffs_node_ioctl2(pu, preq->preq_cookie,
    747 			    (struct puffs_vnreq_ioctl *)auxbuf, &pop);
    748 			break;
    749 
    750 		case PUFFS_VN_FCNTL:
    751 			error = pops->puffs_node_fcntl1(pu, preq->preq_cookie,
    752 			     (struct puffs_vnreq_fcntl *)auxbuf, &pop);
    753 			if (error != 0)
    754 				break;
    755 			pop.pso_reqid = preq->preq_id;
    756 
    757 			/* let the kernel do it's intermediate duty */
    758 			error = ioctl(pu->pu_fd, PUFFSSIZEOP, &pop);
    759 			/*
    760 			 * XXX: I don't actually know what the correct
    761 			 * thing to do in case of an error is, so I'll
    762 			 * just ignore it for the time being.
    763 			 */
    764 			error = pops->puffs_node_fcntl2(pu, preq->preq_cookie,
    765 			    (struct puffs_vnreq_fcntl *)auxbuf, &pop);
    766 			break;
    767 
    768 		default:
    769 			printf("inval op %d\n", preq->preq_optype);
    770 			error = EINVAL;
    771 			break;
    772 		}
    773 	} else {
    774 		/*
    775 		 * this one also
    776 		 */
    777 		error = EINVAL;
    778 	}
    779 
    780 	preq->preq_rv = error;
    781 	return rv;
    782 }
    783 
    784 
    785 #if 0
    786 		case PUFFS_VN_POLL:
    787 		{
    788 			struct puffs_vnreq_poll *auxt = auxbuf;
    789 			if (pops->puffs_node_poll == NULL) {
    790 				error = 0;
    791 				break;
    792 			}
    793 
    794 			error = pops->puffs_node_poll(pu,
    795 			    preq->preq_cookie, preq-);
    796 			break;
    797 		}
    798 
    799 		case PUFFS_VN_KQFILTER:
    800 		{
    801 			struct puffs_vnreq_kqfilter *auxt = auxbuf;
    802 			if (pops->puffs_node_kqfilter == NULL) {
    803 				error = 0;
    804 				break;
    805 			}
    806 
    807 			error = pops->puffs_node_kqfilter(pu,
    808 			    preq->preq_cookie, );
    809 			break;
    810 		}
    811 
    812 		case PUFFS_VN_CLOSEEXTATTR:
    813 		{
    814 			struct puffs_vnreq_closeextattr *auxt = auxbuf;
    815 			if (pops->puffs_closeextattr == NULL) {
    816 				error = 0;
    817 				break;
    818 			}
    819 
    820 			error = pops->puffs_closeextattr(pu,
    821 			    preq->preq_cookie, );
    822 			break;
    823 		}
    824 
    825 		case PUFFS_VN_GETEXTATTR:
    826 		{
    827 			struct puffs_vnreq_getextattr *auxt = auxbuf;
    828 			if (pops->puffs_getextattr == NULL) {
    829 				error = 0;
    830 				break;
    831 			}
    832 
    833 			error = pops->puffs_getextattr(pu,
    834 			    preq->preq_cookie, );
    835 			break;
    836 		}
    837 
    838 		case PUFFS_VN_LISTEXTATTR:
    839 		{
    840 			struct puffs_vnreq_listextattr *auxt = auxbuf;
    841 			if (pops->puffs_listextattr == NULL) {
    842 				error = 0;
    843 				break;
    844 			}
    845 
    846 			error = pops->puffs_listextattr(pu,
    847 			    preq->preq_cookie, );
    848 			break;
    849 		}
    850 
    851 		case PUFFS_VN_OPENEXTATTR:
    852 		{
    853 			struct puffs_vnreq_openextattr *auxt = auxbuf;
    854 			if (pops->puffs_openextattr == NULL) {
    855 				error = 0;
    856 				break;
    857 			}
    858 
    859 			error = pops->puffs_openextattr(pu,
    860 			    preq->preq_cookie, );
    861 			break;
    862 		}
    863 
    864 		case PUFFS_VN_DELETEEXTATTR:
    865 		{
    866 			struct puffs_vnreq_deleteextattr *auxt = auxbuf;
    867 			if (pops->puffs_deleteextattr == NULL) {
    868 				error = 0;
    869 				break;
    870 			}
    871 
    872 			error = pops->puffs_deleteextattr(pu,
    873 			    preq->preq_cookie, );
    874 			break;
    875 		}
    876 
    877 		case PUFFS_VN_SETEXTATTR:
    878 		{
    879 			struct puffs_vnreq_setextattr *auxt = auxbuf;
    880 			if (pops->puffs_setextattr == NULL) {
    881 				error = 0;
    882 				break;
    883 			}
    884 
    885 			error = pops->puffs_setextattr(pu,
    886 			    preq->preq_cookie, );
    887 			break;
    888 		}
    889 
    890 #endif
    891