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