Home | History | Annotate | Line # | Download | only in libpuffs
dispatcher.c revision 1.34
      1 /*	$NetBSD: dispatcher.c,v 1.34 2010/05/21 10:50:52 pooka Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2006, 2007, 2008 Antti Kantee.  All Rights Reserved.
      5  *
      6  * Development of this software was supported by the
      7  * Ulla Tuominen Foundation, the Finnish Cultural Foundation and
      8  * Research Foundation of Helsinki University of Technology.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     20  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     22  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 #if !defined(lint)
     34 __RCSID("$NetBSD: dispatcher.c,v 1.34 2010/05/21 10:50:52 pooka Exp $");
     35 #endif /* !lint */
     36 
     37 #include <sys/types.h>
     38 #include <sys/poll.h>
     39 
     40 #include <assert.h>
     41 #include <errno.h>
     42 #ifdef PUFFS_WITH_THREADS
     43 #include <pthread.h>
     44 #endif
     45 #include <puffs.h>
     46 #include <puffsdump.h>
     47 #include <stdio.h>
     48 #include <stdlib.h>
     49 #include <unistd.h>
     50 
     51 #include "puffs_priv.h"
     52 
     53 #if 0 /* me not worka now */
     54 /*
     55  * Set the following to 1 to handle each request in a separate pthread.
     56  * This is not exported as it should not be used yet unless having a
     57  * very good knowledge of what you're signing up for (libpuffs is not
     58  * threadsafe).
     59  */
     60 int puffs_usethreads;
     61 #endif
     62 
     63 static void dispatch(struct puffs_cc *);
     64 
     65 /* for our eyes only */
     66 void
     67 puffs__ml_dispatch(struct puffs_usermount *pu, struct puffs_framebuf *pb)
     68 {
     69 	struct puffs_cc *pcc = puffs_cc_getcc(pu);
     70 	struct puffs_req *preq;
     71 
     72 	pcc->pcc_pb = pb;
     73 	pcc->pcc_flags |= PCC_MLCONT;
     74 	dispatch(pcc);
     75 
     76 	/* Put result to kernel sendqueue if necessary */
     77 	preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
     78 	if (PUFFSOP_WANTREPLY(preq->preq_opclass)) {
     79 		if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
     80 			puffsdump_rv(preq);
     81 
     82 		puffs_framev_enqueue_justsend(pu, pu->pu_fd,
     83 		    pcc->pcc_pb, 0, 0);
     84 	} else {
     85 		puffs_framebuf_destroy(pcc->pcc_pb);
     86 	}
     87 
     88 	/* who needs information when you're living on borrowed time? */
     89 	if (pcc->pcc_flags & PCC_BORROWED) {
     90 		puffs_cc_yield(pcc); /* back to borrow source */
     91 	}
     92 	pcc->pcc_flags = 0;
     93 }
     94 
     95 /* public, but not really tested and only semi-supported */
     96 int
     97 puffs_dispatch_create(struct puffs_usermount *pu, struct puffs_framebuf *pb,
     98 	struct puffs_cc **pccp)
     99 {
    100 	struct puffs_cc *pcc;
    101 
    102 	if (puffs__cc_create(pu, dispatch, &pcc) == -1)
    103 		return -1;
    104 
    105 	pcc->pcc_pb = pb;
    106 	*pccp = pcc;
    107 
    108 	return 0;
    109 }
    110 
    111 int
    112 puffs_dispatch_exec(struct puffs_cc *pcc, struct puffs_framebuf **pbp)
    113 {
    114 	int rv;
    115 
    116 	puffs_cc_continue(pcc);
    117 
    118 	if (pcc->pcc_flags & PCC_DONE) {
    119 		rv = 1;
    120 		*pbp = pcc->pcc_pb;
    121 		pcc->pcc_flags = 0;
    122 		puffs__cc_destroy(pcc, 0);
    123 	} else {
    124 		rv = 0;
    125 	}
    126 
    127 	return rv;
    128 }
    129 
    130 static void
    131 dispatch(struct puffs_cc *pcc)
    132 {
    133 	struct puffs_usermount *pu = pcc->pcc_pu;
    134 	struct puffs_ops *pops = &pu->pu_ops;
    135 	struct puffs_req *preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
    136 	void *auxbuf; /* help with typecasting */
    137 	puffs_cookie_t opcookie;
    138 	int error = 0, buildpath;
    139 
    140 	/* XXX: smaller hammer, please */
    141 	if ((PUFFSOP_OPCLASS(preq->preq_opclass == PUFFSOP_VFS &&
    142 	    preq->preq_optype == PUFFS_VFS_VPTOFH)) ||
    143 	    (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN &&
    144 	    (preq->preq_optype == PUFFS_VN_READDIR
    145 	    || preq->preq_optype == PUFFS_VN_READ))) {
    146 		if (puffs_framebuf_reserve_space(pcc->pcc_pb,
    147 		    PUFFS_MSG_MAXSIZE) == -1)
    148 			error = errno;
    149 		preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
    150 	}
    151 
    152 	auxbuf = preq;
    153 	opcookie = preq->preq_cookie;
    154 
    155 	assert((pcc->pcc_flags & PCC_DONE) == 0);
    156 
    157 	buildpath = pu->pu_flags & PUFFS_FLAG_BUILDPATH;
    158 	preq->preq_setbacks = 0;
    159 
    160 	if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
    161 		puffsdump_req(preq);
    162 
    163 	puffs__cc_setcaller(pcc, preq->preq_pid, preq->preq_lid);
    164 
    165 	/* pre-operation */
    166 	if (pu->pu_oppre)
    167 		pu->pu_oppre(pu);
    168 
    169 	if (error)
    170 		goto out;
    171 
    172 	/* Execute actual operation */
    173 	if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) {
    174 		switch (preq->preq_optype) {
    175 		case PUFFS_VFS_UNMOUNT:
    176 		{
    177 			struct puffs_vfsmsg_unmount *auxt = auxbuf;
    178 
    179 			PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTING);
    180 			error = pops->puffs_fs_unmount(pu, auxt->pvfsr_flags);
    181 			if (!error)
    182 				PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTED);
    183 			else
    184 				PU_SETSTATE(pu, PUFFS_STATE_RUNNING);
    185 			break;
    186 		}
    187 
    188 		case PUFFS_VFS_STATVFS:
    189 		{
    190 			struct puffs_vfsmsg_statvfs *auxt = auxbuf;
    191 
    192 			error = pops->puffs_fs_statvfs(pu, &auxt->pvfsr_sb);
    193 			break;
    194 		}
    195 
    196 		case PUFFS_VFS_SYNC:
    197 		{
    198 			struct puffs_vfsmsg_sync *auxt = auxbuf;
    199 			PUFFS_MAKECRED(pcr, &auxt->pvfsr_cred);
    200 
    201 			error = pops->puffs_fs_sync(pu,
    202 			    auxt->pvfsr_waitfor, pcr);
    203 			break;
    204 		}
    205 
    206 		case PUFFS_VFS_FHTOVP:
    207 		{
    208 			struct puffs_vfsmsg_fhtonode *auxt = auxbuf;
    209 			struct puffs_newinfo pni;
    210 
    211 			pni.pni_cookie = &auxt->pvfsr_fhcookie;
    212 			pni.pni_vtype = &auxt->pvfsr_vtype;
    213 			pni.pni_size = &auxt->pvfsr_size;
    214 			pni.pni_rdev = &auxt->pvfsr_rdev;
    215 
    216 			error = pops->puffs_fs_fhtonode(pu, auxt->pvfsr_data,
    217 			    auxt->pvfsr_dsize, &pni);
    218 
    219 			break;
    220 		}
    221 
    222 		case PUFFS_VFS_VPTOFH:
    223 		{
    224 			struct puffs_vfsmsg_nodetofh *auxt = auxbuf;
    225 
    226 			error = pops->puffs_fs_nodetofh(pu,
    227 			    auxt->pvfsr_fhcookie, auxt->pvfsr_data,
    228 			    &auxt->pvfsr_dsize);
    229 
    230 			break;
    231 		}
    232 
    233 		case PUFFS_VFS_EXTATTRCTL:
    234 		{
    235 			struct puffs_vfsmsg_extattrctl *auxt = auxbuf;
    236 			const char *attrname;
    237 			int flags;
    238 
    239 			if (pops->puffs_fs_extattrctl == NULL) {
    240 				error = EOPNOTSUPP;
    241 				break;
    242 			}
    243 
    244 			if (auxt->pvfsr_flags & PUFFS_EXTATTRCTL_HASATTRNAME)
    245 				attrname = auxt->pvfsr_attrname;
    246 			else
    247 				attrname = NULL;
    248 
    249 			flags = auxt->pvfsr_flags & PUFFS_EXTATTRCTL_HASNODE;
    250 			error = pops->puffs_fs_extattrctl(pu, auxt->pvfsr_cmd,
    251 			    opcookie, flags,
    252 			    auxt->pvfsr_attrnamespace, attrname);
    253 			break;
    254 		}
    255 
    256 		default:
    257 			/*
    258 			 * I guess the kernel sees this one coming
    259 			 */
    260 			error = EINVAL;
    261 			break;
    262 		}
    263 
    264 	/* XXX: audit return values */
    265 	/* XXX: sync with kernel */
    266 	} else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) {
    267 		switch (preq->preq_optype) {
    268 		case PUFFS_VN_LOOKUP:
    269 		{
    270 			struct puffs_vnmsg_lookup *auxt = auxbuf;
    271 			struct puffs_newinfo pni;
    272 			struct puffs_cn pcn;
    273 
    274 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    275 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    276 			pni.pni_cookie = &auxt->pvnr_newnode;
    277 			pni.pni_vtype = &auxt->pvnr_vtype;
    278 			pni.pni_size = &auxt->pvnr_size;
    279 			pni.pni_rdev = &auxt->pvnr_rdev;
    280 
    281 			if (buildpath) {
    282 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    283 				if (error)
    284 					break;
    285 			}
    286 
    287 			/* lookup *must* be present */
    288 			error = pops->puffs_node_lookup(pu, opcookie,
    289 			    &pni, &pcn);
    290 
    291 			if (buildpath) {
    292 				if (error) {
    293 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    294 				} else {
    295 					struct puffs_node *pn;
    296 
    297 					/*
    298 					 * did we get a new node or a
    299 					 * recycled node?
    300 					 */
    301 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    302 					if (pn->pn_po.po_path == NULL)
    303 						pn->pn_po = pcn.pcn_po_full;
    304 					else
    305 						pu->pu_pathfree(pu,
    306 						    &pcn.pcn_po_full);
    307 				}
    308 			}
    309 
    310 			break;
    311 		}
    312 
    313 		case PUFFS_VN_CREATE:
    314 		{
    315 			struct puffs_vnmsg_create *auxt = auxbuf;
    316 			struct puffs_newinfo pni;
    317 			struct puffs_cn pcn;
    318 
    319 			if (pops->puffs_node_create == NULL) {
    320 				error = 0;
    321 				break;
    322 			}
    323 
    324 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    325 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    326 
    327 			memset(&pni, 0, sizeof(pni));
    328 			pni.pni_cookie = &auxt->pvnr_newnode;
    329 
    330 			if (buildpath) {
    331 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    332 				if (error)
    333 					break;
    334 			}
    335 
    336 			error = pops->puffs_node_create(pu,
    337 			    opcookie, &pni, &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_MKNOD:
    354 		{
    355 			struct puffs_vnmsg_mknod *auxt = auxbuf;
    356 			struct puffs_newinfo pni;
    357 			struct puffs_cn pcn;
    358 
    359 			if (pops->puffs_node_mknod == NULL) {
    360 				error = 0;
    361 				break;
    362 			}
    363 
    364 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    365 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    366 
    367 			memset(&pni, 0, sizeof(pni));
    368 			pni.pni_cookie = &auxt->pvnr_newnode;
    369 
    370 			if (buildpath) {
    371 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    372 				if (error)
    373 					break;
    374 			}
    375 
    376 			error = pops->puffs_node_mknod(pu,
    377 			    opcookie, &pni, &pcn, &auxt->pvnr_va);
    378 
    379 			if (buildpath) {
    380 				if (error) {
    381 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    382 				} else {
    383 					struct puffs_node *pn;
    384 
    385 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    386 					pn->pn_po = pcn.pcn_po_full;
    387 				}
    388 			}
    389 
    390 			break;
    391 		}
    392 
    393 		case PUFFS_VN_OPEN:
    394 		{
    395 			struct puffs_vnmsg_open *auxt = auxbuf;
    396 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    397 
    398 			if (pops->puffs_node_open == NULL) {
    399 				error = 0;
    400 				break;
    401 			}
    402 
    403 			error = pops->puffs_node_open(pu,
    404 			    opcookie, auxt->pvnr_mode, pcr);
    405 			break;
    406 		}
    407 
    408 		case PUFFS_VN_CLOSE:
    409 		{
    410 			struct puffs_vnmsg_close *auxt = auxbuf;
    411 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    412 
    413 			if (pops->puffs_node_close == NULL) {
    414 				error = 0;
    415 				break;
    416 			}
    417 
    418 			error = pops->puffs_node_close(pu,
    419 			    opcookie, auxt->pvnr_fflag, pcr);
    420 			break;
    421 		}
    422 
    423 		case PUFFS_VN_ACCESS:
    424 		{
    425 			struct puffs_vnmsg_access *auxt = auxbuf;
    426 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    427 
    428 			if (pops->puffs_node_access == NULL) {
    429 				error = 0;
    430 				break;
    431 			}
    432 
    433 			error = pops->puffs_node_access(pu,
    434 			    opcookie, auxt->pvnr_mode, pcr);
    435 			break;
    436 		}
    437 
    438 		case PUFFS_VN_GETATTR:
    439 		{
    440 			struct puffs_vnmsg_getattr *auxt = auxbuf;
    441 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    442 
    443 			if (pops->puffs_node_getattr == NULL) {
    444 				error = EOPNOTSUPP;
    445 				break;
    446 			}
    447 
    448 			error = pops->puffs_node_getattr(pu,
    449 			    opcookie, &auxt->pvnr_va, pcr);
    450 			break;
    451 		}
    452 
    453 		case PUFFS_VN_SETATTR:
    454 		{
    455 			struct puffs_vnmsg_setattr *auxt = auxbuf;
    456 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    457 
    458 			if (pops->puffs_node_setattr == NULL) {
    459 				error = EOPNOTSUPP;
    460 				break;
    461 			}
    462 
    463 			error = pops->puffs_node_setattr(pu,
    464 			    opcookie, &auxt->pvnr_va, pcr);
    465 			break;
    466 		}
    467 
    468 		case PUFFS_VN_MMAP:
    469 		{
    470 			struct puffs_vnmsg_mmap *auxt = auxbuf;
    471 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    472 
    473 			if (pops->puffs_node_mmap == NULL) {
    474 				error = 0;
    475 				break;
    476 			}
    477 
    478 			error = pops->puffs_node_mmap(pu,
    479 			    opcookie, auxt->pvnr_prot, pcr);
    480 			break;
    481 		}
    482 
    483 		case PUFFS_VN_FSYNC:
    484 		{
    485 			struct puffs_vnmsg_fsync *auxt = auxbuf;
    486 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    487 
    488 			if (pops->puffs_node_fsync == NULL) {
    489 				error = 0;
    490 				break;
    491 			}
    492 
    493 			error = pops->puffs_node_fsync(pu, opcookie, pcr,
    494 			    auxt->pvnr_flags, auxt->pvnr_offlo,
    495 			    auxt->pvnr_offhi);
    496 			break;
    497 		}
    498 
    499 		case PUFFS_VN_SEEK:
    500 		{
    501 			struct puffs_vnmsg_seek *auxt = auxbuf;
    502 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    503 
    504 			if (pops->puffs_node_seek == NULL) {
    505 				error = 0;
    506 				break;
    507 			}
    508 
    509 			error = pops->puffs_node_seek(pu,
    510 			    opcookie, auxt->pvnr_oldoff,
    511 			    auxt->pvnr_newoff, pcr);
    512 			break;
    513 		}
    514 
    515 		case PUFFS_VN_REMOVE:
    516 		{
    517 			struct puffs_vnmsg_remove *auxt = auxbuf;
    518 			struct puffs_cn pcn;
    519 			if (pops->puffs_node_remove == NULL) {
    520 				error = 0;
    521 				break;
    522 			}
    523 
    524 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    525 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    526 
    527 			error = pops->puffs_node_remove(pu,
    528 			    opcookie, auxt->pvnr_cookie_targ, &pcn);
    529 			break;
    530 		}
    531 
    532 		case PUFFS_VN_LINK:
    533 		{
    534 			struct puffs_vnmsg_link *auxt = auxbuf;
    535 			struct puffs_cn pcn;
    536 			if (pops->puffs_node_link == NULL) {
    537 				error = 0;
    538 				break;
    539 			}
    540 
    541 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    542 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    543 
    544 			if (buildpath) {
    545 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    546 				if (error)
    547 					break;
    548 			}
    549 
    550 			error = pops->puffs_node_link(pu,
    551 			    opcookie, auxt->pvnr_cookie_targ, &pcn);
    552 			if (buildpath)
    553 				pu->pu_pathfree(pu, &pcn.pcn_po_full);
    554 
    555 			break;
    556 		}
    557 
    558 		case PUFFS_VN_RENAME:
    559 		{
    560 			struct puffs_vnmsg_rename *auxt = auxbuf;
    561 			struct puffs_cn pcn_src, pcn_targ;
    562 			struct puffs_node *pn_src;
    563 
    564 			if (pops->puffs_node_rename == NULL) {
    565 				error = 0;
    566 				break;
    567 			}
    568 
    569 			pcn_src.pcn_pkcnp = &auxt->pvnr_cn_src;
    570 			PUFFS_KCREDTOCRED(pcn_src.pcn_cred,
    571 			    &auxt->pvnr_cn_src_cred);
    572 
    573 			pcn_targ.pcn_pkcnp = &auxt->pvnr_cn_targ;
    574 			PUFFS_KCREDTOCRED(pcn_targ.pcn_cred,
    575 			    &auxt->pvnr_cn_targ_cred);
    576 
    577 			if (buildpath) {
    578 				pn_src = auxt->pvnr_cookie_src;
    579 				pcn_src.pcn_po_full = pn_src->pn_po;
    580 
    581 				error = puffs_path_pcnbuild(pu, &pcn_targ,
    582 				    auxt->pvnr_cookie_targdir);
    583 				if (error)
    584 					break;
    585 			}
    586 
    587 			error = pops->puffs_node_rename(pu,
    588 			    opcookie, auxt->pvnr_cookie_src,
    589 			    &pcn_src, auxt->pvnr_cookie_targdir,
    590 			    auxt->pvnr_cookie_targ, &pcn_targ);
    591 
    592 			if (buildpath) {
    593 				if (error) {
    594 					pu->pu_pathfree(pu,
    595 					    &pcn_targ.pcn_po_full);
    596 				} else {
    597 					struct puffs_pathinfo pi;
    598 					struct puffs_pathobj po_old;
    599 
    600 					/* handle this node */
    601 					po_old = pn_src->pn_po;
    602 					pn_src->pn_po = pcn_targ.pcn_po_full;
    603 
    604 					if (pn_src->pn_va.va_type != VDIR) {
    605 						pu->pu_pathfree(pu, &po_old);
    606 						break;
    607 					}
    608 
    609 					/* handle all child nodes for DIRs */
    610 					pi.pi_old = &pcn_src.pcn_po_full;
    611 					pi.pi_new = &pcn_targ.pcn_po_full;
    612 
    613 					PU_LOCK();
    614 					if (puffs_pn_nodewalk(pu,
    615 					    puffs_path_prefixadj, &pi) != NULL)
    616 						error = ENOMEM;
    617 					PU_UNLOCK();
    618 					pu->pu_pathfree(pu, &po_old);
    619 				}
    620 			}
    621 			break;
    622 		}
    623 
    624 		case PUFFS_VN_MKDIR:
    625 		{
    626 			struct puffs_vnmsg_mkdir *auxt = auxbuf;
    627 			struct puffs_newinfo pni;
    628 			struct puffs_cn pcn;
    629 
    630 			if (pops->puffs_node_mkdir == NULL) {
    631 				error = 0;
    632 				break;
    633 			}
    634 
    635 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    636 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    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(pu,
    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 
    676 			error = pops->puffs_node_rmdir(pu,
    677 			    opcookie, auxt->pvnr_cookie_targ, &pcn);
    678 			break;
    679 		}
    680 
    681 		case PUFFS_VN_SYMLINK:
    682 		{
    683 			struct puffs_vnmsg_symlink *auxt = auxbuf;
    684 			struct puffs_newinfo pni;
    685 			struct puffs_cn pcn;
    686 
    687 			if (pops->puffs_node_symlink == NULL) {
    688 				error = 0;
    689 				break;
    690 			}
    691 
    692 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    693 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    694 
    695 			memset(&pni, 0, sizeof(pni));
    696 			pni.pni_cookie = &auxt->pvnr_newnode;
    697 
    698 			if (buildpath) {
    699 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
    700 				if (error)
    701 					break;
    702 			}
    703 
    704 			error = pops->puffs_node_symlink(pu,
    705 			    opcookie, &pni, &pcn,
    706 			    &auxt->pvnr_va, auxt->pvnr_link);
    707 
    708 			if (buildpath) {
    709 				if (error) {
    710 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
    711 				} else {
    712 					struct puffs_node *pn;
    713 
    714 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
    715 					pn->pn_po = pcn.pcn_po_full;
    716 				}
    717 			}
    718 
    719 			break;
    720 		}
    721 
    722 		case PUFFS_VN_READDIR:
    723 		{
    724 			struct puffs_vnmsg_readdir *auxt = auxbuf;
    725 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    726 			struct dirent *dent;
    727 			off_t *cookies;
    728 			size_t res, origcookies;
    729 
    730 			if (pops->puffs_node_readdir == NULL) {
    731 				error = 0;
    732 				break;
    733 			}
    734 
    735 			if (auxt->pvnr_ncookies) {
    736 				/* LINTED: pvnr_data is __aligned() */
    737 				cookies = (off_t *)auxt->pvnr_data;
    738 				origcookies = auxt->pvnr_ncookies;
    739 			} else {
    740 				cookies = NULL;
    741 				origcookies = 0;
    742 			}
    743 			/* LINTED: dentoff is aligned in the kernel */
    744 			dent = (struct dirent *)
    745 			    (auxt->pvnr_data + auxt->pvnr_dentoff);
    746 
    747 			res = auxt->pvnr_resid;
    748 			error = pops->puffs_node_readdir(pu,
    749 			    opcookie, dent, &auxt->pvnr_offset,
    750 			    &auxt->pvnr_resid, pcr, &auxt->pvnr_eofflag,
    751 			    cookies, &auxt->pvnr_ncookies);
    752 
    753 			/* much easier to track non-working NFS */
    754 			assert(auxt->pvnr_ncookies <= origcookies);
    755 
    756 			/* need to move a bit more */
    757 			preq->preq_buflen = sizeof(struct puffs_vnmsg_readdir)
    758 			    + auxt->pvnr_dentoff + (res - auxt->pvnr_resid);
    759 			break;
    760 		}
    761 
    762 		case PUFFS_VN_READLINK:
    763 		{
    764 			struct puffs_vnmsg_readlink *auxt = auxbuf;
    765 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    766 
    767 			if (pops->puffs_node_readlink == NULL) {
    768 				error = EOPNOTSUPP;
    769 				break;
    770 			}
    771 
    772 			/*LINTED*/
    773 			error = pops->puffs_node_readlink(pu, opcookie, pcr,
    774 			    auxt->pvnr_link, &auxt->pvnr_linklen);
    775 			break;
    776 		}
    777 
    778 		case PUFFS_VN_RECLAIM:
    779 		{
    780 
    781 			if (pops->puffs_node_reclaim == NULL) {
    782 				error = 0;
    783 				break;
    784 			}
    785 
    786 			error = pops->puffs_node_reclaim(pu, opcookie);
    787 			break;
    788 		}
    789 
    790 		case PUFFS_VN_INACTIVE:
    791 		{
    792 
    793 			if (pops->puffs_node_inactive == NULL) {
    794 				error = EOPNOTSUPP;
    795 				break;
    796 			}
    797 
    798 			error = pops->puffs_node_inactive(pu, opcookie);
    799 			break;
    800 		}
    801 
    802 		case PUFFS_VN_PATHCONF:
    803 		{
    804 			struct puffs_vnmsg_pathconf *auxt = auxbuf;
    805 			if (pops->puffs_node_pathconf == NULL) {
    806 				error = 0;
    807 				break;
    808 			}
    809 
    810 			error = pops->puffs_node_pathconf(pu,
    811 			    opcookie, auxt->pvnr_name,
    812 			    &auxt->pvnr_retval);
    813 			break;
    814 		}
    815 
    816 		case PUFFS_VN_ADVLOCK:
    817 		{
    818 			struct puffs_vnmsg_advlock *auxt = auxbuf;
    819 			if (pops->puffs_node_advlock == NULL) {
    820 				error = 0;
    821 				break;
    822 			}
    823 
    824 			error = pops->puffs_node_advlock(pu,
    825 			    opcookie, auxt->pvnr_id, auxt->pvnr_op,
    826 			    &auxt->pvnr_fl, auxt->pvnr_flags);
    827 			break;
    828 		}
    829 
    830 		case PUFFS_VN_PRINT:
    831 		{
    832 			if (pops->puffs_node_print == NULL) {
    833 				error = 0;
    834 				break;
    835 			}
    836 
    837 			error = pops->puffs_node_print(pu,
    838 			    opcookie);
    839 			break;
    840 		}
    841 
    842 		case PUFFS_VN_ABORTOP:
    843 		{
    844 			struct puffs_vnmsg_abortop *auxt = auxbuf;
    845 			struct puffs_cn pcn;
    846 
    847 			if (pops->puffs_node_abortop == NULL) {
    848 				error = 0;
    849 				break;
    850 			}
    851 
    852 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
    853 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
    854 
    855 			error = pops->puffs_node_abortop(pu, opcookie, &pcn);
    856 
    857 			break;
    858 		}
    859 
    860 		case PUFFS_VN_READ:
    861 		{
    862 			struct puffs_vnmsg_read *auxt = auxbuf;
    863 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    864 			size_t res;
    865 
    866 			if (pops->puffs_node_read == NULL) {
    867 				error = EIO;
    868 				break;
    869 			}
    870 
    871 			res = auxt->pvnr_resid;
    872 			error = pops->puffs_node_read(pu,
    873 			    opcookie, auxt->pvnr_data,
    874 			    auxt->pvnr_offset, &auxt->pvnr_resid,
    875 			    pcr, auxt->pvnr_ioflag);
    876 
    877 			/* need to move a bit more */
    878 			preq->preq_buflen = sizeof(struct puffs_vnmsg_read)
    879 			    + (res - auxt->pvnr_resid);
    880 			break;
    881 		}
    882 
    883 		case PUFFS_VN_WRITE:
    884 		{
    885 			struct puffs_vnmsg_write *auxt = auxbuf;
    886 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    887 
    888 			if (pops->puffs_node_write == NULL) {
    889 				error = EIO;
    890 				break;
    891 			}
    892 
    893 			error = pops->puffs_node_write(pu,
    894 			    opcookie, auxt->pvnr_data,
    895 			    auxt->pvnr_offset, &auxt->pvnr_resid,
    896 			    pcr, auxt->pvnr_ioflag);
    897 
    898 			/* don't need to move data back to the kernel */
    899 			preq->preq_buflen = sizeof(struct puffs_vnmsg_write);
    900 			break;
    901 		}
    902 
    903 		case PUFFS_VN_POLL:
    904 		{
    905 			struct puffs_vnmsg_poll *auxt = auxbuf;
    906 
    907 			if (pops->puffs_node_poll == NULL) {
    908 				error = 0;
    909 
    910 				/* emulate genfs_poll() */
    911 				auxt->pvnr_events &= (POLLIN | POLLOUT
    912 						    | POLLRDNORM | POLLWRNORM);
    913 
    914 				break;
    915 			}
    916 
    917 			error = pops->puffs_node_poll(pu,
    918 			    opcookie, &auxt->pvnr_events);
    919 			break;
    920 		}
    921 
    922 		case PUFFS_VN_GETEXTATTR:
    923 		{
    924 			struct puffs_vnmsg_getextattr *auxt = auxbuf;
    925 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    926 			size_t res, *resp, *sizep;
    927 			uint8_t *data;
    928 
    929 			if (pops->puffs_node_getextattr == NULL) {
    930 				error = EOPNOTSUPP;
    931 				break;
    932 			}
    933 
    934 			if (auxt->pvnr_datasize)
    935 				sizep = &auxt->pvnr_datasize;
    936 			else
    937 				sizep = NULL;
    938 
    939 			res = auxt->pvnr_resid;
    940 			if (res > 0) {
    941 				data = auxt->pvnr_data;
    942 				resp = &auxt->pvnr_resid;
    943 			} else {
    944 				data = NULL;
    945 				resp = NULL;
    946 			}
    947 
    948 			error = pops->puffs_node_getextattr(pu,
    949 			    opcookie, auxt->pvnr_attrnamespace,
    950 			    auxt->pvnr_attrname, sizep, data, resp, pcr);
    951 
    952 			/* need to move a bit more? */
    953 			preq->preq_buflen =
    954 			    sizeof(struct puffs_vnmsg_getextattr)
    955 			    + (res - auxt->pvnr_resid);
    956 			break;
    957 		}
    958 
    959 		case PUFFS_VN_SETEXTATTR:
    960 		{
    961 			struct puffs_vnmsg_setextattr *auxt = auxbuf;
    962 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    963 			size_t *resp;
    964 			uint8_t *data;
    965 
    966 			if (pops->puffs_node_setextattr == NULL) {
    967 				error = EOPNOTSUPP;
    968 				break;
    969 			}
    970 
    971 			if (auxt->pvnr_resid > 0) {
    972 				data = auxt->pvnr_data;
    973 				resp = &auxt->pvnr_resid;
    974 			} else {
    975 				data = NULL;
    976 				resp = NULL;
    977 			}
    978 
    979 			error = pops->puffs_node_setextattr(pu,
    980 			    opcookie, auxt->pvnr_attrnamespace,
    981 			    auxt->pvnr_attrname, data, resp, pcr);
    982 			break;
    983 		}
    984 
    985 		case PUFFS_VN_LISTEXTATTR:
    986 		{
    987 			struct puffs_vnmsg_listextattr *auxt = auxbuf;
    988 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
    989 			size_t res, *resp, *sizep;
    990 			uint8_t *data;
    991 
    992 			if (pops->puffs_node_listextattr == NULL) {
    993 				error = EOPNOTSUPP;
    994 				break;
    995 			}
    996 
    997 			if (auxt->pvnr_datasize)
    998 				sizep = &auxt->pvnr_datasize;
    999 			else
   1000 				sizep = NULL;
   1001 
   1002 			res = auxt->pvnr_resid;
   1003 			if (res > 0) {
   1004 				data = auxt->pvnr_data;
   1005 				resp = &auxt->pvnr_resid;
   1006 			} else {
   1007 				data = NULL;
   1008 				resp = NULL;
   1009 			}
   1010 
   1011 			res = auxt->pvnr_resid;
   1012 			error = pops->puffs_node_listextattr(pu,
   1013 			    opcookie, auxt->pvnr_attrnamespace,
   1014 			    sizep, data, resp, pcr);
   1015 
   1016 			/* need to move a bit more? */
   1017 			preq->preq_buflen =
   1018 			    sizeof(struct puffs_vnmsg_listextattr)
   1019 			    + (res - auxt->pvnr_resid);
   1020 			break;
   1021 		}
   1022 
   1023 		case PUFFS_VN_DELETEEXTATTR:
   1024 		{
   1025 			struct puffs_vnmsg_deleteextattr *auxt = auxbuf;
   1026 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
   1027 
   1028 			if (pops->puffs_node_deleteextattr == NULL) {
   1029 				error = EOPNOTSUPP;
   1030 				break;
   1031 			}
   1032 
   1033 			error = pops->puffs_node_deleteextattr(pu,
   1034 			    opcookie, auxt->pvnr_attrnamespace,
   1035 			    auxt->pvnr_attrname, pcr);
   1036 			break;
   1037 		}
   1038 
   1039 		default:
   1040 			printf("inval op %d\n", preq->preq_optype);
   1041 			error = EINVAL;
   1042 			break;
   1043 		}
   1044 
   1045 #if 0
   1046 	/* not issued by kernel currently */
   1047 	} else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_CACHE) {
   1048 		struct puffs_cacheinfo *pci = (void *)preq;
   1049 
   1050 		if (pu->pu_ops.puffs_cache_write) {
   1051 			pu->pu_ops.puffs_cache_write(pu, preq->preq_cookie,
   1052 			    pci->pcache_nruns, pci->pcache_runs);
   1053 		}
   1054 		error = 0;
   1055 #endif
   1056 
   1057 	} else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_ERROR) {
   1058 		struct puffs_error *perr = (void *)preq;
   1059 
   1060 		pu->pu_errnotify(pu, preq->preq_optype,
   1061 		    perr->perr_error, perr->perr_str, preq->preq_cookie);
   1062 		error = 0;
   1063 	} else {
   1064 		/*
   1065 		 * I guess the kernel sees this one coming also
   1066 		 */
   1067 		error = EINVAL;
   1068 	}
   1069 
   1070  out:
   1071 	preq->preq_rv = error;
   1072 
   1073 	if (pu->pu_oppost)
   1074 		pu->pu_oppost(pu);
   1075 
   1076 	pcc->pcc_flags |= PCC_DONE;
   1077 }
   1078