Home | History | Annotate | Line # | Download | only in libpuffs
dispatcher.c revision 1.32
      1 /*	$NetBSD: dispatcher.c,v 1.32 2008/08/12 19:44:39 pooka 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.32 2008/08/12 19:44:39 pooka 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 #ifdef PUFFS_WITH_THREADS
     43 #include <pthread.h>
     44 #endif
     45 #include <puffs.h>
     46 #include <puffsdump.h>
     47 #include <stdio.h>
     48 #include <stdlib.h>
     49 #include <unistd.h>
     50 
     51 #include "puffs_priv.h"
     52 
     53 #if 0 /* me not worka now */
     54 /*
     55  * Set the following to 1 to handle each request in a separate pthread.
     56  * This is not exported as it should not be used yet unless having a
     57  * very good knowledge of what you're signing up for (libpuffs is not
     58  * threadsafe).
     59  */
     60 int puffs_usethreads;
     61 #endif
     62 
     63 static void dispatch(struct puffs_cc *);
     64 
     65 /* for our eyes only */
     66 void
     67 puffs__ml_dispatch(struct puffs_usermount *pu, struct puffs_framebuf *pb)
     68 {
     69 	struct puffs_cc *pcc = puffs_cc_getcc(pu);
     70 	struct puffs_req *preq;
     71 
     72 	pcc->pcc_pb = pb;
     73 	pcc->pcc_flags |= PCC_MLCONT;
     74 	dispatch(pcc);
     75 
     76 	/* Put result to kernel sendqueue if necessary */
     77 	preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
     78 	if (PUFFSOP_WANTREPLY(preq->preq_opclass)) {
     79 		if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
     80 			puffsdump_rv(preq);
     81 
     82 		puffs_framev_enqueue_justsend(pu, pu->pu_fd,
     83 		    pcc->pcc_pb, 0, 0);
     84 	} else {
     85 		puffs_framebuf_destroy(pcc->pcc_pb);
     86 	}
     87 
     88 	/* who needs information when you're living on borrowed time? */
     89 	if (pcc->pcc_flags & PCC_BORROWED) {
     90 		puffs_cc_yield(pcc); /* back to borrow source */
     91 	}
     92 	pcc->pcc_flags = 0;
     93 }
     94 
     95 /* public, but not really tested and only semi-supported */
     96 int
     97 puffs_dispatch_create(struct puffs_usermount *pu, struct puffs_framebuf *pb,
     98 	struct puffs_cc **pccp)
     99 {
    100 	struct puffs_cc *pcc;
    101 
    102 	if (puffs__cc_create(pu, dispatch, &pcc) == -1)
    103 		return -1;
    104 
    105 	pcc->pcc_pb = pb;
    106 	*pccp = pcc;
    107 
    108 	return 0;
    109 }
    110 
    111 int
    112 puffs_dispatch_exec(struct puffs_cc *pcc, struct puffs_framebuf **pbp)
    113 {
    114 	int rv;
    115 
    116 	puffs_cc_continue(pcc);
    117 
    118 	if (pcc->pcc_flags & PCC_DONE) {
    119 		rv = 1;
    120 		*pbp = pcc->pcc_pb;
    121 		pcc->pcc_flags = 0;
    122 		puffs__cc_destroy(pcc, 0);
    123 	} else {
    124 		rv = 0;
    125 	}
    126 
    127 	return rv;
    128 }
    129 
    130 static void
    131 dispatch(struct puffs_cc *pcc)
    132 {
    133 	struct puffs_usermount *pu = pcc->pcc_pu;
    134 	struct puffs_ops *pops = &pu->pu_ops;
    135 	struct puffs_req *preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
    136 	void *auxbuf; /* help with typecasting */
    137 	puffs_cookie_t opcookie;
    138 	int error = 0, buildpath;
    139 
    140 	/* XXX: smaller hammer, please */
    141 	if ((PUFFSOP_OPCLASS(preq->preq_opclass == PUFFSOP_VFS &&
    142 	    preq->preq_optype == PUFFS_VFS_VPTOFH)) ||
    143 	    (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN &&
    144 	    (preq->preq_optype == PUFFS_VN_READDIR
    145 	    || preq->preq_optype == PUFFS_VN_READ))) {
    146 		if (puffs_framebuf_reserve_space(pcc->pcc_pb,
    147 		    PUFFS_MSG_MAXSIZE) == -1)
    148 			error = errno;
    149 		preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
    150 	}
    151 
    152 	auxbuf = preq;
    153 	opcookie = preq->preq_cookie;
    154 
    155 	assert((pcc->pcc_flags & PCC_DONE) == 0);
    156 
    157 	buildpath = pu->pu_flags & PUFFS_FLAG_BUILDPATH;
    158 	preq->preq_setbacks = 0;
    159 
    160 	if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
    161 		puffsdump_req(preq);
    162 
    163 	puffs__cc_setcaller(pcc, preq->preq_pid, preq->preq_lid);
    164 
    165 	/* pre-operation */
    166 	if (pu->pu_oppre)
    167 		pu->pu_oppre(pu);
    168 
    169 	if (error)
    170 		goto out;
    171 
    172 	/* Execute actual operation */
    173 	if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) {
    174 		switch (preq->preq_optype) {
    175 		case PUFFS_VFS_UNMOUNT:
    176 		{
    177 			struct puffs_vfsmsg_unmount *auxt = auxbuf;
    178 
    179 			PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTING);
    180 			error = pops->puffs_fs_unmount(pu, auxt->pvfsr_flags);
    181 			if (!error)
    182 				PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTED);
    183 			else
    184 				PU_SETSTATE(pu, PUFFS_STATE_RUNNING);
    185 			break;
    186 		}
    187 
    188 		case PUFFS_VFS_STATVFS:
    189 		{
    190 			struct puffs_vfsmsg_statvfs *auxt = auxbuf;
    191 
    192 			error = pops->puffs_fs_statvfs(pu, &auxt->pvfsr_sb);
    193 			break;
    194 		}
    195 
    196 		case PUFFS_VFS_SYNC:
    197 		{
    198 			struct puffs_vfsmsg_sync *auxt = auxbuf;
    199 			PUFFS_MAKECRED(pcr, &auxt->pvfsr_cred);
    200 
    201 			error = pops->puffs_fs_sync(pu,
    202 			    auxt->pvfsr_waitfor, pcr);
    203 			break;
    204 		}
    205 
    206 		case PUFFS_VFS_FHTOVP:
    207 		{
    208 			struct puffs_vfsmsg_fhtonode *auxt = auxbuf;
    209 			struct puffs_newinfo pni;
    210 
    211 			pni.pni_cookie = &auxt->pvfsr_fhcookie;
    212 			pni.pni_vtype = &auxt->pvfsr_vtype;
    213 			pni.pni_size = &auxt->pvfsr_size;
    214 			pni.pni_rdev = &auxt->pvfsr_rdev;
    215 
    216 			error = pops->puffs_fs_fhtonode(pu, auxt->pvfsr_data,
    217 			    auxt->pvfsr_dsize, &pni);
    218 
    219 			break;
    220 		}
    221 
    222 		case PUFFS_VFS_VPTOFH:
    223 		{
    224 			struct puffs_vfsmsg_nodetofh *auxt = auxbuf;
    225 
    226 			error = pops->puffs_fs_nodetofh(pu,
    227 			    auxt->pvfsr_fhcookie, auxt->pvfsr_data,
    228 			    &auxt->pvfsr_dsize);
    229 
    230 			break;
    231 		}
    232 
    233 		case PUFFS_VFS_SUSPEND:
    234 		{
    235 			struct puffs_vfsmsg_suspend *auxt = auxbuf;
    236 
    237 			error = 0;
    238 			if (pops->puffs_fs_suspend == NULL)
    239 				break;
    240 
    241 			pops->puffs_fs_suspend(pu, auxt->pvfsr_status);
    242 			break;
    243 		}
    244 
    245 		default:
    246 			/*
    247 			 * I guess the kernel sees this one coming
    248 			 */
    249 			error = EINVAL;
    250 			break;
    251 		}
    252 
    253 	/* XXX: audit return values */
    254 	/* XXX: sync with kernel */
    255 	} else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) {
    256 		switch (preq->preq_optype) {
    257 		case PUFFS_VN_LOOKUP:
    258 		{
    259 			struct puffs_vnmsg_lookup *auxt = auxbuf;
    260 			struct puffs_newinfo pni;
    261 			struct puffs_cn pcn;
    262 
    263 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    264 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    265 			pni.pni_cookie = &auxt->pvnr_newnode;
    266 			pni.pni_vtype = &auxt->pvnr_vtype;
    267 			pni.pni_size = &auxt->pvnr_size;
    268 			pni.pni_rdev = &auxt->pvnr_rdev;
    269 
    270 			if (buildpath) {
    271 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    272 				if (error)
    273 					break;
    274 			}
    275 
    276 			/* lookup *must* be present */
    277 			error = pops->puffs_node_lookup(pu, opcookie,
    278 			    &pni, &pcn);
    279 
    280 			if (buildpath) {
    281 				if (error) {
    282 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    283 				} else {
    284 					struct puffs_node *pn;
    285 
    286 					/*
    287 					 * did we get a new node or a
    288 					 * recycled node?
    289 					 */
    290 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    291 					if (pn->pn_po.po_path == NULL)
    292 						pn->pn_po = pcn.pcn_po_full;
    293 					else
    294 						pu->pu_pathfree(pu,
    295 						    &pcn.pcn_po_full);
    296 				}
    297 			}
    298 
    299 			break;
    300 		}
    301 
    302 		case PUFFS_VN_CREATE:
    303 		{
    304 			struct puffs_vnmsg_create *auxt = auxbuf;
    305 			struct puffs_newinfo pni;
    306 			struct puffs_cn pcn;
    307 
    308 			if (pops->puffs_node_create == NULL) {
    309 				error = 0;
    310 				break;
    311 			}
    312 
    313 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    314 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    315 
    316 			memset(&pni, 0, sizeof(pni));
    317 			pni.pni_cookie = &auxt->pvnr_newnode;
    318 
    319 			if (buildpath) {
    320 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    321 				if (error)
    322 					break;
    323 			}
    324 
    325 			error = pops->puffs_node_create(pu,
    326 			    opcookie, &pni, &pcn, &auxt->pvnr_va);
    327 
    328 			if (buildpath) {
    329 				if (error) {
    330 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    331 				} else {
    332 					struct puffs_node *pn;
    333 
    334 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    335 					pn->pn_po = pcn.pcn_po_full;
    336 				}
    337 			}
    338 
    339 			break;
    340 		}
    341 
    342 		case PUFFS_VN_MKNOD:
    343 		{
    344 			struct puffs_vnmsg_mknod *auxt = auxbuf;
    345 			struct puffs_newinfo pni;
    346 			struct puffs_cn pcn;
    347 
    348 			if (pops->puffs_node_mknod == NULL) {
    349 				error = 0;
    350 				break;
    351 			}
    352 
    353 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    354 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    355 
    356 			memset(&pni, 0, sizeof(pni));
    357 			pni.pni_cookie = &auxt->pvnr_newnode;
    358 
    359 			if (buildpath) {
    360 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    361 				if (error)
    362 					break;
    363 			}
    364 
    365 			error = pops->puffs_node_mknod(pu,
    366 			    opcookie, &pni, &pcn, &auxt->pvnr_va);
    367 
    368 			if (buildpath) {
    369 				if (error) {
    370 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    371 				} else {
    372 					struct puffs_node *pn;
    373 
    374 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    375 					pn->pn_po = pcn.pcn_po_full;
    376 				}
    377 			}
    378 
    379 			break;
    380 		}
    381 
    382 		case PUFFS_VN_OPEN:
    383 		{
    384 			struct puffs_vnmsg_open *auxt = auxbuf;
    385 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    386 
    387 			if (pops->puffs_node_open == NULL) {
    388 				error = 0;
    389 				break;
    390 			}
    391 
    392 			error = pops->puffs_node_open(pu,
    393 			    opcookie, auxt->pvnr_mode, pcr);
    394 			break;
    395 		}
    396 
    397 		case PUFFS_VN_CLOSE:
    398 		{
    399 			struct puffs_vnmsg_close *auxt = auxbuf;
    400 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    401 
    402 			if (pops->puffs_node_close == NULL) {
    403 				error = 0;
    404 				break;
    405 			}
    406 
    407 			error = pops->puffs_node_close(pu,
    408 			    opcookie, auxt->pvnr_fflag, pcr);
    409 			break;
    410 		}
    411 
    412 		case PUFFS_VN_ACCESS:
    413 		{
    414 			struct puffs_vnmsg_access *auxt = auxbuf;
    415 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    416 
    417 			if (pops->puffs_node_access == NULL) {
    418 				error = 0;
    419 				break;
    420 			}
    421 
    422 			error = pops->puffs_node_access(pu,
    423 			    opcookie, auxt->pvnr_mode, pcr);
    424 			break;
    425 		}
    426 
    427 		case PUFFS_VN_GETATTR:
    428 		{
    429 			struct puffs_vnmsg_getattr *auxt = auxbuf;
    430 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    431 
    432 			if (pops->puffs_node_getattr == NULL) {
    433 				error = EOPNOTSUPP;
    434 				break;
    435 			}
    436 
    437 			error = pops->puffs_node_getattr(pu,
    438 			    opcookie, &auxt->pvnr_va, pcr);
    439 			break;
    440 		}
    441 
    442 		case PUFFS_VN_SETATTR:
    443 		{
    444 			struct puffs_vnmsg_setattr *auxt = auxbuf;
    445 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    446 
    447 			if (pops->puffs_node_setattr == NULL) {
    448 				error = EOPNOTSUPP;
    449 				break;
    450 			}
    451 
    452 			error = pops->puffs_node_setattr(pu,
    453 			    opcookie, &auxt->pvnr_va, pcr);
    454 			break;
    455 		}
    456 
    457 		case PUFFS_VN_MMAP:
    458 		{
    459 			struct puffs_vnmsg_mmap *auxt = auxbuf;
    460 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    461 
    462 			if (pops->puffs_node_mmap == NULL) {
    463 				error = 0;
    464 				break;
    465 			}
    466 
    467 			error = pops->puffs_node_mmap(pu,
    468 			    opcookie, auxt->pvnr_prot, pcr);
    469 			break;
    470 		}
    471 
    472 		case PUFFS_VN_FSYNC:
    473 		{
    474 			struct puffs_vnmsg_fsync *auxt = auxbuf;
    475 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    476 
    477 			if (pops->puffs_node_fsync == NULL) {
    478 				error = 0;
    479 				break;
    480 			}
    481 
    482 			error = pops->puffs_node_fsync(pu, opcookie, pcr,
    483 			    auxt->pvnr_flags, auxt->pvnr_offlo,
    484 			    auxt->pvnr_offhi);
    485 			break;
    486 		}
    487 
    488 		case PUFFS_VN_SEEK:
    489 		{
    490 			struct puffs_vnmsg_seek *auxt = auxbuf;
    491 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    492 
    493 			if (pops->puffs_node_seek == NULL) {
    494 				error = 0;
    495 				break;
    496 			}
    497 
    498 			error = pops->puffs_node_seek(pu,
    499 			    opcookie, auxt->pvnr_oldoff,
    500 			    auxt->pvnr_newoff, pcr);
    501 			break;
    502 		}
    503 
    504 		case PUFFS_VN_REMOVE:
    505 		{
    506 			struct puffs_vnmsg_remove *auxt = auxbuf;
    507 			struct puffs_cn pcn;
    508 			if (pops->puffs_node_remove == NULL) {
    509 				error = 0;
    510 				break;
    511 			}
    512 
    513 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    514 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    515 
    516 			error = pops->puffs_node_remove(pu,
    517 			    opcookie, auxt->pvnr_cookie_targ, &pcn);
    518 			break;
    519 		}
    520 
    521 		case PUFFS_VN_LINK:
    522 		{
    523 			struct puffs_vnmsg_link *auxt = auxbuf;
    524 			struct puffs_cn pcn;
    525 			if (pops->puffs_node_link == NULL) {
    526 				error = 0;
    527 				break;
    528 			}
    529 
    530 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    531 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    532 
    533 			if (buildpath) {
    534 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    535 				if (error)
    536 					break;
    537 			}
    538 
    539 			error = pops->puffs_node_link(pu,
    540 			    opcookie, auxt->pvnr_cookie_targ, &pcn);
    541 			if (buildpath)
    542 				pu->pu_pathfree(pu, &pcn.pcn_po_full);
    543 
    544 			break;
    545 		}
    546 
    547 		case PUFFS_VN_RENAME:
    548 		{
    549 			struct puffs_vnmsg_rename *auxt = auxbuf;
    550 			struct puffs_cn pcn_src, pcn_targ;
    551 			struct puffs_node *pn_src;
    552 
    553 			if (pops->puffs_node_rename == NULL) {
    554 				error = 0;
    555 				break;
    556 			}
    557 
    558 			pcn_src.pcn_pkcnp = &auxt->pvnr_cn_src;
    559 			PUFFS_KCREDTOCRED(pcn_src.pcn_cred,
    560 			    &auxt->pvnr_cn_src_cred);
    561 
    562 			pcn_targ.pcn_pkcnp = &auxt->pvnr_cn_targ;
    563 			PUFFS_KCREDTOCRED(pcn_targ.pcn_cred,
    564 			    &auxt->pvnr_cn_targ_cred);
    565 
    566 			if (buildpath) {
    567 				pn_src = auxt->pvnr_cookie_src;
    568 				pcn_src.pcn_po_full = pn_src->pn_po;
    569 
    570 				error = puffs_path_pcnbuild(pu, &pcn_targ,
    571 				    auxt->pvnr_cookie_targdir);
    572 				if (error)
    573 					break;
    574 			}
    575 
    576 			error = pops->puffs_node_rename(pu,
    577 			    opcookie, auxt->pvnr_cookie_src,
    578 			    &pcn_src, auxt->pvnr_cookie_targdir,
    579 			    auxt->pvnr_cookie_targ, &pcn_targ);
    580 
    581 			if (buildpath) {
    582 				if (error) {
    583 					pu->pu_pathfree(pu,
    584 					    &pcn_targ.pcn_po_full);
    585 				} else {
    586 					struct puffs_pathinfo pi;
    587 					struct puffs_pathobj po_old;
    588 
    589 					/* handle this node */
    590 					po_old = pn_src->pn_po;
    591 					pn_src->pn_po = pcn_targ.pcn_po_full;
    592 
    593 					if (pn_src->pn_va.va_type != VDIR) {
    594 						pu->pu_pathfree(pu, &po_old);
    595 						break;
    596 					}
    597 
    598 					/* handle all child nodes for DIRs */
    599 					pi.pi_old = &pcn_src.pcn_po_full;
    600 					pi.pi_new = &pcn_targ.pcn_po_full;
    601 
    602 					PU_LOCK();
    603 					if (puffs_pn_nodewalk(pu,
    604 					    puffs_path_prefixadj, &pi) != NULL)
    605 						error = ENOMEM;
    606 					PU_UNLOCK();
    607 					pu->pu_pathfree(pu, &po_old);
    608 				}
    609 			}
    610 			break;
    611 		}
    612 
    613 		case PUFFS_VN_MKDIR:
    614 		{
    615 			struct puffs_vnmsg_mkdir *auxt = auxbuf;
    616 			struct puffs_newinfo pni;
    617 			struct puffs_cn pcn;
    618 
    619 			if (pops->puffs_node_mkdir == NULL) {
    620 				error = 0;
    621 				break;
    622 			}
    623 
    624 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    625 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    626 
    627 			memset(&pni, 0, sizeof(pni));
    628 			pni.pni_cookie = &auxt->pvnr_newnode;
    629 
    630 			if (buildpath) {
    631 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    632 				if (error)
    633 					break;
    634 			}
    635 
    636 			error = pops->puffs_node_mkdir(pu,
    637 			    opcookie, &pni, &pcn, &auxt->pvnr_va);
    638 
    639 			if (buildpath) {
    640 				if (error) {
    641 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    642 				} else {
    643 					struct puffs_node *pn;
    644 
    645 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    646 					pn->pn_po = pcn.pcn_po_full;
    647 				}
    648 			}
    649 
    650 			break;
    651 		}
    652 
    653 		case PUFFS_VN_RMDIR:
    654 		{
    655 			struct puffs_vnmsg_rmdir *auxt = auxbuf;
    656 			struct puffs_cn pcn;
    657 			if (pops->puffs_node_rmdir == NULL) {
    658 				error = 0;
    659 				break;
    660 			}
    661 
    662 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    663 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    664 
    665 			error = pops->puffs_node_rmdir(pu,
    666 			    opcookie, auxt->pvnr_cookie_targ, &pcn);
    667 			break;
    668 		}
    669 
    670 		case PUFFS_VN_SYMLINK:
    671 		{
    672 			struct puffs_vnmsg_symlink *auxt = auxbuf;
    673 			struct puffs_newinfo pni;
    674 			struct puffs_cn pcn;
    675 
    676 			if (pops->puffs_node_symlink == NULL) {
    677 				error = 0;
    678 				break;
    679 			}
    680 
    681 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    682 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    683 
    684 			memset(&pni, 0, sizeof(pni));
    685 			pni.pni_cookie = &auxt->pvnr_newnode;
    686 
    687 			if (buildpath) {
    688 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    689 				if (error)
    690 					break;
    691 			}
    692 
    693 			error = pops->puffs_node_symlink(pu,
    694 			    opcookie, &pni, &pcn,
    695 			    &auxt->pvnr_va, auxt->pvnr_link);
    696 
    697 			if (buildpath) {
    698 				if (error) {
    699 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    700 				} else {
    701 					struct puffs_node *pn;
    702 
    703 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    704 					pn->pn_po = pcn.pcn_po_full;
    705 				}
    706 			}
    707 
    708 			break;
    709 		}
    710 
    711 		case PUFFS_VN_READDIR:
    712 		{
    713 			struct puffs_vnmsg_readdir *auxt = auxbuf;
    714 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    715 			struct dirent *dent;
    716 			off_t *cookies;
    717 			size_t res, origcookies;
    718 
    719 			if (pops->puffs_node_readdir == NULL) {
    720 				error = 0;
    721 				break;
    722 			}
    723 
    724 			if (auxt->pvnr_ncookies) {
    725 				/* LINTED: pvnr_data is __aligned() */
    726 				cookies = (off_t *)auxt->pvnr_data;
    727 				origcookies = auxt->pvnr_ncookies;
    728 			} else {
    729 				cookies = NULL;
    730 				origcookies = 0;
    731 			}
    732 			/* LINTED: dentoff is aligned in the kernel */
    733 			dent = (struct dirent *)
    734 			    (auxt->pvnr_data + auxt->pvnr_dentoff);
    735 
    736 			res = auxt->pvnr_resid;
    737 			error = pops->puffs_node_readdir(pu,
    738 			    opcookie, dent, &auxt->pvnr_offset,
    739 			    &auxt->pvnr_resid, pcr, &auxt->pvnr_eofflag,
    740 			    cookies, &auxt->pvnr_ncookies);
    741 
    742 			/* much easier to track non-working NFS */
    743 			assert(auxt->pvnr_ncookies <= origcookies);
    744 
    745 			/* need to move a bit more */
    746 			preq->preq_buflen = sizeof(struct puffs_vnmsg_readdir)
    747 			    + auxt->pvnr_dentoff + (res - auxt->pvnr_resid);
    748 			break;
    749 		}
    750 
    751 		case PUFFS_VN_READLINK:
    752 		{
    753 			struct puffs_vnmsg_readlink *auxt = auxbuf;
    754 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    755 
    756 			if (pops->puffs_node_readlink == NULL) {
    757 				error = EOPNOTSUPP;
    758 				break;
    759 			}
    760 
    761 			/*LINTED*/
    762 			error = pops->puffs_node_readlink(pu, opcookie, pcr,
    763 			    auxt->pvnr_link, &auxt->pvnr_linklen);
    764 			break;
    765 		}
    766 
    767 		case PUFFS_VN_RECLAIM:
    768 		{
    769 
    770 			if (pops->puffs_node_reclaim == NULL) {
    771 				error = 0;
    772 				break;
    773 			}
    774 
    775 			error = pops->puffs_node_reclaim(pu, opcookie);
    776 			break;
    777 		}
    778 
    779 		case PUFFS_VN_INACTIVE:
    780 		{
    781 
    782 			if (pops->puffs_node_inactive == NULL) {
    783 				error = EOPNOTSUPP;
    784 				break;
    785 			}
    786 
    787 			error = pops->puffs_node_inactive(pu, opcookie);
    788 			break;
    789 		}
    790 
    791 		case PUFFS_VN_PATHCONF:
    792 		{
    793 			struct puffs_vnmsg_pathconf *auxt = auxbuf;
    794 			if (pops->puffs_node_pathconf == NULL) {
    795 				error = 0;
    796 				break;
    797 			}
    798 
    799 			error = pops->puffs_node_pathconf(pu,
    800 			    opcookie, auxt->pvnr_name,
    801 			    &auxt->pvnr_retval);
    802 			break;
    803 		}
    804 
    805 		case PUFFS_VN_ADVLOCK:
    806 		{
    807 			struct puffs_vnmsg_advlock *auxt = auxbuf;
    808 			if (pops->puffs_node_advlock == NULL) {
    809 				error = 0;
    810 				break;
    811 			}
    812 
    813 			error = pops->puffs_node_advlock(pu,
    814 			    opcookie, auxt->pvnr_id, auxt->pvnr_op,
    815 			    &auxt->pvnr_fl, auxt->pvnr_flags);
    816 			break;
    817 		}
    818 
    819 		case PUFFS_VN_PRINT:
    820 		{
    821 			if (pops->puffs_node_print == NULL) {
    822 				error = 0;
    823 				break;
    824 			}
    825 
    826 			error = pops->puffs_node_print(pu,
    827 			    opcookie);
    828 			break;
    829 		}
    830 
    831 		case PUFFS_VN_READ:
    832 		{
    833 			struct puffs_vnmsg_read *auxt = auxbuf;
    834 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    835 			size_t res;
    836 
    837 			if (pops->puffs_node_read == NULL) {
    838 				error = EIO;
    839 				break;
    840 			}
    841 
    842 			res = auxt->pvnr_resid;
    843 			error = pops->puffs_node_read(pu,
    844 			    opcookie, auxt->pvnr_data,
    845 			    auxt->pvnr_offset, &auxt->pvnr_resid,
    846 			    pcr, auxt->pvnr_ioflag);
    847 
    848 			/* need to move a bit more */
    849 			preq->preq_buflen = sizeof(struct puffs_vnmsg_read)
    850 			    + (res - auxt->pvnr_resid);
    851 			break;
    852 		}
    853 
    854 		case PUFFS_VN_WRITE:
    855 		{
    856 			struct puffs_vnmsg_write *auxt = auxbuf;
    857 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    858 
    859 			if (pops->puffs_node_write == NULL) {
    860 				error = EIO;
    861 				break;
    862 			}
    863 
    864 			error = pops->puffs_node_write(pu,
    865 			    opcookie, auxt->pvnr_data,
    866 			    auxt->pvnr_offset, &auxt->pvnr_resid,
    867 			    pcr, auxt->pvnr_ioflag);
    868 
    869 			/* don't need to move data back to the kernel */
    870 			preq->preq_buflen = sizeof(struct puffs_vnmsg_write);
    871 			break;
    872 		}
    873 
    874 		case PUFFS_VN_POLL:
    875 		{
    876 			struct puffs_vnmsg_poll *auxt = auxbuf;
    877 
    878 			if (pops->puffs_node_poll == NULL) {
    879 				error = 0;
    880 
    881 				/* emulate genfs_poll() */
    882 				auxt->pvnr_events &= (POLLIN | POLLOUT
    883 						    | POLLRDNORM | POLLWRNORM);
    884 
    885 				break;
    886 			}
    887 
    888 			error = pops->puffs_node_poll(pu,
    889 			    opcookie, &auxt->pvnr_events);
    890 			break;
    891 		}
    892 
    893 		default:
    894 			printf("inval op %d\n", preq->preq_optype);
    895 			error = EINVAL;
    896 			break;
    897 		}
    898 
    899 	} else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_CACHE) {
    900 		struct puffs_cacheinfo *pci = (void *)preq;
    901 
    902 		if (pu->pu_ops.puffs_cache_write) {
    903 			pu->pu_ops.puffs_cache_write(pu, preq->preq_cookie,
    904 			    pci->pcache_nruns, pci->pcache_runs);
    905 		}
    906 		error = 0;
    907 
    908 	} else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_ERROR) {
    909 		struct puffs_error *perr = (void *)preq;
    910 
    911 		pu->pu_errnotify(pu, preq->preq_optype,
    912 		    perr->perr_error, perr->perr_str, preq->preq_cookie);
    913 		error = 0;
    914 	} else {
    915 		/*
    916 		 * I guess the kernel sees this one coming also
    917 		 */
    918 		error = EINVAL;
    919 	}
    920 
    921  out:
    922 	preq->preq_rv = error;
    923 
    924 	if (pu->pu_oppost)
    925 		pu->pu_oppost(pu);
    926 
    927 	pcc->pcc_flags |= PCC_DONE;
    928 }
    929