Home | History | Annotate | Line # | Download | only in libpuffs
dispatcher.c revision 1.7
      1 /*	$NetBSD: dispatcher.c,v 1.7 2007/07/01 15:30:15 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.7 2007/07/01 15:30:15 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 
    158 			PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTING);
    159 			error = pops->puffs_fs_unmount(pcc,
    160 			    auxt->pvfsr_flags, auxt->pvfsr_pid);
    161 			if (!error)
    162 				PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTED);
    163 			else
    164 				PU_SETSTATE(pu, PUFFS_STATE_RUNNING);
    165 			break;
    166 		}
    167 
    168 		case PUFFS_VFS_STATVFS:
    169 		{
    170 			struct puffs_vfsreq_statvfs *auxt = auxbuf;
    171 
    172 			error = pops->puffs_fs_statvfs(pcc,
    173 			    &auxt->pvfsr_sb, auxt->pvfsr_pid);
    174 			break;
    175 		}
    176 
    177 		case PUFFS_VFS_SYNC:
    178 		{
    179 			struct puffs_vfsreq_sync *auxt = auxbuf;
    180 			PUFFS_MAKECRED(pcr, &auxt->pvfsr_cred);
    181 
    182 			error = pops->puffs_fs_sync(pcc,
    183 			    auxt->pvfsr_waitfor, pcr, auxt->pvfsr_pid);
    184 			break;
    185 		}
    186 
    187 		case PUFFS_VFS_FHTOVP:
    188 		{
    189 			struct puffs_vfsreq_fhtonode *auxt = auxbuf;
    190 
    191 			error = pops->puffs_fs_fhtonode(pcc, auxt->pvfsr_data,
    192 			    auxt->pvfsr_dsize, &auxt->pvfsr_fhcookie,
    193 			    &auxt->pvfsr_vtype, &auxt->pvfsr_size,
    194 			    &auxt->pvfsr_rdev);
    195 
    196 			break;
    197 		}
    198 
    199 		case PUFFS_VFS_VPTOFH:
    200 		{
    201 			struct puffs_vfsreq_nodetofh *auxt = auxbuf;
    202 
    203 			error = pops->puffs_fs_nodetofh(pcc,
    204 			    auxt->pvfsr_fhcookie, auxt->pvfsr_data,
    205 			    &auxt->pvfsr_dsize);
    206 
    207 			break;
    208 		}
    209 
    210 		case PUFFS_VFS_SUSPEND:
    211 		{
    212 			struct puffs_vfsreq_suspend *auxt = auxbuf;
    213 
    214 			error = 0;
    215 			if (pops->puffs_fs_suspend == NULL)
    216 				break;
    217 
    218 			pops->puffs_fs_suspend(pcc, auxt->pvfsr_status);
    219 			break;
    220 		}
    221 
    222 		default:
    223 			/*
    224 			 * I guess the kernel sees this one coming
    225 			 */
    226 			error = EINVAL;
    227 			break;
    228 		}
    229 
    230 	/* XXX: audit return values */
    231 	/* XXX: sync with kernel */
    232 	} else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) {
    233 		switch (preq->preq_optype) {
    234 		case PUFFS_VN_LOOKUP:
    235 		{
    236 			struct puffs_vnreq_lookup *auxt = auxbuf;
    237 			struct puffs_cn pcn;
    238 
    239 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    240 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    241 
    242 			if (buildpath) {
    243 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    244 				if (error)
    245 					break;
    246 			}
    247 
    248 			/* lookup *must* be present */
    249 			error = pops->puffs_node_lookup(pcc, opcookie,
    250 			    &auxt->pvnr_newnode, &auxt->pvnr_vtype,
    251 			    &auxt->pvnr_size, &auxt->pvnr_rdev, &pcn);
    252 
    253 			if (buildpath) {
    254 				if (error) {
    255 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    256 				} else {
    257 					struct puffs_node *pn;
    258 
    259 					/*
    260 					 * did we get a new node or a
    261 					 * recycled node?
    262 					 */
    263 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    264 					if (pn->pn_po.po_path == NULL)
    265 						pn->pn_po = pcn.pcn_po_full;
    266 					else
    267 						pu->pu_pathfree(pu,
    268 						    &pcn.pcn_po_full);
    269 				}
    270 			}
    271 
    272 			break;
    273 		}
    274 
    275 		case PUFFS_VN_CREATE:
    276 		{
    277 			struct puffs_vnreq_create *auxt = auxbuf;
    278 			struct puffs_cn pcn;
    279 			if (pops->puffs_node_create == NULL) {
    280 				error = 0;
    281 				break;
    282 			}
    283 
    284 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    285 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    286 
    287 			if (buildpath) {
    288 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    289 				if (error)
    290 					break;
    291 			}
    292 
    293 			error = pops->puffs_node_create(pcc,
    294 			    opcookie, &auxt->pvnr_newnode,
    295 			    &pcn, &auxt->pvnr_va);
    296 
    297 			if (buildpath) {
    298 				if (error) {
    299 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    300 				} else {
    301 					struct puffs_node *pn;
    302 
    303 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    304 					pn->pn_po = pcn.pcn_po_full;
    305 				}
    306 			}
    307 
    308 			break;
    309 		}
    310 
    311 		case PUFFS_VN_MKNOD:
    312 		{
    313 			struct puffs_vnreq_mknod *auxt = auxbuf;
    314 			struct puffs_cn pcn;
    315 			if (pops->puffs_node_mknod == NULL) {
    316 				error = 0;
    317 				break;
    318 			}
    319 
    320 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    321 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    322 
    323 			if (buildpath) {
    324 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    325 				if (error)
    326 					break;
    327 			}
    328 
    329 			error = pops->puffs_node_mknod(pcc,
    330 			    opcookie, &auxt->pvnr_newnode,
    331 			    &pcn, &auxt->pvnr_va);
    332 
    333 			if (buildpath) {
    334 				if (error) {
    335 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    336 				} else {
    337 					struct puffs_node *pn;
    338 
    339 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    340 					pn->pn_po = pcn.pcn_po_full;
    341 				}
    342 			}
    343 
    344 			break;
    345 		}
    346 
    347 		case PUFFS_VN_OPEN:
    348 		{
    349 			struct puffs_vnreq_open *auxt = auxbuf;
    350 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    351 
    352 			if (pops->puffs_node_open == NULL) {
    353 				error = 0;
    354 				break;
    355 			}
    356 
    357 			error = pops->puffs_node_open(pcc,
    358 			    opcookie, auxt->pvnr_mode, pcr, auxt->pvnr_pid);
    359 			break;
    360 		}
    361 
    362 		case PUFFS_VN_CLOSE:
    363 		{
    364 			struct puffs_vnreq_close *auxt = auxbuf;
    365 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    366 
    367 			if (pops->puffs_node_close == NULL) {
    368 				error = 0;
    369 				break;
    370 			}
    371 
    372 			error = pops->puffs_node_close(pcc,
    373 			    opcookie, auxt->pvnr_fflag, pcr, auxt->pvnr_pid);
    374 			break;
    375 		}
    376 
    377 		case PUFFS_VN_ACCESS:
    378 		{
    379 			struct puffs_vnreq_access *auxt = auxbuf;
    380 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    381 
    382 			if (pops->puffs_node_access == NULL) {
    383 				error = 0;
    384 				break;
    385 			}
    386 
    387 			error = pops->puffs_node_access(pcc,
    388 			    opcookie, auxt->pvnr_mode, pcr, auxt->pvnr_pid);
    389 			break;
    390 		}
    391 
    392 		case PUFFS_VN_GETATTR:
    393 		{
    394 			struct puffs_vnreq_getattr *auxt = auxbuf;
    395 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    396 
    397 			if (pops->puffs_node_getattr == NULL) {
    398 				error = EOPNOTSUPP;
    399 				break;
    400 			}
    401 
    402 			error = pops->puffs_node_getattr(pcc,
    403 			    opcookie, &auxt->pvnr_va, pcr, auxt->pvnr_pid);
    404 			break;
    405 		}
    406 
    407 		case PUFFS_VN_SETATTR:
    408 		{
    409 			struct puffs_vnreq_setattr *auxt = auxbuf;
    410 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    411 
    412 			if (pops->puffs_node_setattr == NULL) {
    413 				error = EOPNOTSUPP;
    414 				break;
    415 			}
    416 
    417 			error = pops->puffs_node_setattr(pcc,
    418 			    opcookie, &auxt->pvnr_va, pcr, auxt->pvnr_pid);
    419 			break;
    420 		}
    421 
    422 		case PUFFS_VN_MMAP:
    423 		{
    424 			struct puffs_vnreq_mmap *auxt = auxbuf;
    425 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    426 
    427 			if (pops->puffs_node_mmap == NULL) {
    428 				error = 0;
    429 				break;
    430 			}
    431 
    432 			error = pops->puffs_node_mmap(pcc,
    433 			    opcookie, auxt->pvnr_fflags,
    434 			    pcr, auxt->pvnr_pid);
    435 			break;
    436 		}
    437 
    438 		case PUFFS_VN_FSYNC:
    439 		{
    440 			struct puffs_vnreq_fsync *auxt = auxbuf;
    441 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    442 
    443 			if (pops->puffs_node_fsync == NULL) {
    444 				error = 0;
    445 				break;
    446 			}
    447 
    448 			error = pops->puffs_node_fsync(pcc, opcookie, pcr,
    449 			    auxt->pvnr_flags, auxt->pvnr_offlo,
    450 			    auxt->pvnr_offhi, auxt->pvnr_pid);
    451 			break;
    452 		}
    453 
    454 		case PUFFS_VN_SEEK:
    455 		{
    456 			struct puffs_vnreq_seek *auxt = auxbuf;
    457 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    458 
    459 			if (pops->puffs_node_seek == NULL) {
    460 				error = 0;
    461 				break;
    462 			}
    463 
    464 			error = pops->puffs_node_seek(pcc,
    465 			    opcookie, auxt->pvnr_oldoff,
    466 			    auxt->pvnr_newoff, pcr);
    467 			break;
    468 		}
    469 
    470 		case PUFFS_VN_REMOVE:
    471 		{
    472 			struct puffs_vnreq_remove *auxt = auxbuf;
    473 			struct puffs_cn pcn;
    474 			if (pops->puffs_node_remove == NULL) {
    475 				error = 0;
    476 				break;
    477 			}
    478 
    479 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    480 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    481 
    482 			error = pops->puffs_node_remove(pcc,
    483 			    opcookie, auxt->pvnr_cookie_targ, &pcn);
    484 			break;
    485 		}
    486 
    487 		case PUFFS_VN_LINK:
    488 		{
    489 			struct puffs_vnreq_link *auxt = auxbuf;
    490 			struct puffs_cn pcn;
    491 			if (pops->puffs_node_link == NULL) {
    492 				error = 0;
    493 				break;
    494 			}
    495 
    496 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    497 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    498 
    499 			if (buildpath) {
    500 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    501 				if (error)
    502 					break;
    503 			}
    504 
    505 			error = pops->puffs_node_link(pcc,
    506 			    opcookie, auxt->pvnr_cookie_targ, &pcn);
    507 			if (buildpath)
    508 				pu->pu_pathfree(pu, &pcn.pcn_po_full);
    509 
    510 			break;
    511 		}
    512 
    513 		case PUFFS_VN_RENAME:
    514 		{
    515 			struct puffs_vnreq_rename *auxt = auxbuf;
    516 			struct puffs_cn pcn_src, pcn_targ;
    517 			struct puffs_node *pn_src;
    518 
    519 			if (pops->puffs_node_rename == NULL) {
    520 				error = 0;
    521 				break;
    522 			}
    523 
    524 			pcn_src.pcn_pkcnp = &auxt->pvnr_cn_src;
    525 			PUFFS_KCREDTOCRED(pcn_src.pcn_cred,
    526 			    &auxt->pvnr_cn_src_cred);
    527 			pcn_targ.pcn_pkcnp = &auxt->pvnr_cn_targ;
    528 			PUFFS_KCREDTOCRED(pcn_targ.pcn_cred,
    529 			    &auxt->pvnr_cn_targ_cred);
    530 
    531 			if (buildpath) {
    532 				pn_src = auxt->pvnr_cookie_src;
    533 				pcn_src.pcn_po_full = pn_src->pn_po;
    534 
    535 				error = puffs_path_pcnbuild(pu, &pcn_targ,
    536 				    auxt->pvnr_cookie_targdir);
    537 				if (error)
    538 					break;
    539 			}
    540 
    541 			error = pops->puffs_node_rename(pcc,
    542 			    opcookie, auxt->pvnr_cookie_src,
    543 			    &pcn_src, auxt->pvnr_cookie_targdir,
    544 			    auxt->pvnr_cookie_targ, &pcn_targ);
    545 
    546 			if (buildpath) {
    547 				if (error) {
    548 					pu->pu_pathfree(pu,
    549 					    &pcn_targ.pcn_po_full);
    550 				} else {
    551 					struct puffs_pathinfo pi;
    552 					struct puffs_pathobj po_old;
    553 
    554 					/* handle this node */
    555 					po_old = pn_src->pn_po;
    556 					pn_src->pn_po = pcn_targ.pcn_po_full;
    557 
    558 					if (pn_src->pn_va.va_type != VDIR) {
    559 						pu->pu_pathfree(pu, &po_old);
    560 						break;
    561 					}
    562 
    563 					/* handle all child nodes for DIRs */
    564 					pi.pi_old = &pcn_src.pcn_po_full;
    565 					pi.pi_new = &pcn_targ.pcn_po_full;
    566 
    567 					if (puffs_pn_nodewalk(pu,
    568 					    puffs_path_prefixadj, &pi) != NULL)
    569 						error = ENOMEM;
    570 					pu->pu_pathfree(pu, &po_old);
    571 				}
    572 			}
    573 			break;
    574 		}
    575 
    576 		case PUFFS_VN_MKDIR:
    577 		{
    578 			struct puffs_vnreq_mkdir *auxt = auxbuf;
    579 			struct puffs_cn pcn;
    580 			if (pops->puffs_node_mkdir == NULL) {
    581 				error = 0;
    582 				break;
    583 			}
    584 
    585 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    586 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    587 
    588 			if (buildpath) {
    589 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    590 				if (error)
    591 					break;
    592 			}
    593 
    594 			error = pops->puffs_node_mkdir(pcc,
    595 			    opcookie, &auxt->pvnr_newnode,
    596 			    &pcn, &auxt->pvnr_va);
    597 
    598 			if (buildpath) {
    599 				if (error) {
    600 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    601 				} else {
    602 					struct puffs_node *pn;
    603 
    604 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    605 					pn->pn_po = pcn.pcn_po_full;
    606 				}
    607 			}
    608 
    609 			break;
    610 		}
    611 
    612 		case PUFFS_VN_RMDIR:
    613 		{
    614 			struct puffs_vnreq_rmdir *auxt = auxbuf;
    615 			struct puffs_cn pcn;
    616 			if (pops->puffs_node_rmdir == NULL) {
    617 				error = 0;
    618 				break;
    619 			}
    620 
    621 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    622 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    623 
    624 			error = pops->puffs_node_rmdir(pcc,
    625 			    opcookie, auxt->pvnr_cookie_targ, &pcn);
    626 			break;
    627 		}
    628 
    629 		case PUFFS_VN_SYMLINK:
    630 		{
    631 			struct puffs_vnreq_symlink *auxt = auxbuf;
    632 			struct puffs_cn pcn;
    633 			if (pops->puffs_node_symlink == NULL) {
    634 				error = 0;
    635 				break;
    636 			}
    637 
    638 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    639 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    640 
    641 			if (buildpath) {
    642 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    643 				if (error)
    644 					break;
    645 			}
    646 
    647 			error = pops->puffs_node_symlink(pcc,
    648 			    opcookie, &auxt->pvnr_newnode,
    649 			    &pcn, &auxt->pvnr_va, auxt->pvnr_link);
    650 
    651 			if (buildpath) {
    652 				if (error) {
    653 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    654 				} else {
    655 					struct puffs_node *pn;
    656 
    657 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    658 					pn->pn_po = pcn.pcn_po_full;
    659 				}
    660 			}
    661 
    662 			break;
    663 		}
    664 
    665 		case PUFFS_VN_READDIR:
    666 		{
    667 			struct puffs_vnreq_readdir *auxt = auxbuf;
    668 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    669 			struct dirent *dent;
    670 			off_t *cookies;
    671 			size_t res, origcookies;
    672 
    673 			if (pops->puffs_node_readdir == NULL) {
    674 				error = 0;
    675 				break;
    676 			}
    677 
    678 			if (auxt->pvnr_ncookies) {
    679 				/* LINTED: pvnr_data is __aligned() */
    680 				cookies = (off_t *)auxt->pvnr_data;
    681 				origcookies = auxt->pvnr_ncookies;
    682 			} else {
    683 				cookies = NULL;
    684 				origcookies = 0;
    685 			}
    686 			/* LINTED: dentoff is aligned in the kernel */
    687 			dent = (struct dirent *)
    688 			    (auxt->pvnr_data + auxt->pvnr_dentoff);
    689 
    690 			res = auxt->pvnr_resid;
    691 			error = pops->puffs_node_readdir(pcc,
    692 			    opcookie, dent, &auxt->pvnr_offset,
    693 			    &auxt->pvnr_resid, pcr, &auxt->pvnr_eofflag,
    694 			    cookies, &auxt->pvnr_ncookies);
    695 
    696 			/* much easier to track non-working NFS */
    697 			assert(auxt->pvnr_ncookies <= origcookies);
    698 
    699 			/* need to move a bit more */
    700 			preq->preq_buflen = sizeof(struct puffs_vnreq_readdir)
    701 			    + auxt->pvnr_dentoff + (res - auxt->pvnr_resid);
    702 			break;
    703 		}
    704 
    705 		case PUFFS_VN_READLINK:
    706 		{
    707 			struct puffs_vnreq_readlink *auxt = auxbuf;
    708 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    709 
    710 			if (pops->puffs_node_readlink == NULL) {
    711 				error = EOPNOTSUPP;
    712 				break;
    713 			}
    714 
    715 			/*LINTED*/
    716 			error = pops->puffs_node_readlink(pcc, opcookie, pcr,
    717 			    auxt->pvnr_link, &auxt->pvnr_linklen);
    718 			break;
    719 		}
    720 
    721 		case PUFFS_VN_RECLAIM:
    722 		{
    723 			struct puffs_vnreq_reclaim *auxt = auxbuf;
    724 			if (pops->puffs_node_reclaim == NULL) {
    725 				error = 0;
    726 				break;
    727 			}
    728 
    729 			error = pops->puffs_node_reclaim(pcc,
    730 			    opcookie, auxt->pvnr_pid);
    731 			break;
    732 		}
    733 
    734 		case PUFFS_VN_INACTIVE:
    735 		{
    736 			struct puffs_vnreq_inactive *auxt = auxbuf;
    737 			if (pops->puffs_node_inactive == NULL) {
    738 				error = EOPNOTSUPP;
    739 				break;
    740 			}
    741 
    742 			auxt->pvnr_backendrefs = 1; /* safe default */
    743 			error = pops->puffs_node_inactive(pcc,
    744 			    opcookie, auxt->pvnr_pid,
    745 			    &auxt->pvnr_backendrefs);
    746 			break;
    747 		}
    748 
    749 		case PUFFS_VN_PATHCONF:
    750 		{
    751 			struct puffs_vnreq_pathconf *auxt = auxbuf;
    752 			if (pops->puffs_node_pathconf == NULL) {
    753 				error = 0;
    754 				break;
    755 			}
    756 
    757 			error = pops->puffs_node_pathconf(pcc,
    758 			    opcookie, auxt->pvnr_name,
    759 			    &auxt->pvnr_retval);
    760 			break;
    761 		}
    762 
    763 		case PUFFS_VN_ADVLOCK:
    764 		{
    765 			struct puffs_vnreq_advlock *auxt = auxbuf;
    766 			if (pops->puffs_node_advlock == NULL) {
    767 				error = 0;
    768 				break;
    769 			}
    770 
    771 			error = pops->puffs_node_advlock(pcc,
    772 			    opcookie, auxt->pvnr_id, auxt->pvnr_op,
    773 			    &auxt->pvnr_fl, auxt->pvnr_flags);
    774 			break;
    775 		}
    776 
    777 		case PUFFS_VN_PRINT:
    778 		{
    779 			if (pops->puffs_node_print == NULL) {
    780 				error = 0;
    781 				break;
    782 			}
    783 
    784 			error = pops->puffs_node_print(pcc,
    785 			    opcookie);
    786 			break;
    787 		}
    788 
    789 		case PUFFS_VN_READ:
    790 		{
    791 			struct puffs_vnreq_read *auxt = auxbuf;
    792 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    793 			size_t res;
    794 
    795 			if (pops->puffs_node_read == NULL) {
    796 				error = EIO;
    797 				break;
    798 			}
    799 
    800 			res = auxt->pvnr_resid;
    801 			error = pops->puffs_node_read(pcc,
    802 			    opcookie, auxt->pvnr_data,
    803 			    auxt->pvnr_offset, &auxt->pvnr_resid,
    804 			    pcr, auxt->pvnr_ioflag);
    805 
    806 			/* need to move a bit more */
    807 			preq->preq_buflen = sizeof(struct puffs_vnreq_read)
    808 			    + (res - auxt->pvnr_resid);
    809 			break;
    810 		}
    811 
    812 		case PUFFS_VN_WRITE:
    813 		{
    814 			struct puffs_vnreq_write *auxt = auxbuf;
    815 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    816 
    817 			if (pops->puffs_node_write == NULL) {
    818 				error = EIO;
    819 				break;
    820 			}
    821 
    822 			error = pops->puffs_node_write(pcc,
    823 			    opcookie, auxt->pvnr_data,
    824 			    auxt->pvnr_offset, &auxt->pvnr_resid,
    825 			    pcr, auxt->pvnr_ioflag);
    826 
    827 			/* don't need to move data back to the kernel */
    828 			preq->preq_buflen = sizeof(struct puffs_vnreq_write);
    829 			break;
    830 		}
    831 
    832 		case PUFFS_VN_POLL:
    833 		{
    834 			struct puffs_vnreq_poll *auxt = auxbuf;
    835 			if (pops->puffs_node_poll == NULL) {
    836 				error = 0;
    837 
    838 				/* emulate genfs_poll() */
    839 				auxt->pvnr_events &= (POLLIN | POLLOUT
    840 						    | POLLRDNORM | POLLWRNORM);
    841 
    842 				break;
    843 			}
    844 
    845 			error = pops->puffs_node_poll(pcc,
    846 			    opcookie, &auxt->pvnr_events, auxt->pvnr_pid);
    847 			break;
    848 		}
    849 
    850 /* holy bitrot, ryydman! */
    851 #if 0
    852 		case PUFFS_VN_IOCTL:
    853 			error = pops->puffs_node_ioctl1(pcc, opcookie,
    854 			     (struct puffs_vnreq_ioctl *)auxbuf, &pop);
    855 			if (error != 0)
    856 				break;
    857 			pop.pso_reqid = preq->preq_id;
    858 
    859 			/* let the kernel do it's intermediate duty */
    860 			error = ioctl(pu->pu_kargs.pa_fd, PUFFSSIZEOP, &pop);
    861 			/*
    862 			 * XXX: I don't actually know what the correct
    863 			 * thing to do in case of an error is, so I'll
    864 			 * just ignore it for the time being.
    865 			 */
    866 			error = pops->puffs_node_ioctl2(pcc, opcookie,
    867 			    (struct puffs_vnreq_ioctl *)auxbuf, &pop);
    868 			break;
    869 
    870 		case PUFFS_VN_FCNTL:
    871 			error = pops->puffs_node_fcntl1(pcc, opcookie,
    872 			     (struct puffs_vnreq_fcntl *)auxbuf, &pop);
    873 			if (error != 0)
    874 				break;
    875 			pop.pso_reqid = preq->preq_id;
    876 
    877 			/* let the kernel do it's intermediate duty */
    878 			error = ioctl(pu->pu_kargs.pa_fd, PUFFSSIZEOP, &pop);
    879 			/*
    880 			 * XXX: I don't actually know what the correct
    881 			 * thing to do in case of an error is, so I'll
    882 			 * just ignore it for the time being.
    883 			 */
    884 			error = pops->puffs_node_fcntl2(pcc, opcookie,
    885 			    (struct puffs_vnreq_fcntl *)auxbuf, &pop);
    886 			break;
    887 #endif
    888 
    889 		default:
    890 			printf("inval op %d\n", preq->preq_optype);
    891 			error = EINVAL;
    892 			break;
    893 		}
    894 	} else {
    895 		/*
    896 		 * this one also
    897 		 */
    898 		error = EINVAL;
    899 	}
    900 
    901 	preq->preq_rv = error;
    902 	pcc->pcc_flags |= PCC_DONE;
    903 
    904 	/*
    905 	 * Note, we are calling this from here so that we can run it
    906 	 * off of the continuation stack.  Otherwise puffs_goto() would
    907 	 * not work.
    908 	 */
    909 	processresult(pcc, pcc->pcc_ppr, rv);
    910 }
    911 
    912 static void
    913 processresult(struct puffs_cc *pcc, struct puffs_putreq *ppr, int how)
    914 {
    915 	struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
    916 
    917 	/* check if we need to store this reply */
    918 	switch (how) {
    919 	case PUFFCALL_ANSWER:
    920 		if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
    921 			puffsdump_rv(pcc->pcc_preq);
    922 
    923 		if (pcc->pcc_flags & PCC_REALCC)
    924 			puffs_req_putcc(ppr, pcc);
    925 		else
    926 			puffs_req_put(ppr, pcc->pcc_preq);
    927 		break;
    928 	case PUFFCALL_IGNORE:
    929 		if (pcc->pcc_flags & PCC_REALCC)
    930 			LIST_INSERT_HEAD(&pu->pu_ccnukelst, pcc, nlst_entries);
    931 		break;
    932 	case PUFFCALL_AGAIN:
    933 		if (pcc->pcc_flags & PCC_FAKECC)
    934 			assert(pcc->pcc_flags & PCC_DONE);
    935 		break;
    936 	default:
    937 		assert(/*CONSTCOND*/0);
    938 	}
    939 
    940 	/* who needs information when you're living on borrowed time? */
    941 	if (pcc->pcc_flags & PCC_BORROWED)
    942 		puffs_cc_yield(pcc); /* back to borrow source */
    943 }
    944 
    945 
    946 #if 0
    947 		case PUFFS_VN_KQFILTER:
    948 		{
    949 			struct puffs_vnreq_kqfilter *auxt = auxbuf;
    950 			if (pops->puffs_node_kqfilter == NULL) {
    951 				error = 0;
    952 				break;
    953 			}
    954 
    955 			error = pops->puffs_node_kqfilter(pcc,
    956 			    opcookie, );
    957 			break;
    958 		}
    959 
    960 		case PUFFS_VN_CLOSEEXTATTR:
    961 		{
    962 			struct puffs_vnreq_closeextattr *auxt = auxbuf;
    963 			if (pops->puffs_closeextattr == NULL) {
    964 				error = 0;
    965 				break;
    966 			}
    967 
    968 			error = pops->puffs_closeextattr(pcc,
    969 			    opcookie, );
    970 			break;
    971 		}
    972 
    973 		case PUFFS_VN_GETEXTATTR:
    974 		{
    975 			struct puffs_vnreq_getextattr *auxt = auxbuf;
    976 			if (pops->puffs_getextattr == NULL) {
    977 				error = 0;
    978 				break;
    979 			}
    980 
    981 			error = pops->puffs_getextattr(pcc,
    982 			    opcookie, );
    983 			break;
    984 		}
    985 
    986 		case PUFFS_VN_LISTEXTATTR:
    987 		{
    988 			struct puffs_vnreq_listextattr *auxt = auxbuf;
    989 			if (pops->puffs_listextattr == NULL) {
    990 				error = 0;
    991 				break;
    992 			}
    993 
    994 			error = pops->puffs_listextattr(pcc,
    995 			    opcookie, );
    996 			break;
    997 		}
    998 
    999 		case PUFFS_VN_OPENEXTATTR:
   1000 		{
   1001 			struct puffs_vnreq_openextattr *auxt = auxbuf;
   1002 			if (pops->puffs_openextattr == NULL) {
   1003 				error = 0;
   1004 				break;
   1005 			}
   1006 
   1007 			error = pops->puffs_openextattr(pcc,
   1008 			    opcookie, );
   1009 			break;
   1010 		}
   1011 
   1012 		case PUFFS_VN_DELETEEXTATTR:
   1013 		{
   1014 			struct puffs_vnreq_deleteextattr *auxt = auxbuf;
   1015 			if (pops->puffs_deleteextattr == NULL) {
   1016 				error = 0;
   1017 				break;
   1018 			}
   1019 
   1020 			error = pops->puffs_deleteextattr(pcc,
   1021 			    opcookie, );
   1022 			break;
   1023 		}
   1024 
   1025 		case PUFFS_VN_SETEXTATTR:
   1026 		{
   1027 			struct puffs_vnreq_setextattr *auxt = auxbuf;
   1028 			if (pops->puffs_setextattr == NULL) {
   1029 				error = 0;
   1030 				break;
   1031 			}
   1032 
   1033 			error = pops->puffs_setextattr(pcc,
   1034 			    opcookie, );
   1035 			break;
   1036 		}
   1037 
   1038 #endif
   1039