Home | History | Annotate | Line # | Download | only in libpuffs
dispatcher.c revision 1.38.2.3
      1 /*	$NetBSD: dispatcher.c,v 1.38.2.3 2012/08/12 13:13:21 martin Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2006, 2007, 2008 Antti Kantee.  All Rights Reserved.
      5  *
      6  * Development of this software was supported by the
      7  * Ulla Tuominen Foundation, the Finnish Cultural Foundation and
      8  * Research Foundation of Helsinki University of Technology.
      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  *
     19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     20  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     22  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 #if !defined(lint)
     34 __RCSID("$NetBSD: dispatcher.c,v 1.38.2.3 2012/08/12 13:13:21 martin Exp $");
     35 #endif /* !lint */
     36 
     37 #include <sys/types.h>
     38 #include <sys/poll.h>
     39 
     40 #include <assert.h>
     41 #include <errno.h>
     42 #include <pthread.h>
     43 #include <puffs.h>
     44 #include <puffsdump.h>
     45 #include <stdio.h>
     46 #include <stdlib.h>
     47 #include <unistd.h>
     48 
     49 #include "puffs_priv.h"
     50 
     51 #define PUFFS_USE_FS_TTL(pu) (pu->pu_flags & PUFFS_KFLAG_CACHE_FS_TTL)
     52 
     53 static void dispatch(struct puffs_cc *);
     54 
     55 /* for our eyes only */
     56 void
     57 puffs__ml_dispatch(struct puffs_usermount *pu, struct puffs_framebuf *pb)
     58 {
     59 	struct puffs_cc *pcc = puffs_cc_getcc(pu);
     60 	struct puffs_req *preq;
     61 
     62 	pcc->pcc_pb = pb;
     63 	pcc->pcc_flags |= PCC_MLCONT;
     64 	dispatch(pcc);
     65 
     66 	/* Put result to kernel sendqueue if necessary */
     67 	preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
     68 	if (PUFFSOP_WANTREPLY(preq->preq_opclass)) {
     69 		if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
     70 			puffsdump_rv(preq);
     71 
     72 		puffs_framev_enqueue_justsend(pu, pu->pu_fd,
     73 		    pcc->pcc_pb, 0, 0);
     74 	} else {
     75 		puffs_framebuf_destroy(pcc->pcc_pb);
     76 	}
     77 
     78 	/* who needs information when you're living on borrowed time? */
     79 	if (pcc->pcc_flags & PCC_BORROWED) {
     80 		puffs_cc_yield(pcc); /* back to borrow source */
     81 	}
     82 	pcc->pcc_flags = 0;
     83 }
     84 
     85 /* public, but not really tested and only semi-supported */
     86 int
     87 puffs_dispatch_create(struct puffs_usermount *pu, struct puffs_framebuf *pb,
     88 	struct puffs_cc **pccp)
     89 {
     90 	struct puffs_cc *pcc;
     91 
     92 	if (puffs__cc_create(pu, dispatch, &pcc) == -1)
     93 		return -1;
     94 
     95 	pcc->pcc_pb = pb;
     96 	*pccp = pcc;
     97 
     98 	return 0;
     99 }
    100 
    101 int
    102 puffs_dispatch_exec(struct puffs_cc *pcc, struct puffs_framebuf **pbp)
    103 {
    104 	int rv;
    105 
    106 	puffs_cc_continue(pcc);
    107 
    108 	if (pcc->pcc_flags & PCC_DONE) {
    109 		rv = 1;
    110 		*pbp = pcc->pcc_pb;
    111 		pcc->pcc_flags = 0;
    112 		puffs__cc_destroy(pcc, 0);
    113 	} else {
    114 		rv = 0;
    115 	}
    116 
    117 	return rv;
    118 }
    119 
    120 static void
    121 dispatch(struct puffs_cc *pcc)
    122 {
    123 	struct puffs_usermount *pu = pcc->pcc_pu;
    124 	struct puffs_ops *pops = &pu->pu_ops;
    125 	struct puffs_req *preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
    126 	void *auxbuf; /* help with typecasting */
    127 	puffs_cookie_t opcookie;
    128 	int error = 0, buildpath;
    129 
    130 	/* XXX: smaller hammer, please */
    131 	if ((PUFFSOP_OPCLASS(preq->preq_opclass == PUFFSOP_VFS &&
    132 	    preq->preq_optype == PUFFS_VFS_VPTOFH)) ||
    133 	    (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN &&
    134 	    (preq->preq_optype == PUFFS_VN_READDIR
    135 	    || preq->preq_optype == PUFFS_VN_READ))) {
    136 		if (puffs_framebuf_reserve_space(pcc->pcc_pb,
    137 		    PUFFS_MSG_MAXSIZE) == -1)
    138 			error = errno;
    139 		preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
    140 	}
    141 
    142 	auxbuf = preq;
    143 	opcookie = preq->preq_cookie;
    144 
    145 	assert((pcc->pcc_flags & PCC_DONE) == 0);
    146 
    147 	buildpath = pu->pu_flags & PUFFS_FLAG_BUILDPATH;
    148 	preq->preq_setbacks = 0;
    149 
    150 	if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
    151 		puffsdump_req(preq);
    152 
    153 	puffs__cc_setcaller(pcc, preq->preq_pid, preq->preq_lid);
    154 
    155 	/* pre-operation */
    156 	if (pu->pu_oppre)
    157 		pu->pu_oppre(pu);
    158 
    159 	if (error)
    160 		goto out;
    161 
    162 	/* Execute actual operation */
    163 	if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) {
    164 		switch (preq->preq_optype) {
    165 		case PUFFS_VFS_UNMOUNT:
    166 		{
    167 			struct puffs_vfsmsg_unmount *auxt = auxbuf;
    168 
    169 			PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTING);
    170 			error = pops->puffs_fs_unmount(pu, auxt->pvfsr_flags);
    171 			if (!error)
    172 				PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTED);
    173 			else
    174 				PU_SETSTATE(pu, PUFFS_STATE_RUNNING);
    175 			break;
    176 		}
    177 
    178 		case PUFFS_VFS_STATVFS:
    179 		{
    180 			struct puffs_vfsmsg_statvfs *auxt = auxbuf;
    181 
    182 			error = pops->puffs_fs_statvfs(pu, &auxt->pvfsr_sb);
    183 			break;
    184 		}
    185 
    186 		case PUFFS_VFS_SYNC:
    187 		{
    188 			struct puffs_vfsmsg_sync *auxt = auxbuf;
    189 			PUFFS_MAKECRED(pcr, &auxt->pvfsr_cred);
    190 
    191 			error = pops->puffs_fs_sync(pu,
    192 			    auxt->pvfsr_waitfor, pcr);
    193 			break;
    194 		}
    195 
    196 		case PUFFS_VFS_FHTOVP:
    197 		{
    198 			struct puffs_vfsmsg_fhtonode *auxt = auxbuf;
    199 			struct puffs_newinfo pni;
    200 
    201 			pni.pni_cookie = &auxt->pvfsr_fhcookie;
    202 			pni.pni_vtype = &auxt->pvfsr_vtype;
    203 			pni.pni_size = &auxt->pvfsr_size;
    204 			pni.pni_rdev = &auxt->pvfsr_rdev;
    205 			pni.pni_va = NULL;
    206 			pni.pni_va_ttl = NULL;
    207 			pni.pni_cn_ttl = NULL;
    208 
    209 			error = pops->puffs_fs_fhtonode(pu, auxt->pvfsr_data,
    210 			    auxt->pvfsr_dsize, &pni);
    211 
    212 			break;
    213 		}
    214 
    215 		case PUFFS_VFS_VPTOFH:
    216 		{
    217 			struct puffs_vfsmsg_nodetofh *auxt = auxbuf;
    218 
    219 			error = pops->puffs_fs_nodetofh(pu,
    220 			    auxt->pvfsr_fhcookie, auxt->pvfsr_data,
    221 			    &auxt->pvfsr_dsize);
    222 
    223 			break;
    224 		}
    225 
    226 		case PUFFS_VFS_EXTATTRCTL:
    227 		{
    228 			struct puffs_vfsmsg_extattrctl *auxt = auxbuf;
    229 			const char *attrname;
    230 			int flags;
    231 
    232 			if (pops->puffs_fs_extattrctl == NULL) {
    233 				error = EOPNOTSUPP;
    234 				break;
    235 			}
    236 
    237 			if (auxt->pvfsr_flags & PUFFS_EXTATTRCTL_HASATTRNAME)
    238 				attrname = auxt->pvfsr_attrname;
    239 			else
    240 				attrname = NULL;
    241 
    242 			flags = auxt->pvfsr_flags & PUFFS_EXTATTRCTL_HASNODE;
    243 			error = pops->puffs_fs_extattrctl(pu, auxt->pvfsr_cmd,
    244 			    opcookie, flags,
    245 			    auxt->pvfsr_attrnamespace, attrname);
    246 			break;
    247 		}
    248 
    249 		default:
    250 			/*
    251 			 * I guess the kernel sees this one coming
    252 			 */
    253 			error = EINVAL;
    254 			break;
    255 		}
    256 
    257 	/* XXX: audit return values */
    258 	/* XXX: sync with kernel */
    259 	} else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) {
    260 		switch (preq->preq_optype) {
    261 		case PUFFS_VN_LOOKUP:
    262 		{
    263 			struct puffs_vnmsg_lookup *auxt = auxbuf;
    264 			struct puffs_newinfo pni;
    265 			struct puffs_cn pcn;
    266 			struct puffs_node *pn = NULL;
    267 
    268 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    269 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    270 			pni.pni_cookie = &auxt->pvnr_newnode;
    271 			pni.pni_vtype = &auxt->pvnr_vtype;
    272 			pni.pni_size = &auxt->pvnr_size;
    273 			pni.pni_rdev = &auxt->pvnr_rdev;
    274 			pni.pni_va = &auxt->pvnr_va;
    275 			pni.pni_va_ttl = &auxt->pvnr_va_ttl;
    276 			pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
    277 
    278 			if (buildpath) {
    279 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    280 				if (error)
    281 					break;
    282 			}
    283 
    284 			/* lookup *must* be present */
    285 			error = pops->puffs_node_lookup(pu, opcookie,
    286 			    &pni, &pcn);
    287 
    288 			if (buildpath) {
    289 				if (error) {
    290 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    291 				} else {
    292 					/*
    293 					 * did we get a new node or a
    294 					 * recycled node?
    295 					 */
    296 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    297 					if (pn->pn_po.po_path == NULL)
    298 						pn->pn_po = pcn.pcn_po_full;
    299 					else
    300 						pu->pu_pathfree(pu,
    301 						    &pcn.pcn_po_full);
    302 				}
    303 			}
    304 
    305 			if (!error) {
    306 				if (pn == NULL)
    307 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    308 				pn->pn_nlookup++;
    309 			}
    310 			break;
    311 		}
    312 
    313 		case PUFFS_VN_CREATE:
    314 		{
    315 			struct puffs_vnmsg_create *auxt = auxbuf;
    316 			struct puffs_newinfo pni;
    317 			struct puffs_cn pcn;
    318 			struct puffs_node *pn = NULL;
    319 
    320 			if (pops->puffs_node_create == NULL) {
    321 				error = 0;
    322 				break;
    323 			}
    324 
    325 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    326 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    327 
    328 			memset(&pni, 0, sizeof(pni));
    329 			pni.pni_cookie = &auxt->pvnr_newnode;
    330 			pni.pni_va = &auxt->pvnr_va;
    331 			pni.pni_va_ttl = &auxt->pvnr_va_ttl;
    332 			pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
    333 
    334 			if (buildpath) {
    335 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    336 				if (error)
    337 					break;
    338 			}
    339 
    340 			error = pops->puffs_node_create(pu,
    341 			    opcookie, &pni, &pcn, &auxt->pvnr_va);
    342 
    343 			if (buildpath) {
    344 				if (error) {
    345 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    346 				} else {
    347 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    348 					pn->pn_po = pcn.pcn_po_full;
    349 				}
    350 			}
    351 
    352 			if (!error) {
    353 				if (pn == NULL)
    354 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    355 				pn->pn_nlookup++;
    356 			}
    357 			break;
    358 		}
    359 
    360 		case PUFFS_VN_MKNOD:
    361 		{
    362 			struct puffs_vnmsg_mknod *auxt = auxbuf;
    363 			struct puffs_newinfo pni;
    364 			struct puffs_cn pcn;
    365 			struct puffs_node *pn = NULL;
    366 
    367 			if (pops->puffs_node_mknod == NULL) {
    368 				error = 0;
    369 				break;
    370 			}
    371 
    372 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    373 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    374 
    375 			memset(&pni, 0, sizeof(pni));
    376 			pni.pni_cookie = &auxt->pvnr_newnode;
    377 			pni.pni_va = &auxt->pvnr_va;
    378 			pni.pni_va_ttl = &auxt->pvnr_va_ttl;
    379 			pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
    380 
    381 			if (buildpath) {
    382 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    383 				if (error)
    384 					break;
    385 			}
    386 
    387 			error = pops->puffs_node_mknod(pu,
    388 			    opcookie, &pni, &pcn, &auxt->pvnr_va);
    389 
    390 			if (buildpath) {
    391 				if (error) {
    392 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    393 				} else {
    394 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    395 					pn->pn_po = pcn.pcn_po_full;
    396 				}
    397 			}
    398 
    399 			if (!error) {
    400 				if (pn == NULL)
    401 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    402 				pn->pn_nlookup++;
    403 			}
    404 			break;
    405 		}
    406 
    407 		case PUFFS_VN_OPEN:
    408 		{
    409 			struct puffs_vnmsg_open *auxt = auxbuf;
    410 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    411 
    412 			if (pops->puffs_node_open == NULL) {
    413 				error = 0;
    414 				break;
    415 			}
    416 
    417 			error = pops->puffs_node_open(pu,
    418 			    opcookie, auxt->pvnr_mode, pcr);
    419 			break;
    420 		}
    421 
    422 		case PUFFS_VN_CLOSE:
    423 		{
    424 			struct puffs_vnmsg_close *auxt = auxbuf;
    425 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    426 
    427 			if (pops->puffs_node_close == NULL) {
    428 				error = 0;
    429 				break;
    430 			}
    431 
    432 			error = pops->puffs_node_close(pu,
    433 			    opcookie, auxt->pvnr_fflag, pcr);
    434 			break;
    435 		}
    436 
    437 		case PUFFS_VN_ACCESS:
    438 		{
    439 			struct puffs_vnmsg_access *auxt = auxbuf;
    440 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    441 
    442 			if (pops->puffs_node_access == NULL) {
    443 				error = 0;
    444 				break;
    445 			}
    446 
    447 			error = pops->puffs_node_access(pu,
    448 			    opcookie, auxt->pvnr_mode, pcr);
    449 			break;
    450 		}
    451 
    452 		case PUFFS_VN_GETATTR:
    453 		{
    454 			struct puffs_vnmsg_getattr *auxt = auxbuf;
    455 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    456 
    457 			if (PUFFS_USE_FS_TTL(pu)) {
    458 				if (pops->puffs_node_getattr_ttl == NULL) {
    459 					error = EOPNOTSUPP;
    460 					break;
    461 				}
    462 
    463 				error = pops->puffs_node_getattr_ttl(pu,
    464 				    opcookie, &auxt->pvnr_va, pcr,
    465 				    &auxt->pvnr_va_ttl);
    466 			} else {
    467 				if (pops->puffs_node_getattr == NULL) {
    468 					error = EOPNOTSUPP;
    469 					break;
    470 				}
    471 
    472 				error = pops->puffs_node_getattr(pu,
    473 				    opcookie, &auxt->pvnr_va, pcr);
    474 			}
    475 			break;
    476 		}
    477 
    478 		case PUFFS_VN_SETATTR:
    479 		{
    480 			struct puffs_vnmsg_setattr *auxt = auxbuf;
    481 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    482 
    483 			if (PUFFS_USE_FS_TTL(pu)) {
    484 				int xflag = 0;
    485 
    486 				if (pops->puffs_node_setattr_ttl == NULL) {
    487 					error = EOPNOTSUPP;
    488 					break;
    489 				}
    490 
    491 				if (!PUFFSOP_WANTREPLY(preq->preq_opclass))
    492 					xflag |= PUFFS_SETATTR_FAF;
    493 
    494 				error = pops->puffs_node_setattr_ttl(pu,
    495 				    opcookie, &auxt->pvnr_va, pcr,
    496 				    &auxt->pvnr_va_ttl, xflag);
    497 			} else {
    498 				if (pops->puffs_node_setattr == NULL) {
    499 					error = EOPNOTSUPP;
    500 					break;
    501 				}
    502 
    503 				error = pops->puffs_node_setattr(pu,
    504 				    opcookie, &auxt->pvnr_va, pcr);
    505 			}
    506 			break;
    507 		}
    508 
    509 		case PUFFS_VN_MMAP:
    510 		{
    511 			struct puffs_vnmsg_mmap *auxt = auxbuf;
    512 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    513 
    514 			if (pops->puffs_node_mmap == NULL) {
    515 				error = 0;
    516 				break;
    517 			}
    518 
    519 			error = pops->puffs_node_mmap(pu,
    520 			    opcookie, auxt->pvnr_prot, pcr);
    521 			break;
    522 		}
    523 
    524 		case PUFFS_VN_FSYNC:
    525 		{
    526 			struct puffs_vnmsg_fsync *auxt = auxbuf;
    527 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    528 
    529 			if (pops->puffs_node_fsync == NULL) {
    530 				error = 0;
    531 				break;
    532 			}
    533 
    534 			error = pops->puffs_node_fsync(pu, opcookie, pcr,
    535 			    auxt->pvnr_flags, auxt->pvnr_offlo,
    536 			    auxt->pvnr_offhi);
    537 			break;
    538 		}
    539 
    540 		case PUFFS_VN_SEEK:
    541 		{
    542 			struct puffs_vnmsg_seek *auxt = auxbuf;
    543 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    544 
    545 			if (pops->puffs_node_seek == NULL) {
    546 				error = 0;
    547 				break;
    548 			}
    549 
    550 			error = pops->puffs_node_seek(pu,
    551 			    opcookie, auxt->pvnr_oldoff,
    552 			    auxt->pvnr_newoff, pcr);
    553 			break;
    554 		}
    555 
    556 		case PUFFS_VN_REMOVE:
    557 		{
    558 			struct puffs_vnmsg_remove *auxt = auxbuf;
    559 			struct puffs_cn pcn;
    560 			if (pops->puffs_node_remove == NULL) {
    561 				error = 0;
    562 				break;
    563 			}
    564 
    565 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    566 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    567 
    568 			error = pops->puffs_node_remove(pu,
    569 			    opcookie, auxt->pvnr_cookie_targ, &pcn);
    570 			break;
    571 		}
    572 
    573 		case PUFFS_VN_LINK:
    574 		{
    575 			struct puffs_vnmsg_link *auxt = auxbuf;
    576 			struct puffs_cn pcn;
    577 			if (pops->puffs_node_link == NULL) {
    578 				error = 0;
    579 				break;
    580 			}
    581 
    582 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    583 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    584 
    585 			if (buildpath) {
    586 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    587 				if (error)
    588 					break;
    589 			}
    590 
    591 			error = pops->puffs_node_link(pu,
    592 			    opcookie, auxt->pvnr_cookie_targ, &pcn);
    593 			if (buildpath)
    594 				pu->pu_pathfree(pu, &pcn.pcn_po_full);
    595 
    596 			break;
    597 		}
    598 
    599 		case PUFFS_VN_RENAME:
    600 		{
    601 			struct puffs_vnmsg_rename *auxt = auxbuf;
    602 			struct puffs_cn pcn_src, pcn_targ;
    603 			struct puffs_node *pn_src;
    604 
    605 			if (pops->puffs_node_rename == NULL) {
    606 				error = 0;
    607 				break;
    608 			}
    609 
    610 			pcn_src.pcn_pkcnp = &auxt->pvnr_cn_src;
    611 			PUFFS_KCREDTOCRED(pcn_src.pcn_cred,
    612 			    &auxt->pvnr_cn_src_cred);
    613 
    614 			pcn_targ.pcn_pkcnp = &auxt->pvnr_cn_targ;
    615 			PUFFS_KCREDTOCRED(pcn_targ.pcn_cred,
    616 			    &auxt->pvnr_cn_targ_cred);
    617 
    618 			if (buildpath) {
    619 				pn_src = auxt->pvnr_cookie_src;
    620 				pcn_src.pcn_po_full = pn_src->pn_po;
    621 
    622 				error = puffs_path_pcnbuild(pu, &pcn_targ,
    623 				    auxt->pvnr_cookie_targdir);
    624 				if (error)
    625 					break;
    626 			}
    627 
    628 			error = pops->puffs_node_rename(pu,
    629 			    opcookie, auxt->pvnr_cookie_src,
    630 			    &pcn_src, auxt->pvnr_cookie_targdir,
    631 			    auxt->pvnr_cookie_targ, &pcn_targ);
    632 
    633 			if (buildpath) {
    634 				if (error) {
    635 					pu->pu_pathfree(pu,
    636 					    &pcn_targ.pcn_po_full);
    637 				} else {
    638 					struct puffs_pathinfo pi;
    639 					struct puffs_pathobj po_old;
    640 
    641 					/* handle this node */
    642 					po_old = pn_src->pn_po;
    643 					pn_src->pn_po = pcn_targ.pcn_po_full;
    644 
    645 					if (pn_src->pn_va.va_type != VDIR) {
    646 						pu->pu_pathfree(pu, &po_old);
    647 						break;
    648 					}
    649 
    650 					/* handle all child nodes for DIRs */
    651 					pi.pi_old = &pcn_src.pcn_po_full;
    652 					pi.pi_new = &pcn_targ.pcn_po_full;
    653 
    654 					PU_LOCK();
    655 					if (puffs_pn_nodewalk(pu,
    656 					    puffs_path_prefixadj, &pi) != NULL)
    657 						error = ENOMEM;
    658 					PU_UNLOCK();
    659 					pu->pu_pathfree(pu, &po_old);
    660 				}
    661 			}
    662 			break;
    663 		}
    664 
    665 		case PUFFS_VN_MKDIR:
    666 		{
    667 			struct puffs_vnmsg_mkdir *auxt = auxbuf;
    668 			struct puffs_newinfo pni;
    669 			struct puffs_cn pcn;
    670 			struct puffs_node *pn = NULL;
    671 
    672 			if (pops->puffs_node_mkdir == NULL) {
    673 				error = 0;
    674 				break;
    675 			}
    676 
    677 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    678 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    679 
    680 			memset(&pni, 0, sizeof(pni));
    681 			pni.pni_cookie = &auxt->pvnr_newnode;
    682 			pni.pni_va = &auxt->pvnr_va;
    683 			pni.pni_va_ttl = &auxt->pvnr_va_ttl;
    684 			pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
    685 
    686 			if (buildpath) {
    687 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    688 				if (error)
    689 					break;
    690 			}
    691 
    692 			error = pops->puffs_node_mkdir(pu,
    693 			    opcookie, &pni, &pcn, &auxt->pvnr_va);
    694 
    695 			if (buildpath) {
    696 				if (error) {
    697 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    698 				} else {
    699 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    700 					pn->pn_po = pcn.pcn_po_full;
    701 				}
    702 			}
    703 
    704 			if (!error) {
    705 				if (pn == NULL)
    706 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    707 				pn->pn_nlookup++;
    708 			}
    709 			break;
    710 		}
    711 
    712 		case PUFFS_VN_RMDIR:
    713 		{
    714 			struct puffs_vnmsg_rmdir *auxt = auxbuf;
    715 			struct puffs_cn pcn;
    716 			if (pops->puffs_node_rmdir == NULL) {
    717 				error = 0;
    718 				break;
    719 			}
    720 
    721 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    722 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    723 
    724 			error = pops->puffs_node_rmdir(pu,
    725 			    opcookie, auxt->pvnr_cookie_targ, &pcn);
    726 			break;
    727 		}
    728 
    729 		case PUFFS_VN_SYMLINK:
    730 		{
    731 			struct puffs_vnmsg_symlink *auxt = auxbuf;
    732 			struct puffs_newinfo pni;
    733 			struct puffs_cn pcn;
    734 			struct puffs_node *pn = NULL;
    735 
    736 			if (pops->puffs_node_symlink == NULL) {
    737 				error = 0;
    738 				break;
    739 			}
    740 
    741 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    742 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    743 
    744 			memset(&pni, 0, sizeof(pni));
    745 			pni.pni_cookie = &auxt->pvnr_newnode;
    746 			pni.pni_va = &auxt->pvnr_va;
    747 			pni.pni_va_ttl = &auxt->pvnr_va_ttl;
    748 			pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
    749 
    750 			if (buildpath) {
    751 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    752 				if (error)
    753 					break;
    754 			}
    755 
    756 			error = pops->puffs_node_symlink(pu,
    757 			    opcookie, &pni, &pcn,
    758 			    &auxt->pvnr_va, auxt->pvnr_link);
    759 
    760 			if (buildpath) {
    761 				if (error) {
    762 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    763 				} else {
    764 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    765 					pn->pn_po = pcn.pcn_po_full;
    766 				}
    767 			}
    768 
    769 			if (!error) {
    770 				if (pn == NULL)
    771 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    772 				pn->pn_nlookup++;
    773 			}
    774 			break;
    775 		}
    776 
    777 		case PUFFS_VN_READDIR:
    778 		{
    779 			struct puffs_vnmsg_readdir *auxt = auxbuf;
    780 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    781 			struct dirent *dent;
    782 			off_t *cookies;
    783 			size_t res, origcookies;
    784 
    785 			if (pops->puffs_node_readdir == NULL) {
    786 				error = 0;
    787 				break;
    788 			}
    789 
    790 			if (auxt->pvnr_ncookies) {
    791 				/* LINTED: pvnr_data is __aligned() */
    792 				cookies = (off_t *)auxt->pvnr_data;
    793 				origcookies = auxt->pvnr_ncookies;
    794 			} else {
    795 				cookies = NULL;
    796 				origcookies = 0;
    797 			}
    798 			/* LINTED: dentoff is aligned in the kernel */
    799 			dent = (struct dirent *)
    800 			    (auxt->pvnr_data + auxt->pvnr_dentoff);
    801 
    802 			res = auxt->pvnr_resid;
    803 			error = pops->puffs_node_readdir(pu,
    804 			    opcookie, dent, &auxt->pvnr_offset,
    805 			    &auxt->pvnr_resid, pcr, &auxt->pvnr_eofflag,
    806 			    cookies, &auxt->pvnr_ncookies);
    807 
    808 			/* much easier to track non-working NFS */
    809 			assert(auxt->pvnr_ncookies <= origcookies);
    810 
    811 			/* need to move a bit more */
    812 			preq->preq_buflen = sizeof(struct puffs_vnmsg_readdir)
    813 			    + auxt->pvnr_dentoff + (res - auxt->pvnr_resid);
    814 			break;
    815 		}
    816 
    817 		case PUFFS_VN_READLINK:
    818 		{
    819 			struct puffs_vnmsg_readlink *auxt = auxbuf;
    820 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    821 
    822 			if (pops->puffs_node_readlink == NULL) {
    823 				error = EOPNOTSUPP;
    824 				break;
    825 			}
    826 
    827 			/*LINTED*/
    828 			error = pops->puffs_node_readlink(pu, opcookie, pcr,
    829 			    auxt->pvnr_link, &auxt->pvnr_linklen);
    830 			break;
    831 		}
    832 
    833 		case PUFFS_VN_RECLAIM:
    834 		{
    835 			struct puffs_vnmsg_reclaim *auxt = auxbuf;
    836 			struct puffs_node *pn;
    837 
    838 			if (pops->puffs_node_reclaim == NULL) {
    839 				error = 0;
    840 				break;
    841 			}
    842 
    843 			/*
    844 			 * This fixes a race condition,
    845 			 * where a node in reclaimed by kernel
    846 			 * after a lookup request is sent,
    847 			 * but before the reply, leaving the kernel
    848 			 * with a invalid vnode/cookie reference.
    849 			 */
    850 			pn = PU_CMAP(pu, opcookie);
    851 			pn->pn_nlookup -= auxt->pvnr_nlookup;
    852 			if (pn->pn_nlookup >= 1) {
    853 				error = 0;
    854 				break;
    855 			}
    856 
    857 			error = pops->puffs_node_reclaim(pu, opcookie);
    858 			break;
    859 		}
    860 
    861 		case PUFFS_VN_INACTIVE:
    862 		{
    863 
    864 			if (pops->puffs_node_inactive == NULL) {
    865 				error = EOPNOTSUPP;
    866 				break;
    867 			}
    868 
    869 			error = pops->puffs_node_inactive(pu, opcookie);
    870 			break;
    871 		}
    872 
    873 		case PUFFS_VN_PATHCONF:
    874 		{
    875 			struct puffs_vnmsg_pathconf *auxt = auxbuf;
    876 			if (pops->puffs_node_pathconf == NULL) {
    877 				error = 0;
    878 				break;
    879 			}
    880 
    881 			error = pops->puffs_node_pathconf(pu,
    882 			    opcookie, auxt->pvnr_name,
    883 			    &auxt->pvnr_retval);
    884 			break;
    885 		}
    886 
    887 		case PUFFS_VN_ADVLOCK:
    888 		{
    889 			struct puffs_vnmsg_advlock *auxt = auxbuf;
    890 			if (pops->puffs_node_advlock == NULL) {
    891 				error = 0;
    892 				break;
    893 			}
    894 
    895 			error = pops->puffs_node_advlock(pu,
    896 			    opcookie, auxt->pvnr_id, auxt->pvnr_op,
    897 			    &auxt->pvnr_fl, auxt->pvnr_flags);
    898 			break;
    899 		}
    900 
    901 		case PUFFS_VN_PRINT:
    902 		{
    903 			if (pops->puffs_node_print == NULL) {
    904 				error = 0;
    905 				break;
    906 			}
    907 
    908 			error = pops->puffs_node_print(pu,
    909 			    opcookie);
    910 			break;
    911 		}
    912 
    913 		case PUFFS_VN_ABORTOP:
    914 		{
    915 			struct puffs_vnmsg_abortop *auxt = auxbuf;
    916 			struct puffs_cn pcn;
    917 
    918 			if (pops->puffs_node_abortop == NULL) {
    919 				error = 0;
    920 				break;
    921 			}
    922 
    923 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    924 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    925 
    926 			error = pops->puffs_node_abortop(pu, opcookie, &pcn);
    927 
    928 			break;
    929 		}
    930 
    931 		case PUFFS_VN_READ:
    932 		{
    933 			struct puffs_vnmsg_read *auxt = auxbuf;
    934 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    935 			size_t res;
    936 
    937 			if (pops->puffs_node_read == NULL) {
    938 				error = EIO;
    939 				break;
    940 			}
    941 
    942 			res = auxt->pvnr_resid;
    943 			error = pops->puffs_node_read(pu,
    944 			    opcookie, auxt->pvnr_data,
    945 			    auxt->pvnr_offset, &auxt->pvnr_resid,
    946 			    pcr, auxt->pvnr_ioflag);
    947 
    948 			/* need to move a bit more */
    949 			preq->preq_buflen = sizeof(struct puffs_vnmsg_read)
    950 			    + (res - auxt->pvnr_resid);
    951 			break;
    952 		}
    953 
    954 		case PUFFS_VN_WRITE:
    955 		{
    956 			struct puffs_vnmsg_write *auxt = auxbuf;
    957 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    958 
    959 			if (pops->puffs_node_write2 != NULL) {
    960 				int xflag = 0;
    961 
    962 				if (!PUFFSOP_WANTREPLY(preq->preq_opclass))
    963 					xflag |= PUFFS_SETATTR_FAF;
    964 
    965 				error = pops->puffs_node_write2(pu,
    966 				    opcookie, auxt->pvnr_data,
    967 				    auxt->pvnr_offset, &auxt->pvnr_resid,
    968 				    pcr, auxt->pvnr_ioflag, xflag);
    969 
    970 			} else if (pops->puffs_node_write != NULL) {
    971 				error = pops->puffs_node_write(pu,
    972 				    opcookie, auxt->pvnr_data,
    973 				    auxt->pvnr_offset, &auxt->pvnr_resid,
    974 				    pcr, auxt->pvnr_ioflag);
    975 			} else {
    976 				error = EIO;
    977 				break;
    978 			}
    979 
    980 
    981 			/* don't need to move data back to the kernel */
    982 			preq->preq_buflen = sizeof(struct puffs_vnmsg_write);
    983 			break;
    984 		}
    985 
    986 		case PUFFS_VN_POLL:
    987 		{
    988 			struct puffs_vnmsg_poll *auxt = auxbuf;
    989 
    990 			if (pops->puffs_node_poll == NULL) {
    991 				error = 0;
    992 
    993 				/* emulate genfs_poll() */
    994 				auxt->pvnr_events &= (POLLIN | POLLOUT
    995 						    | POLLRDNORM | POLLWRNORM);
    996 
    997 				break;
    998 			}
    999 
   1000 			error = pops->puffs_node_poll(pu,
   1001 			    opcookie, &auxt->pvnr_events);
   1002 			break;
   1003 		}
   1004 
   1005 		case PUFFS_VN_GETEXTATTR:
   1006 		{
   1007 			struct puffs_vnmsg_getextattr *auxt = auxbuf;
   1008 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
   1009 			size_t res, *resp, *sizep;
   1010 			uint8_t *data;
   1011 
   1012 			if (pops->puffs_node_getextattr == NULL) {
   1013 				error = EOPNOTSUPP;
   1014 				break;
   1015 			}
   1016 
   1017 			if (auxt->pvnr_datasize)
   1018 				sizep = &auxt->pvnr_datasize;
   1019 			else
   1020 				sizep = NULL;
   1021 
   1022 			res = auxt->pvnr_resid;
   1023 			if (res > 0) {
   1024 				data = auxt->pvnr_data;
   1025 				resp = &auxt->pvnr_resid;
   1026 			} else {
   1027 				data = NULL;
   1028 				resp = NULL;
   1029 			}
   1030 
   1031 			error = pops->puffs_node_getextattr(pu,
   1032 			    opcookie, auxt->pvnr_attrnamespace,
   1033 			    auxt->pvnr_attrname, sizep, data, resp, pcr);
   1034 
   1035 			/* need to move a bit more? */
   1036 			preq->preq_buflen =
   1037 			    sizeof(struct puffs_vnmsg_getextattr)
   1038 			    + (res - auxt->pvnr_resid);
   1039 			break;
   1040 		}
   1041 
   1042 		case PUFFS_VN_SETEXTATTR:
   1043 		{
   1044 			struct puffs_vnmsg_setextattr *auxt = auxbuf;
   1045 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
   1046 			size_t *resp;
   1047 			uint8_t *data;
   1048 
   1049 			if (pops->puffs_node_setextattr == NULL) {
   1050 				error = EOPNOTSUPP;
   1051 				break;
   1052 			}
   1053 
   1054 			if (auxt->pvnr_resid > 0) {
   1055 				data = auxt->pvnr_data;
   1056 				resp = &auxt->pvnr_resid;
   1057 			} else {
   1058 				data = NULL;
   1059 				resp = NULL;
   1060 			}
   1061 
   1062 			error = pops->puffs_node_setextattr(pu,
   1063 			    opcookie, auxt->pvnr_attrnamespace,
   1064 			    auxt->pvnr_attrname, data, resp, pcr);
   1065 			break;
   1066 		}
   1067 
   1068 		case PUFFS_VN_LISTEXTATTR:
   1069 		{
   1070 			struct puffs_vnmsg_listextattr *auxt = auxbuf;
   1071 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
   1072 			size_t res, *resp, *sizep;
   1073 			int flag;
   1074 			uint8_t *data;
   1075 
   1076 			if (pops->puffs_node_listextattr == NULL) {
   1077 				error = EOPNOTSUPP;
   1078 				break;
   1079 			}
   1080 
   1081 			if (auxt->pvnr_datasize)
   1082 				sizep = &auxt->pvnr_datasize;
   1083 			else
   1084 				sizep = NULL;
   1085 
   1086 			res = auxt->pvnr_resid;
   1087 			if (res > 0) {
   1088 				data = auxt->pvnr_data;
   1089 				resp = &auxt->pvnr_resid;
   1090 			} else {
   1091 				data = NULL;
   1092 				resp = NULL;
   1093 			}
   1094 
   1095 			res = auxt->pvnr_resid;
   1096 			flag = auxt->pvnr_flag;
   1097 			error = pops->puffs_node_listextattr(pu,
   1098 			    opcookie, auxt->pvnr_attrnamespace,
   1099 			    sizep, data, resp, flag, pcr);
   1100 
   1101 			/* need to move a bit more? */
   1102 			preq->preq_buflen =
   1103 			    sizeof(struct puffs_vnmsg_listextattr)
   1104 			    + (res - auxt->pvnr_resid);
   1105 			break;
   1106 		}
   1107 
   1108 		case PUFFS_VN_DELETEEXTATTR:
   1109 		{
   1110 			struct puffs_vnmsg_deleteextattr *auxt = auxbuf;
   1111 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
   1112 
   1113 			if (pops->puffs_node_deleteextattr == NULL) {
   1114 				error = EOPNOTSUPP;
   1115 				break;
   1116 			}
   1117 
   1118 			error = pops->puffs_node_deleteextattr(pu,
   1119 			    opcookie, auxt->pvnr_attrnamespace,
   1120 			    auxt->pvnr_attrname, pcr);
   1121 			break;
   1122 		}
   1123 
   1124 		default:
   1125 			printf("inval op %d\n", preq->preq_optype);
   1126 			error = EINVAL;
   1127 			break;
   1128 		}
   1129 
   1130 #if 0
   1131 	/* not issued by kernel currently */
   1132 	} else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_CACHE) {
   1133 		struct puffs_cacheinfo *pci = (void *)preq;
   1134 
   1135 		if (pu->pu_ops.puffs_cache_write) {
   1136 			pu->pu_ops.puffs_cache_write(pu, preq->preq_cookie,
   1137 			    pci->pcache_nruns, pci->pcache_runs);
   1138 		}
   1139 		error = 0;
   1140 #endif
   1141 
   1142 	} else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_ERROR) {
   1143 		struct puffs_error *perr = (void *)preq;
   1144 
   1145 		pu->pu_errnotify(pu, preq->preq_optype,
   1146 		    perr->perr_error, perr->perr_str, preq->preq_cookie);
   1147 		error = 0;
   1148 	} else {
   1149 		/*
   1150 		 * I guess the kernel sees this one coming also
   1151 		 */
   1152 		error = EINVAL;
   1153 	}
   1154 
   1155  out:
   1156 	preq->preq_rv = error;
   1157 
   1158 	if (pu->pu_oppost)
   1159 		pu->pu_oppost(pu);
   1160 
   1161 	pcc->pcc_flags |= PCC_DONE;
   1162 }
   1163