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