Home | History | Annotate | Line # | Download | only in libpuffs
dispatcher.c revision 1.8
      1 /*	$NetBSD: dispatcher.c,v 1.8 2007/07/01 17:22:18 pooka Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2006, 2007  Antti Kantee.  All Rights Reserved.
      5  *
      6  * Development of this software was supported by the
      7  * Ulla Tuominen Foundation.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     19  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     21  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     28  * SUCH DAMAGE.
     29  */
     30 
     31 #include <sys/cdefs.h>
     32 #if !defined(lint)
     33 __RCSID("$NetBSD: dispatcher.c,v 1.8 2007/07/01 17:22:18 pooka Exp $");
     34 #endif /* !lint */
     35 
     36 #include <sys/types.h>
     37 #include <sys/poll.h>
     38 
     39 #include <assert.h>
     40 #include <errno.h>
     41 #include <puffs.h>
     42 #include <puffsdump.h>
     43 #include <stdio.h>
     44 #include <stdlib.h>
     45 #include <unistd.h>
     46 
     47 #include "puffs_priv.h"
     48 
     49 static void processresult(struct puffs_cc *, struct puffs_putreq *, int);
     50 
     51 /*
     52  * Set the following to 1 to not handle each request on a separate
     53  * stack.  This is highly volatile kludge, therefore no external
     54  * interface.
     55  */
     56 int puffs_fakecc;
     57 
     58 /* user-visible point to handle a request from */
     59 int
     60 puffs_dopreq(struct puffs_usermount *pu, struct puffs_req *preq,
     61 	struct puffs_putreq *ppr)
     62 {
     63 	struct puffs_cc fakecc;
     64 	struct puffs_cc *pcc;
     65 
     66 	/*
     67 	 * XXX: the structure is currently a mess.  anyway, trap
     68 	 * the cacheops here already, since they don't need a cc.
     69 	 * I really should get around to revamping the operation
     70 	 * dispatching code one of these days.
     71 	 */
     72 	if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_CACHE) {
     73 		struct puffs_cacheinfo *pci = (void *)preq;
     74 
     75 		if (pu->pu_ops.puffs_cache_write == NULL)
     76 			return 0;
     77 
     78 		pu->pu_ops.puffs_cache_write(pu, preq->preq_cookie,
     79 		    pci->pcache_nruns, pci->pcache_runs);
     80 	}
     81 
     82 	if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
     83 		puffsdump_req(preq);
     84 
     85 	if (puffs_fakecc) {
     86 		pcc = &fakecc;
     87 		pcc_init_local(pcc);
     88 
     89 		pcc->pcc_pu = pu;
     90 		pcc->pcc_preq = preq;
     91 		pcc->pcc_flags = PCC_FAKECC;
     92 	} else {
     93 		pcc = puffs_cc_create(pu);
     94 
     95 		/* XXX: temporary kludging */
     96 		pcc->pcc_preq = malloc(preq->preq_buflen);
     97 		if (pcc->pcc_preq == NULL)
     98 			return -1;
     99 		(void) memcpy(pcc->pcc_preq, preq, preq->preq_buflen);
    100 	}
    101 
    102 	puffs_docc(pcc, ppr);
    103 	return 0;
    104 }
    105 
    106 enum {PUFFCALL_ANSWER, PUFFCALL_IGNORE, PUFFCALL_AGAIN};
    107 
    108 /* user-visible continuation point */
    109 void
    110 puffs_docc(struct puffs_cc *pcc, struct puffs_putreq *ppr)
    111 {
    112 	struct puffs_usermount *pu = pcc->pcc_pu;
    113 	struct puffs_cc *pcc_iter;
    114 
    115 	assert((pcc->pcc_flags & PCC_DONE) == 0);
    116 	pcc->pcc_ppr = ppr;
    117 
    118 	if (pcc->pcc_flags & PCC_REALCC)
    119 		puffs_cc_continue(pcc);
    120 	else
    121 		puffs_calldispatcher(pcc);
    122 
    123 	/* can't do this above due to PCC_BORROWED */
    124 	while ((pcc_iter = LIST_FIRST(&pu->pu_ccnukelst)) != NULL) {
    125 		LIST_REMOVE(pcc_iter, nlst_entries);
    126 		puffs_cc_destroy(pcc_iter);
    127 	}
    128 }
    129 
    130 /* library private, but linked from callcontext.c */
    131 
    132 void
    133 puffs_calldispatcher(struct puffs_cc *pcc)
    134 {
    135 	struct puffs_usermount *pu = pcc->pcc_pu;
    136 	struct puffs_ops *pops = &pu->pu_ops;
    137 	struct puffs_req *preq = pcc->pcc_preq;
    138 	void *auxbuf = preq; /* help with typecasting */
    139 	void *opcookie = preq->preq_cookie;
    140 	int error, rv, buildpath;
    141 
    142 	assert(pcc->pcc_flags & (PCC_FAKECC | PCC_REALCC));
    143 
    144 	if (PUFFSOP_WANTREPLY(preq->preq_opclass))
    145 		rv = PUFFCALL_ANSWER;
    146 	else
    147 		rv = PUFFCALL_IGNORE;
    148 
    149 	buildpath = pu->pu_flags & PUFFS_FLAG_BUILDPATH;
    150 	preq->preq_setbacks = 0;
    151 
    152 	if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) {
    153 		switch (preq->preq_optype) {
    154 		case PUFFS_VFS_UNMOUNT:
    155 		{
    156 			struct puffs_vfsreq_unmount *auxt = auxbuf;
    157 			PUFFS_MAKECID(pcid, &auxt->pvfsr_cid);
    158 
    159 			PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTING);
    160 			error = pops->puffs_fs_unmount(pcc,
    161 			    auxt->pvfsr_flags, pcid);
    162 			if (!error)
    163 				PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTED);
    164 			else
    165 				PU_SETSTATE(pu, PUFFS_STATE_RUNNING);
    166 			break;
    167 		}
    168 
    169 		case PUFFS_VFS_STATVFS:
    170 		{
    171 			struct puffs_vfsreq_statvfs *auxt = auxbuf;
    172 			PUFFS_MAKECID(pcid, &auxt->pvfsr_cid);
    173 
    174 			error = pops->puffs_fs_statvfs(pcc,
    175 			    &auxt->pvfsr_sb, pcid);
    176 			break;
    177 		}
    178 
    179 		case PUFFS_VFS_SYNC:
    180 		{
    181 			struct puffs_vfsreq_sync *auxt = auxbuf;
    182 			PUFFS_MAKECRED(pcr, &auxt->pvfsr_cred);
    183 			PUFFS_MAKECID(pcid, &auxt->pvfsr_cid);
    184 
    185 			error = pops->puffs_fs_sync(pcc,
    186 			    auxt->pvfsr_waitfor, pcr, pcid);
    187 			break;
    188 		}
    189 
    190 		case PUFFS_VFS_FHTOVP:
    191 		{
    192 			struct puffs_vfsreq_fhtonode *auxt = auxbuf;
    193 
    194 			error = pops->puffs_fs_fhtonode(pcc, auxt->pvfsr_data,
    195 			    auxt->pvfsr_dsize, &auxt->pvfsr_fhcookie,
    196 			    &auxt->pvfsr_vtype, &auxt->pvfsr_size,
    197 			    &auxt->pvfsr_rdev);
    198 
    199 			break;
    200 		}
    201 
    202 		case PUFFS_VFS_VPTOFH:
    203 		{
    204 			struct puffs_vfsreq_nodetofh *auxt = auxbuf;
    205 
    206 			error = pops->puffs_fs_nodetofh(pcc,
    207 			    auxt->pvfsr_fhcookie, auxt->pvfsr_data,
    208 			    &auxt->pvfsr_dsize);
    209 
    210 			break;
    211 		}
    212 
    213 		case PUFFS_VFS_SUSPEND:
    214 		{
    215 			struct puffs_vfsreq_suspend *auxt = auxbuf;
    216 
    217 			error = 0;
    218 			if (pops->puffs_fs_suspend == NULL)
    219 				break;
    220 
    221 			pops->puffs_fs_suspend(pcc, auxt->pvfsr_status);
    222 			break;
    223 		}
    224 
    225 		default:
    226 			/*
    227 			 * I guess the kernel sees this one coming
    228 			 */
    229 			error = EINVAL;
    230 			break;
    231 		}
    232 
    233 	/* XXX: audit return values */
    234 	/* XXX: sync with kernel */
    235 	} else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) {
    236 		switch (preq->preq_optype) {
    237 		case PUFFS_VN_LOOKUP:
    238 		{
    239 			struct puffs_vnreq_lookup *auxt = auxbuf;
    240 			struct puffs_cn pcn;
    241 
    242 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    243 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    244 			PUFFS_KCIDTOCID(pcn.pcn_cid, &auxt->pvnr_cn_cid);
    245 
    246 			if (buildpath) {
    247 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    248 				if (error)
    249 					break;
    250 			}
    251 
    252 			/* lookup *must* be present */
    253 			error = pops->puffs_node_lookup(pcc, opcookie,
    254 			    &auxt->pvnr_newnode, &auxt->pvnr_vtype,
    255 			    &auxt->pvnr_size, &auxt->pvnr_rdev, &pcn);
    256 
    257 			if (buildpath) {
    258 				if (error) {
    259 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    260 				} else {
    261 					struct puffs_node *pn;
    262 
    263 					/*
    264 					 * did we get a new node or a
    265 					 * recycled node?
    266 					 */
    267 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    268 					if (pn->pn_po.po_path == NULL)
    269 						pn->pn_po = pcn.pcn_po_full;
    270 					else
    271 						pu->pu_pathfree(pu,
    272 						    &pcn.pcn_po_full);
    273 				}
    274 			}
    275 
    276 			break;
    277 		}
    278 
    279 		case PUFFS_VN_CREATE:
    280 		{
    281 			struct puffs_vnreq_create *auxt = auxbuf;
    282 			struct puffs_cn pcn;
    283 			if (pops->puffs_node_create == NULL) {
    284 				error = 0;
    285 				break;
    286 			}
    287 
    288 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    289 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    290 			PUFFS_KCIDTOCID(pcn.pcn_cid, &auxt->pvnr_cn_cid);
    291 
    292 			if (buildpath) {
    293 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    294 				if (error)
    295 					break;
    296 			}
    297 
    298 			error = pops->puffs_node_create(pcc,
    299 			    opcookie, &auxt->pvnr_newnode,
    300 			    &pcn, &auxt->pvnr_va);
    301 
    302 			if (buildpath) {
    303 				if (error) {
    304 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    305 				} else {
    306 					struct puffs_node *pn;
    307 
    308 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    309 					pn->pn_po = pcn.pcn_po_full;
    310 				}
    311 			}
    312 
    313 			break;
    314 		}
    315 
    316 		case PUFFS_VN_MKNOD:
    317 		{
    318 			struct puffs_vnreq_mknod *auxt = auxbuf;
    319 			struct puffs_cn pcn;
    320 			if (pops->puffs_node_mknod == 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 			PUFFS_KCIDTOCID(pcn.pcn_cid, &auxt->pvnr_cn_cid);
    328 
    329 			if (buildpath) {
    330 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    331 				if (error)
    332 					break;
    333 			}
    334 
    335 			error = pops->puffs_node_mknod(pcc,
    336 			    opcookie, &auxt->pvnr_newnode,
    337 			    &pcn, &auxt->pvnr_va);
    338 
    339 			if (buildpath) {
    340 				if (error) {
    341 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    342 				} else {
    343 					struct puffs_node *pn;
    344 
    345 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    346 					pn->pn_po = pcn.pcn_po_full;
    347 				}
    348 			}
    349 
    350 			break;
    351 		}
    352 
    353 		case PUFFS_VN_OPEN:
    354 		{
    355 			struct puffs_vnreq_open *auxt = auxbuf;
    356 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    357 			PUFFS_MAKECID(pcid, &auxt->pvnr_cid);
    358 
    359 			if (pops->puffs_node_open == NULL) {
    360 				error = 0;
    361 				break;
    362 			}
    363 
    364 			error = pops->puffs_node_open(pcc,
    365 			    opcookie, auxt->pvnr_mode, pcr, pcid);
    366 			break;
    367 		}
    368 
    369 		case PUFFS_VN_CLOSE:
    370 		{
    371 			struct puffs_vnreq_close *auxt = auxbuf;
    372 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    373 			PUFFS_MAKECID(pcid, &auxt->pvnr_cid);
    374 
    375 
    376 			if (pops->puffs_node_close == NULL) {
    377 				error = 0;
    378 				break;
    379 			}
    380 
    381 			error = pops->puffs_node_close(pcc,
    382 			    opcookie, auxt->pvnr_fflag, pcr, pcid);
    383 			break;
    384 		}
    385 
    386 		case PUFFS_VN_ACCESS:
    387 		{
    388 			struct puffs_vnreq_access *auxt = auxbuf;
    389 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    390 			PUFFS_MAKECID(pcid, &auxt->pvnr_cid);
    391 
    392 
    393 			if (pops->puffs_node_access == NULL) {
    394 				error = 0;
    395 				break;
    396 			}
    397 
    398 			error = pops->puffs_node_access(pcc,
    399 			    opcookie, auxt->pvnr_mode, pcr, pcid);
    400 			break;
    401 		}
    402 
    403 		case PUFFS_VN_GETATTR:
    404 		{
    405 			struct puffs_vnreq_getattr *auxt = auxbuf;
    406 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    407 			PUFFS_MAKECID(pcid, &auxt->pvnr_cid);
    408 
    409 
    410 			if (pops->puffs_node_getattr == NULL) {
    411 				error = EOPNOTSUPP;
    412 				break;
    413 			}
    414 
    415 			error = pops->puffs_node_getattr(pcc,
    416 			    opcookie, &auxt->pvnr_va, pcr, pcid);
    417 			break;
    418 		}
    419 
    420 		case PUFFS_VN_SETATTR:
    421 		{
    422 			struct puffs_vnreq_setattr *auxt = auxbuf;
    423 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    424 			PUFFS_MAKECID(pcid, &auxt->pvnr_cid);
    425 
    426 
    427 			if (pops->puffs_node_setattr == NULL) {
    428 				error = EOPNOTSUPP;
    429 				break;
    430 			}
    431 
    432 			error = pops->puffs_node_setattr(pcc,
    433 			    opcookie, &auxt->pvnr_va, pcr, pcid);
    434 			break;
    435 		}
    436 
    437 		case PUFFS_VN_MMAP:
    438 		{
    439 			struct puffs_vnreq_mmap *auxt = auxbuf;
    440 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    441 			PUFFS_MAKECID(pcid, &auxt->pvnr_cid);
    442 
    443 
    444 			if (pops->puffs_node_mmap == NULL) {
    445 				error = 0;
    446 				break;
    447 			}
    448 
    449 			error = pops->puffs_node_mmap(pcc,
    450 			    opcookie, auxt->pvnr_fflags, pcr, pcid);
    451 			break;
    452 		}
    453 
    454 		case PUFFS_VN_FSYNC:
    455 		{
    456 			struct puffs_vnreq_fsync *auxt = auxbuf;
    457 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    458 			PUFFS_MAKECID(pcid, &auxt->pvnr_cid);
    459 
    460 
    461 			if (pops->puffs_node_fsync == NULL) {
    462 				error = 0;
    463 				break;
    464 			}
    465 
    466 			error = pops->puffs_node_fsync(pcc, opcookie, pcr,
    467 			    auxt->pvnr_flags, auxt->pvnr_offlo,
    468 			    auxt->pvnr_offhi, pcid);
    469 			break;
    470 		}
    471 
    472 		case PUFFS_VN_SEEK:
    473 		{
    474 			struct puffs_vnreq_seek *auxt = auxbuf;
    475 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    476 
    477 			if (pops->puffs_node_seek == NULL) {
    478 				error = 0;
    479 				break;
    480 			}
    481 
    482 			error = pops->puffs_node_seek(pcc,
    483 			    opcookie, auxt->pvnr_oldoff,
    484 			    auxt->pvnr_newoff, pcr);
    485 			break;
    486 		}
    487 
    488 		case PUFFS_VN_REMOVE:
    489 		{
    490 			struct puffs_vnreq_remove *auxt = auxbuf;
    491 			struct puffs_cn pcn;
    492 			if (pops->puffs_node_remove == NULL) {
    493 				error = 0;
    494 				break;
    495 			}
    496 
    497 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    498 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    499 			PUFFS_KCIDTOCID(pcn.pcn_cid, &auxt->pvnr_cn_cid);
    500 
    501 			error = pops->puffs_node_remove(pcc,
    502 			    opcookie, auxt->pvnr_cookie_targ, &pcn);
    503 			break;
    504 		}
    505 
    506 		case PUFFS_VN_LINK:
    507 		{
    508 			struct puffs_vnreq_link *auxt = auxbuf;
    509 			struct puffs_cn pcn;
    510 			if (pops->puffs_node_link == NULL) {
    511 				error = 0;
    512 				break;
    513 			}
    514 
    515 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    516 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    517 			PUFFS_KCIDTOCID(pcn.pcn_cid, &auxt->pvnr_cn_cid);
    518 
    519 			if (buildpath) {
    520 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    521 				if (error)
    522 					break;
    523 			}
    524 
    525 			error = pops->puffs_node_link(pcc,
    526 			    opcookie, auxt->pvnr_cookie_targ, &pcn);
    527 			if (buildpath)
    528 				pu->pu_pathfree(pu, &pcn.pcn_po_full);
    529 
    530 			break;
    531 		}
    532 
    533 		case PUFFS_VN_RENAME:
    534 		{
    535 			struct puffs_vnreq_rename *auxt = auxbuf;
    536 			struct puffs_cn pcn_src, pcn_targ;
    537 			struct puffs_node *pn_src;
    538 
    539 			if (pops->puffs_node_rename == NULL) {
    540 				error = 0;
    541 				break;
    542 			}
    543 
    544 			pcn_src.pcn_pkcnp = &auxt->pvnr_cn_src;
    545 			PUFFS_KCREDTOCRED(pcn_src.pcn_cred,
    546 			    &auxt->pvnr_cn_src_cred);
    547 			PUFFS_KCIDTOCID(pcn_src.pcn_cid,
    548 			    &auxt->pvnr_cn_src_cid);
    549 
    550 			pcn_targ.pcn_pkcnp = &auxt->pvnr_cn_targ;
    551 			PUFFS_KCREDTOCRED(pcn_targ.pcn_cred,
    552 			    &auxt->pvnr_cn_targ_cred);
    553 			PUFFS_KCIDTOCID(pcn_targ.pcn_cid,
    554 			    &auxt->pvnr_cn_targ_cid);
    555 
    556 			if (buildpath) {
    557 				pn_src = auxt->pvnr_cookie_src;
    558 				pcn_src.pcn_po_full = pn_src->pn_po;
    559 
    560 				error = puffs_path_pcnbuild(pu, &pcn_targ,
    561 				    auxt->pvnr_cookie_targdir);
    562 				if (error)
    563 					break;
    564 			}
    565 
    566 			error = pops->puffs_node_rename(pcc,
    567 			    opcookie, auxt->pvnr_cookie_src,
    568 			    &pcn_src, auxt->pvnr_cookie_targdir,
    569 			    auxt->pvnr_cookie_targ, &pcn_targ);
    570 
    571 			if (buildpath) {
    572 				if (error) {
    573 					pu->pu_pathfree(pu,
    574 					    &pcn_targ.pcn_po_full);
    575 				} else {
    576 					struct puffs_pathinfo pi;
    577 					struct puffs_pathobj po_old;
    578 
    579 					/* handle this node */
    580 					po_old = pn_src->pn_po;
    581 					pn_src->pn_po = pcn_targ.pcn_po_full;
    582 
    583 					if (pn_src->pn_va.va_type != VDIR) {
    584 						pu->pu_pathfree(pu, &po_old);
    585 						break;
    586 					}
    587 
    588 					/* handle all child nodes for DIRs */
    589 					pi.pi_old = &pcn_src.pcn_po_full;
    590 					pi.pi_new = &pcn_targ.pcn_po_full;
    591 
    592 					if (puffs_pn_nodewalk(pu,
    593 					    puffs_path_prefixadj, &pi) != NULL)
    594 						error = ENOMEM;
    595 					pu->pu_pathfree(pu, &po_old);
    596 				}
    597 			}
    598 			break;
    599 		}
    600 
    601 		case PUFFS_VN_MKDIR:
    602 		{
    603 			struct puffs_vnreq_mkdir *auxt = auxbuf;
    604 			struct puffs_cn pcn;
    605 			if (pops->puffs_node_mkdir == NULL) {
    606 				error = 0;
    607 				break;
    608 			}
    609 
    610 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    611 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    612 			PUFFS_KCIDTOCID(pcn.pcn_cid, &auxt->pvnr_cn_cid);
    613 
    614 			if (buildpath) {
    615 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    616 				if (error)
    617 					break;
    618 			}
    619 
    620 			error = pops->puffs_node_mkdir(pcc,
    621 			    opcookie, &auxt->pvnr_newnode,
    622 			    &pcn, &auxt->pvnr_va);
    623 
    624 			if (buildpath) {
    625 				if (error) {
    626 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    627 				} else {
    628 					struct puffs_node *pn;
    629 
    630 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    631 					pn->pn_po = pcn.pcn_po_full;
    632 				}
    633 			}
    634 
    635 			break;
    636 		}
    637 
    638 		case PUFFS_VN_RMDIR:
    639 		{
    640 			struct puffs_vnreq_rmdir *auxt = auxbuf;
    641 			struct puffs_cn pcn;
    642 			if (pops->puffs_node_rmdir == NULL) {
    643 				error = 0;
    644 				break;
    645 			}
    646 
    647 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    648 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    649 			PUFFS_KCIDTOCID(pcn.pcn_cid, &auxt->pvnr_cn_cid);
    650 
    651 			error = pops->puffs_node_rmdir(pcc,
    652 			    opcookie, auxt->pvnr_cookie_targ, &pcn);
    653 			break;
    654 		}
    655 
    656 		case PUFFS_VN_SYMLINK:
    657 		{
    658 			struct puffs_vnreq_symlink *auxt = auxbuf;
    659 			struct puffs_cn pcn;
    660 			if (pops->puffs_node_symlink == NULL) {
    661 				error = 0;
    662 				break;
    663 			}
    664 
    665 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    666 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    667 			PUFFS_KCIDTOCID(pcn.pcn_cid, &auxt->pvnr_cn_cid);
    668 
    669 			if (buildpath) {
    670 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    671 				if (error)
    672 					break;
    673 			}
    674 
    675 			error = pops->puffs_node_symlink(pcc,
    676 			    opcookie, &auxt->pvnr_newnode,
    677 			    &pcn, &auxt->pvnr_va, auxt->pvnr_link);
    678 
    679 			if (buildpath) {
    680 				if (error) {
    681 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    682 				} else {
    683 					struct puffs_node *pn;
    684 
    685 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    686 					pn->pn_po = pcn.pcn_po_full;
    687 				}
    688 			}
    689 
    690 			break;
    691 		}
    692 
    693 		case PUFFS_VN_READDIR:
    694 		{
    695 			struct puffs_vnreq_readdir *auxt = auxbuf;
    696 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    697 			struct dirent *dent;
    698 			off_t *cookies;
    699 			size_t res, origcookies;
    700 
    701 			if (pops->puffs_node_readdir == NULL) {
    702 				error = 0;
    703 				break;
    704 			}
    705 
    706 			if (auxt->pvnr_ncookies) {
    707 				/* LINTED: pvnr_data is __aligned() */
    708 				cookies = (off_t *)auxt->pvnr_data;
    709 				origcookies = auxt->pvnr_ncookies;
    710 			} else {
    711 				cookies = NULL;
    712 				origcookies = 0;
    713 			}
    714 			/* LINTED: dentoff is aligned in the kernel */
    715 			dent = (struct dirent *)
    716 			    (auxt->pvnr_data + auxt->pvnr_dentoff);
    717 
    718 			res = auxt->pvnr_resid;
    719 			error = pops->puffs_node_readdir(pcc,
    720 			    opcookie, dent, &auxt->pvnr_offset,
    721 			    &auxt->pvnr_resid, pcr, &auxt->pvnr_eofflag,
    722 			    cookies, &auxt->pvnr_ncookies);
    723 
    724 			/* much easier to track non-working NFS */
    725 			assert(auxt->pvnr_ncookies <= origcookies);
    726 
    727 			/* need to move a bit more */
    728 			preq->preq_buflen = sizeof(struct puffs_vnreq_readdir)
    729 			    + auxt->pvnr_dentoff + (res - auxt->pvnr_resid);
    730 			break;
    731 		}
    732 
    733 		case PUFFS_VN_READLINK:
    734 		{
    735 			struct puffs_vnreq_readlink *auxt = auxbuf;
    736 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    737 
    738 			if (pops->puffs_node_readlink == NULL) {
    739 				error = EOPNOTSUPP;
    740 				break;
    741 			}
    742 
    743 			/*LINTED*/
    744 			error = pops->puffs_node_readlink(pcc, opcookie, pcr,
    745 			    auxt->pvnr_link, &auxt->pvnr_linklen);
    746 			break;
    747 		}
    748 
    749 		case PUFFS_VN_RECLAIM:
    750 		{
    751 			struct puffs_vnreq_reclaim *auxt = auxbuf;
    752 			PUFFS_MAKECID(pcid, &auxt->pvnr_cid);
    753 
    754 			if (pops->puffs_node_reclaim == NULL) {
    755 				error = 0;
    756 				break;
    757 			}
    758 
    759 			error = pops->puffs_node_reclaim(pcc, opcookie, pcid);
    760 			break;
    761 		}
    762 
    763 		case PUFFS_VN_INACTIVE:
    764 		{
    765 			struct puffs_vnreq_inactive *auxt = auxbuf;
    766 			PUFFS_MAKECID(pcid, &auxt->pvnr_cid);
    767 
    768 			if (pops->puffs_node_inactive == NULL) {
    769 				error = EOPNOTSUPP;
    770 				break;
    771 			}
    772 
    773 			auxt->pvnr_backendrefs = 1; /* safe default */
    774 			error = pops->puffs_node_inactive(pcc,
    775 			    opcookie, pcid, &auxt->pvnr_backendrefs);
    776 			break;
    777 		}
    778 
    779 		case PUFFS_VN_PATHCONF:
    780 		{
    781 			struct puffs_vnreq_pathconf *auxt = auxbuf;
    782 			if (pops->puffs_node_pathconf == NULL) {
    783 				error = 0;
    784 				break;
    785 			}
    786 
    787 			error = pops->puffs_node_pathconf(pcc,
    788 			    opcookie, auxt->pvnr_name,
    789 			    &auxt->pvnr_retval);
    790 			break;
    791 		}
    792 
    793 		case PUFFS_VN_ADVLOCK:
    794 		{
    795 			struct puffs_vnreq_advlock *auxt = auxbuf;
    796 			if (pops->puffs_node_advlock == NULL) {
    797 				error = 0;
    798 				break;
    799 			}
    800 
    801 			error = pops->puffs_node_advlock(pcc,
    802 			    opcookie, auxt->pvnr_id, auxt->pvnr_op,
    803 			    &auxt->pvnr_fl, auxt->pvnr_flags);
    804 			break;
    805 		}
    806 
    807 		case PUFFS_VN_PRINT:
    808 		{
    809 			if (pops->puffs_node_print == NULL) {
    810 				error = 0;
    811 				break;
    812 			}
    813 
    814 			error = pops->puffs_node_print(pcc,
    815 			    opcookie);
    816 			break;
    817 		}
    818 
    819 		case PUFFS_VN_READ:
    820 		{
    821 			struct puffs_vnreq_read *auxt = auxbuf;
    822 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    823 			size_t res;
    824 
    825 			if (pops->puffs_node_read == NULL) {
    826 				error = EIO;
    827 				break;
    828 			}
    829 
    830 			res = auxt->pvnr_resid;
    831 			error = pops->puffs_node_read(pcc,
    832 			    opcookie, auxt->pvnr_data,
    833 			    auxt->pvnr_offset, &auxt->pvnr_resid,
    834 			    pcr, auxt->pvnr_ioflag);
    835 
    836 			/* need to move a bit more */
    837 			preq->preq_buflen = sizeof(struct puffs_vnreq_read)
    838 			    + (res - auxt->pvnr_resid);
    839 			break;
    840 		}
    841 
    842 		case PUFFS_VN_WRITE:
    843 		{
    844 			struct puffs_vnreq_write *auxt = auxbuf;
    845 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    846 
    847 			if (pops->puffs_node_write == NULL) {
    848 				error = EIO;
    849 				break;
    850 			}
    851 
    852 			error = pops->puffs_node_write(pcc,
    853 			    opcookie, auxt->pvnr_data,
    854 			    auxt->pvnr_offset, &auxt->pvnr_resid,
    855 			    pcr, auxt->pvnr_ioflag);
    856 
    857 			/* don't need to move data back to the kernel */
    858 			preq->preq_buflen = sizeof(struct puffs_vnreq_write);
    859 			break;
    860 		}
    861 
    862 		case PUFFS_VN_POLL:
    863 		{
    864 			struct puffs_vnreq_poll *auxt = auxbuf;
    865 			PUFFS_MAKECID(pcid, &auxt->pvnr_cid);
    866 
    867 			if (pops->puffs_node_poll == NULL) {
    868 				error = 0;
    869 
    870 				/* emulate genfs_poll() */
    871 				auxt->pvnr_events &= (POLLIN | POLLOUT
    872 						    | POLLRDNORM | POLLWRNORM);
    873 
    874 				break;
    875 			}
    876 
    877 			error = pops->puffs_node_poll(pcc,
    878 			    opcookie, &auxt->pvnr_events, pcid);
    879 			break;
    880 		}
    881 
    882 /* holy bitrot, ryydman! */
    883 #if 0
    884 		case PUFFS_VN_IOCTL:
    885 			error = pops->puffs_node_ioctl1(pcc, opcookie,
    886 			     (struct puffs_vnreq_ioctl *)auxbuf, &pop);
    887 			if (error != 0)
    888 				break;
    889 			pop.pso_reqid = preq->preq_id;
    890 
    891 			/* let the kernel do it's intermediate duty */
    892 			error = ioctl(pu->pu_kargs.pa_fd, PUFFSSIZEOP, &pop);
    893 			/*
    894 			 * XXX: I don't actually know what the correct
    895 			 * thing to do in case of an error is, so I'll
    896 			 * just ignore it for the time being.
    897 			 */
    898 			error = pops->puffs_node_ioctl2(pcc, opcookie,
    899 			    (struct puffs_vnreq_ioctl *)auxbuf, &pop);
    900 			break;
    901 
    902 		case PUFFS_VN_FCNTL:
    903 			error = pops->puffs_node_fcntl1(pcc, opcookie,
    904 			     (struct puffs_vnreq_fcntl *)auxbuf, &pop);
    905 			if (error != 0)
    906 				break;
    907 			pop.pso_reqid = preq->preq_id;
    908 
    909 			/* let the kernel do it's intermediate duty */
    910 			error = ioctl(pu->pu_kargs.pa_fd, PUFFSSIZEOP, &pop);
    911 			/*
    912 			 * XXX: I don't actually know what the correct
    913 			 * thing to do in case of an error is, so I'll
    914 			 * just ignore it for the time being.
    915 			 */
    916 			error = pops->puffs_node_fcntl2(pcc, opcookie,
    917 			    (struct puffs_vnreq_fcntl *)auxbuf, &pop);
    918 			break;
    919 #endif
    920 
    921 		default:
    922 			printf("inval op %d\n", preq->preq_optype);
    923 			error = EINVAL;
    924 			break;
    925 		}
    926 	} else {
    927 		/*
    928 		 * this one also
    929 		 */
    930 		error = EINVAL;
    931 	}
    932 
    933 	preq->preq_rv = error;
    934 	pcc->pcc_flags |= PCC_DONE;
    935 
    936 	/*
    937 	 * Note, we are calling this from here so that we can run it
    938 	 * off of the continuation stack.  Otherwise puffs_goto() would
    939 	 * not work.
    940 	 */
    941 	processresult(pcc, pcc->pcc_ppr, rv);
    942 }
    943 
    944 static void
    945 processresult(struct puffs_cc *pcc, struct puffs_putreq *ppr, int how)
    946 {
    947 	struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
    948 
    949 	/* check if we need to store this reply */
    950 	switch (how) {
    951 	case PUFFCALL_ANSWER:
    952 		if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
    953 			puffsdump_rv(pcc->pcc_preq);
    954 
    955 		if (pcc->pcc_flags & PCC_REALCC)
    956 			puffs_req_putcc(ppr, pcc);
    957 		else
    958 			puffs_req_put(ppr, pcc->pcc_preq);
    959 		break;
    960 	case PUFFCALL_IGNORE:
    961 		if (pcc->pcc_flags & PCC_REALCC)
    962 			LIST_INSERT_HEAD(&pu->pu_ccnukelst, pcc, nlst_entries);
    963 		break;
    964 	case PUFFCALL_AGAIN:
    965 		if (pcc->pcc_flags & PCC_FAKECC)
    966 			assert(pcc->pcc_flags & PCC_DONE);
    967 		break;
    968 	default:
    969 		assert(/*CONSTCOND*/0);
    970 	}
    971 
    972 	/* who needs information when you're living on borrowed time? */
    973 	if (pcc->pcc_flags & PCC_BORROWED)
    974 		puffs_cc_yield(pcc); /* back to borrow source */
    975 }
    976 
    977 
    978 #if 0
    979 		case PUFFS_VN_KQFILTER:
    980 		{
    981 			struct puffs_vnreq_kqfilter *auxt = auxbuf;
    982 			if (pops->puffs_node_kqfilter == NULL) {
    983 				error = 0;
    984 				break;
    985 			}
    986 
    987 			error = pops->puffs_node_kqfilter(pcc,
    988 			    opcookie, );
    989 			break;
    990 		}
    991 
    992 		case PUFFS_VN_CLOSEEXTATTR:
    993 		{
    994 			struct puffs_vnreq_closeextattr *auxt = auxbuf;
    995 			if (pops->puffs_closeextattr == NULL) {
    996 				error = 0;
    997 				break;
    998 			}
    999 
   1000 			error = pops->puffs_closeextattr(pcc,
   1001 			    opcookie, );
   1002 			break;
   1003 		}
   1004 
   1005 		case PUFFS_VN_GETEXTATTR:
   1006 		{
   1007 			struct puffs_vnreq_getextattr *auxt = auxbuf;
   1008 			if (pops->puffs_getextattr == NULL) {
   1009 				error = 0;
   1010 				break;
   1011 			}
   1012 
   1013 			error = pops->puffs_getextattr(pcc,
   1014 			    opcookie, );
   1015 			break;
   1016 		}
   1017 
   1018 		case PUFFS_VN_LISTEXTATTR:
   1019 		{
   1020 			struct puffs_vnreq_listextattr *auxt = auxbuf;
   1021 			if (pops->puffs_listextattr == NULL) {
   1022 				error = 0;
   1023 				break;
   1024 			}
   1025 
   1026 			error = pops->puffs_listextattr(pcc,
   1027 			    opcookie, );
   1028 			break;
   1029 		}
   1030 
   1031 		case PUFFS_VN_OPENEXTATTR:
   1032 		{
   1033 			struct puffs_vnreq_openextattr *auxt = auxbuf;
   1034 			if (pops->puffs_openextattr == NULL) {
   1035 				error = 0;
   1036 				break;
   1037 			}
   1038 
   1039 			error = pops->puffs_openextattr(pcc,
   1040 			    opcookie, );
   1041 			break;
   1042 		}
   1043 
   1044 		case PUFFS_VN_DELETEEXTATTR:
   1045 		{
   1046 			struct puffs_vnreq_deleteextattr *auxt = auxbuf;
   1047 			if (pops->puffs_deleteextattr == NULL) {
   1048 				error = 0;
   1049 				break;
   1050 			}
   1051 
   1052 			error = pops->puffs_deleteextattr(pcc,
   1053 			    opcookie, );
   1054 			break;
   1055 		}
   1056 
   1057 		case PUFFS_VN_SETEXTATTR:
   1058 		{
   1059 			struct puffs_vnreq_setextattr *auxt = auxbuf;
   1060 			if (pops->puffs_setextattr == NULL) {
   1061 				error = 0;
   1062 				break;
   1063 			}
   1064 
   1065 			error = pops->puffs_setextattr(pcc,
   1066 			    opcookie, );
   1067 			break;
   1068 		}
   1069 
   1070 #endif
   1071