xref: /netbsd-src/lib/libpuffs/dispatcher.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /*	$NetBSD: dispatcher.c,v 1.26 2007/12/08 19:57:03 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 and the Finnish Cultural 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.26 2007/12/08 19:57:03 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 #ifdef PUFFS_WITH_THREADS
42 #include <pthread.h>
43 #endif
44 #include <puffs.h>
45 #include <puffsdump.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <unistd.h>
49 
50 #include "puffs_priv.h"
51 
52 static void processresult(struct puffs_cc *, int);
53 
54 /*
55  * Set the following to 1 to not handle each request on a separate
56  * stack.  This is highly volatile kludge, therefore no external
57  * interface.
58  */
59 int puffs_fakecc;
60 
61 /*
62  * Set the following to 1 to handle each request in a separate pthread.
63  * This is not exported as it should not be used yet unless having a
64  * very good knowledge of what you're signing up for (libpuffs is not
65  * threadsafe).
66  */
67 int puffs_usethreads;
68 
69 static int
70 dopufbuf2(struct puffs_usermount *pu, struct puffs_framebuf *pb)
71 {
72 	struct puffs_req *preq = puffs__framebuf_getdataptr(pb);
73 	struct puffs_cc *pcc;
74 	int type;
75 
76 	if (puffs_fakecc) {
77 		type = PCC_FAKECC;
78 	} else if (puffs_usethreads) {
79 		type = PCC_THREADED;
80 #ifndef PUFFS_WITH_THREADS
81 		type = PCC_FAKECC;
82 #endif
83 	} else {
84 		type = PCC_REALCC;
85 	}
86 
87 	if (puffs_cc_create(pu, pb, type, &pcc) == -1)
88 		return errno;
89 
90 	puffs_cc_setcaller(pcc, preq->preq_pid, preq->preq_lid);
91 
92 #ifdef PUFFS_WITH_THREADS
93 	if (puffs_usethreads) {
94 		pthread_attr_t pattr;
95 		pthread_t ptid;
96 		int rv;
97 
98 		pthread_attr_init(&pattr);
99 		pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_DETACHED);
100 		pthread_attr_destroy(&pattr);
101 
102 		ap->pwa_pcc = pcc;
103 
104 		rv = pthread_create(&ptid, &pattr, puffs_docc, pcc);
105 
106 		return rv;
107 	}
108 #endif
109 	puffs_docc(pcc);
110 	return 0;
111 }
112 
113 /*
114  * User-visible point to handle a request from.
115  *
116  * <insert text here>
117  */
118 int
119 puffs_dopufbuf(struct puffs_usermount *pu, struct puffs_framebuf *pb)
120 {
121 	struct puffs_req *preq = puffs__framebuf_getdataptr(pb);
122 	struct puffs_executor *pex;
123 
124 	/*
125 	 * XXX: the structure is currently a mess.  anyway, trap
126 	 * the cacheops here already, since they don't need a cc.
127 	 * I really should get around to revamping the operation
128 	 * dispatching code one of these days.
129 	 *
130 	 * Do the same for error notifications.
131 	 */
132 	if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_CACHE) {
133 		struct puffs_cacheinfo *pci = (void *)preq;
134 
135 		if (pu->pu_ops.puffs_cache_write == NULL)
136 			return 0;
137 
138 		pu->pu_ops.puffs_cache_write(pu, preq->preq_cookie,
139 		    pci->pcache_nruns, pci->pcache_runs);
140 		return 0;
141 	} else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_ERROR) {
142 		struct puffs_error *perr = (void *)preq;
143 
144 		pu->pu_errnotify(pu, preq->preq_optype,
145 		    perr->perr_error, perr->perr_str, preq->preq_cookie);
146 		return 0;
147 	}
148 
149 	if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
150 		puffsdump_req(preq);
151 
152 	/*
153 	 * Check if we are already processing an operation from the same
154 	 * caller.  If so, queue this operation until the previous one
155 	 * finishes.  This prevents us from executing certain operations
156 	 * out-of-order (e.g. fsync and reclaim).
157 	 *
158 	 * Each preq will only remove its own pex from the tailq.
159 	 * See puffs_docc() for the details on other-end removal
160 	 * and dispatching.
161 	 */
162 	pex = malloc(sizeof(struct puffs_executor));
163 	pex->pex_pufbuf = pb;
164 	PU_LOCK();
165 	TAILQ_INSERT_TAIL(&pu->pu_exq, pex, pex_entries);
166 	TAILQ_FOREACH(pex, &pu->pu_exq, pex_entries) {
167 		struct puffs_req *pb_preq;
168 
169 		pb_preq = puffs__framebuf_getdataptr(pex->pex_pufbuf);
170 		if (pb_preq->preq_pid == preq->preq_pid
171 		    && pb_preq->preq_lid == preq->preq_lid) {
172 			if (pb_preq != preq) {
173 				PU_UNLOCK();
174 				return 0;
175 			}
176 		}
177 	}
178 	PU_UNLOCK();
179 
180 	return dopufbuf2(pu, pb);
181 }
182 
183 enum {PUFFCALL_ANSWER, PUFFCALL_IGNORE, PUFFCALL_AGAIN};
184 
185 void *
186 puffs_docc(void *arg)
187 {
188 	struct puffs_cc *pcc = arg;
189 	struct puffs_usermount *pu = pcc->pcc_pu;
190 	struct puffs_req *preq;
191 	struct puffs_cc *pcc_iter;
192 	struct puffs_executor *pex, *pex_n;
193 	int found;
194 
195 	assert((pcc->pcc_flags & PCC_DONE) == 0);
196 
197 	if (pcc->pcc_flags & PCC_REALCC)
198 		puffs_cc_continue(pcc);
199 	else
200 		puffs_calldispatcher(pcc);
201 
202 	if ((pcc->pcc_flags & PCC_DONE) == 0) {
203 		assert(pcc->pcc_flags & PCC_REALCC);
204 		return NULL;
205 	}
206 
207 	/* check if we need to schedule FAFs which were stalled */
208 	found = 0;
209 	preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
210 	PU_LOCK();
211 	for (pex = TAILQ_FIRST(&pu->pu_exq); pex; pex = pex_n) {
212 		struct puffs_req *pb_preq;
213 
214 		pb_preq = puffs__framebuf_getdataptr(pex->pex_pufbuf);
215 		pex_n = TAILQ_NEXT(pex, pex_entries);
216 		if (pb_preq->preq_pid == preq->preq_pid
217 		    && pb_preq->preq_lid == preq->preq_lid) {
218 			if (found == 0) {
219 				/* this is us */
220 				assert(pb_preq == preq);
221 				TAILQ_REMOVE(&pu->pu_exq, pex, pex_entries);
222 				free(pex);
223 				found = 1;
224 			} else {
225 				/* down at the mardi gras */
226 				PU_UNLOCK();
227 				dopufbuf2(pu, pex->pex_pufbuf);
228 				PU_LOCK();
229 				break;
230 			}
231 		}
232 	}
233 
234 	if (!PUFFSOP_WANTREPLY(preq->preq_opclass))
235 		puffs_framebuf_destroy(pcc->pcc_pb);
236 
237 	/* can't do this above due to PCC_BORROWED */
238 	while ((pcc_iter = LIST_FIRST(&pu->pu_ccnukelst)) != NULL) {
239 		LIST_REMOVE(pcc_iter, nlst_entries);
240 		puffs_cc_destroy(pcc_iter);
241 	}
242 	PU_UNLOCK();
243 
244 	return NULL;
245 }
246 
247 /* library private, but linked from callcontext.c */
248 
249 void
250 puffs_calldispatcher(struct puffs_cc *pcc)
251 {
252 	struct puffs_usermount *pu = pcc->pcc_pu;
253 	struct puffs_ops *pops = &pu->pu_ops;
254 	struct puffs_req *preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
255 	void *auxbuf = preq; /* help with typecasting */
256 	void *opcookie = preq->preq_cookie;
257 	int error, rv, buildpath;
258 
259 	assert(pcc->pcc_flags & (PCC_FAKECC | PCC_REALCC | PCC_THREADED));
260 	assert(pcc == puffs_cc_getcc(pu)); /* remove me soon */
261 
262 	if (PUFFSOP_WANTREPLY(preq->preq_opclass))
263 		rv = PUFFCALL_ANSWER;
264 	else
265 		rv = PUFFCALL_IGNORE;
266 
267 	buildpath = pu->pu_flags & PUFFS_FLAG_BUILDPATH;
268 	preq->preq_setbacks = 0;
269 
270 	if (pu->pu_oppre)
271 		pu->pu_oppre(pu);
272 
273 	if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) {
274 		switch (preq->preq_optype) {
275 		case PUFFS_VFS_UNMOUNT:
276 		{
277 			struct puffs_vfsmsg_unmount *auxt = auxbuf;
278 
279 			PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTING);
280 			error = pops->puffs_fs_unmount(pu, auxt->pvfsr_flags);
281 			if (!error)
282 				PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTED);
283 			else
284 				PU_SETSTATE(pu, PUFFS_STATE_RUNNING);
285 			break;
286 		}
287 
288 		case PUFFS_VFS_STATVFS:
289 		{
290 			struct puffs_vfsmsg_statvfs *auxt = auxbuf;
291 
292 			error = pops->puffs_fs_statvfs(pu, &auxt->pvfsr_sb);
293 			break;
294 		}
295 
296 		case PUFFS_VFS_SYNC:
297 		{
298 			struct puffs_vfsmsg_sync *auxt = auxbuf;
299 			PUFFS_MAKECRED(pcr, &auxt->pvfsr_cred);
300 
301 			error = pops->puffs_fs_sync(pu,
302 			    auxt->pvfsr_waitfor, pcr);
303 			break;
304 		}
305 
306 		case PUFFS_VFS_FHTOVP:
307 		{
308 			struct puffs_vfsmsg_fhtonode *auxt = auxbuf;
309 			struct puffs_newinfo pni;
310 
311 			pni.pni_cookie = &auxt->pvfsr_fhcookie;
312 			pni.pni_vtype = &auxt->pvfsr_vtype;
313 			pni.pni_size = &auxt->pvfsr_size;
314 			pni.pni_rdev = &auxt->pvfsr_rdev;
315 
316 			error = pops->puffs_fs_fhtonode(pu, auxt->pvfsr_data,
317 			    auxt->pvfsr_dsize, &pni);
318 
319 			break;
320 		}
321 
322 		case PUFFS_VFS_VPTOFH:
323 		{
324 			struct puffs_vfsmsg_nodetofh *auxt = auxbuf;
325 
326 			error = pops->puffs_fs_nodetofh(pu,
327 			    auxt->pvfsr_fhcookie, auxt->pvfsr_data,
328 			    &auxt->pvfsr_dsize);
329 
330 			break;
331 		}
332 
333 		case PUFFS_VFS_SUSPEND:
334 		{
335 			struct puffs_vfsmsg_suspend *auxt = auxbuf;
336 
337 			error = 0;
338 			if (pops->puffs_fs_suspend == NULL)
339 				break;
340 
341 			pops->puffs_fs_suspend(pu, auxt->pvfsr_status);
342 			break;
343 		}
344 
345 		default:
346 			/*
347 			 * I guess the kernel sees this one coming
348 			 */
349 			error = EINVAL;
350 			break;
351 		}
352 
353 	/* XXX: audit return values */
354 	/* XXX: sync with kernel */
355 	} else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) {
356 		switch (preq->preq_optype) {
357 		case PUFFS_VN_LOOKUP:
358 		{
359 			struct puffs_vnmsg_lookup *auxt = auxbuf;
360 			struct puffs_newinfo pni;
361 			struct puffs_cn pcn;
362 
363 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
364 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
365 			pni.pni_cookie = &auxt->pvnr_newnode;
366 			pni.pni_vtype = &auxt->pvnr_vtype;
367 			pni.pni_size = &auxt->pvnr_size;
368 			pni.pni_rdev = &auxt->pvnr_rdev;
369 
370 			if (buildpath) {
371 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
372 				if (error)
373 					break;
374 			}
375 
376 			/* lookup *must* be present */
377 			error = pops->puffs_node_lookup(pu, opcookie,
378 			    &pni, &pcn);
379 
380 			if (buildpath) {
381 				if (error) {
382 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
383 				} else {
384 					struct puffs_node *pn;
385 
386 					/*
387 					 * did we get a new node or a
388 					 * recycled node?
389 					 */
390 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
391 					if (pn->pn_po.po_path == NULL)
392 						pn->pn_po = pcn.pcn_po_full;
393 					else
394 						pu->pu_pathfree(pu,
395 						    &pcn.pcn_po_full);
396 				}
397 			}
398 
399 			break;
400 		}
401 
402 		case PUFFS_VN_CREATE:
403 		{
404 			struct puffs_vnmsg_create *auxt = auxbuf;
405 			struct puffs_newinfo pni;
406 			struct puffs_cn pcn;
407 
408 			if (pops->puffs_node_create == NULL) {
409 				error = 0;
410 				break;
411 			}
412 
413 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
414 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
415 
416 			memset(&pni, 0, sizeof(pni));
417 			pni.pni_cookie = &auxt->pvnr_newnode;
418 
419 			if (buildpath) {
420 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
421 				if (error)
422 					break;
423 			}
424 
425 			error = pops->puffs_node_create(pu,
426 			    opcookie, &pni, &pcn, &auxt->pvnr_va);
427 
428 			if (buildpath) {
429 				if (error) {
430 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
431 				} else {
432 					struct puffs_node *pn;
433 
434 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
435 					pn->pn_po = pcn.pcn_po_full;
436 				}
437 			}
438 
439 			break;
440 		}
441 
442 		case PUFFS_VN_MKNOD:
443 		{
444 			struct puffs_vnmsg_mknod *auxt = auxbuf;
445 			struct puffs_newinfo pni;
446 			struct puffs_cn pcn;
447 
448 			if (pops->puffs_node_mknod == NULL) {
449 				error = 0;
450 				break;
451 			}
452 
453 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
454 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
455 
456 			memset(&pni, 0, sizeof(pni));
457 			pni.pni_cookie = &auxt->pvnr_newnode;
458 
459 			if (buildpath) {
460 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
461 				if (error)
462 					break;
463 			}
464 
465 			error = pops->puffs_node_mknod(pu,
466 			    opcookie, &pni, &pcn, &auxt->pvnr_va);
467 
468 			if (buildpath) {
469 				if (error) {
470 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
471 				} else {
472 					struct puffs_node *pn;
473 
474 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
475 					pn->pn_po = pcn.pcn_po_full;
476 				}
477 			}
478 
479 			break;
480 		}
481 
482 		case PUFFS_VN_OPEN:
483 		{
484 			struct puffs_vnmsg_open *auxt = auxbuf;
485 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
486 
487 			if (pops->puffs_node_open == NULL) {
488 				error = 0;
489 				break;
490 			}
491 
492 			error = pops->puffs_node_open(pu,
493 			    opcookie, auxt->pvnr_mode, pcr);
494 			break;
495 		}
496 
497 		case PUFFS_VN_CLOSE:
498 		{
499 			struct puffs_vnmsg_close *auxt = auxbuf;
500 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
501 
502 			if (pops->puffs_node_close == NULL) {
503 				error = 0;
504 				break;
505 			}
506 
507 			error = pops->puffs_node_close(pu,
508 			    opcookie, auxt->pvnr_fflag, pcr);
509 			break;
510 		}
511 
512 		case PUFFS_VN_ACCESS:
513 		{
514 			struct puffs_vnmsg_access *auxt = auxbuf;
515 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
516 
517 			if (pops->puffs_node_access == NULL) {
518 				error = 0;
519 				break;
520 			}
521 
522 			error = pops->puffs_node_access(pu,
523 			    opcookie, auxt->pvnr_mode, pcr);
524 			break;
525 		}
526 
527 		case PUFFS_VN_GETATTR:
528 		{
529 			struct puffs_vnmsg_getattr *auxt = auxbuf;
530 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
531 
532 			if (pops->puffs_node_getattr == NULL) {
533 				error = EOPNOTSUPP;
534 				break;
535 			}
536 
537 			error = pops->puffs_node_getattr(pu,
538 			    opcookie, &auxt->pvnr_va, pcr);
539 			break;
540 		}
541 
542 		case PUFFS_VN_SETATTR:
543 		{
544 			struct puffs_vnmsg_setattr *auxt = auxbuf;
545 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
546 
547 			if (pops->puffs_node_setattr == NULL) {
548 				error = EOPNOTSUPP;
549 				break;
550 			}
551 
552 			error = pops->puffs_node_setattr(pu,
553 			    opcookie, &auxt->pvnr_va, pcr);
554 			break;
555 		}
556 
557 		case PUFFS_VN_MMAP:
558 		{
559 			struct puffs_vnmsg_mmap *auxt = auxbuf;
560 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
561 
562 			if (pops->puffs_node_mmap == NULL) {
563 				error = 0;
564 				break;
565 			}
566 
567 			error = pops->puffs_node_mmap(pu,
568 			    opcookie, auxt->pvnr_prot, pcr);
569 			break;
570 		}
571 
572 		case PUFFS_VN_FSYNC:
573 		{
574 			struct puffs_vnmsg_fsync *auxt = auxbuf;
575 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
576 
577 			if (pops->puffs_node_fsync == NULL) {
578 				error = 0;
579 				break;
580 			}
581 
582 			error = pops->puffs_node_fsync(pu, opcookie, pcr,
583 			    auxt->pvnr_flags, auxt->pvnr_offlo,
584 			    auxt->pvnr_offhi);
585 			break;
586 		}
587 
588 		case PUFFS_VN_SEEK:
589 		{
590 			struct puffs_vnmsg_seek *auxt = auxbuf;
591 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
592 
593 			if (pops->puffs_node_seek == NULL) {
594 				error = 0;
595 				break;
596 			}
597 
598 			error = pops->puffs_node_seek(pu,
599 			    opcookie, auxt->pvnr_oldoff,
600 			    auxt->pvnr_newoff, pcr);
601 			break;
602 		}
603 
604 		case PUFFS_VN_REMOVE:
605 		{
606 			struct puffs_vnmsg_remove *auxt = auxbuf;
607 			struct puffs_cn pcn;
608 			if (pops->puffs_node_remove == NULL) {
609 				error = 0;
610 				break;
611 			}
612 
613 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
614 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
615 
616 			error = pops->puffs_node_remove(pu,
617 			    opcookie, auxt->pvnr_cookie_targ, &pcn);
618 			break;
619 		}
620 
621 		case PUFFS_VN_LINK:
622 		{
623 			struct puffs_vnmsg_link *auxt = auxbuf;
624 			struct puffs_cn pcn;
625 			if (pops->puffs_node_link == NULL) {
626 				error = 0;
627 				break;
628 			}
629 
630 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
631 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
632 
633 			if (buildpath) {
634 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
635 				if (error)
636 					break;
637 			}
638 
639 			error = pops->puffs_node_link(pu,
640 			    opcookie, auxt->pvnr_cookie_targ, &pcn);
641 			if (buildpath)
642 				pu->pu_pathfree(pu, &pcn.pcn_po_full);
643 
644 			break;
645 		}
646 
647 		case PUFFS_VN_RENAME:
648 		{
649 			struct puffs_vnmsg_rename *auxt = auxbuf;
650 			struct puffs_cn pcn_src, pcn_targ;
651 			struct puffs_node *pn_src;
652 
653 			if (pops->puffs_node_rename == NULL) {
654 				error = 0;
655 				break;
656 			}
657 
658 			pcn_src.pcn_pkcnp = &auxt->pvnr_cn_src;
659 			PUFFS_KCREDTOCRED(pcn_src.pcn_cred,
660 			    &auxt->pvnr_cn_src_cred);
661 
662 			pcn_targ.pcn_pkcnp = &auxt->pvnr_cn_targ;
663 			PUFFS_KCREDTOCRED(pcn_targ.pcn_cred,
664 			    &auxt->pvnr_cn_targ_cred);
665 
666 			if (buildpath) {
667 				pn_src = auxt->pvnr_cookie_src;
668 				pcn_src.pcn_po_full = pn_src->pn_po;
669 
670 				error = puffs_path_pcnbuild(pu, &pcn_targ,
671 				    auxt->pvnr_cookie_targdir);
672 				if (error)
673 					break;
674 			}
675 
676 			error = pops->puffs_node_rename(pu,
677 			    opcookie, auxt->pvnr_cookie_src,
678 			    &pcn_src, auxt->pvnr_cookie_targdir,
679 			    auxt->pvnr_cookie_targ, &pcn_targ);
680 
681 			if (buildpath) {
682 				if (error) {
683 					pu->pu_pathfree(pu,
684 					    &pcn_targ.pcn_po_full);
685 				} else {
686 					struct puffs_pathinfo pi;
687 					struct puffs_pathobj po_old;
688 
689 					/* handle this node */
690 					po_old = pn_src->pn_po;
691 					pn_src->pn_po = pcn_targ.pcn_po_full;
692 
693 					if (pn_src->pn_va.va_type != VDIR) {
694 						pu->pu_pathfree(pu, &po_old);
695 						break;
696 					}
697 
698 					/* handle all child nodes for DIRs */
699 					pi.pi_old = &pcn_src.pcn_po_full;
700 					pi.pi_new = &pcn_targ.pcn_po_full;
701 
702 					PU_LOCK();
703 					if (puffs_pn_nodewalk(pu,
704 					    puffs_path_prefixadj, &pi) != NULL)
705 						error = ENOMEM;
706 					PU_UNLOCK();
707 					pu->pu_pathfree(pu, &po_old);
708 				}
709 			}
710 			break;
711 		}
712 
713 		case PUFFS_VN_MKDIR:
714 		{
715 			struct puffs_vnmsg_mkdir *auxt = auxbuf;
716 			struct puffs_newinfo pni;
717 			struct puffs_cn pcn;
718 
719 			if (pops->puffs_node_mkdir == NULL) {
720 				error = 0;
721 				break;
722 			}
723 
724 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
725 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
726 
727 			memset(&pni, 0, sizeof(pni));
728 			pni.pni_cookie = &auxt->pvnr_newnode;
729 
730 			if (buildpath) {
731 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
732 				if (error)
733 					break;
734 			}
735 
736 			error = pops->puffs_node_mkdir(pu,
737 			    opcookie, &pni, &pcn, &auxt->pvnr_va);
738 
739 			if (buildpath) {
740 				if (error) {
741 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
742 				} else {
743 					struct puffs_node *pn;
744 
745 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
746 					pn->pn_po = pcn.pcn_po_full;
747 				}
748 			}
749 
750 			break;
751 		}
752 
753 		case PUFFS_VN_RMDIR:
754 		{
755 			struct puffs_vnmsg_rmdir *auxt = auxbuf;
756 			struct puffs_cn pcn;
757 			if (pops->puffs_node_rmdir == NULL) {
758 				error = 0;
759 				break;
760 			}
761 
762 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
763 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
764 
765 			error = pops->puffs_node_rmdir(pu,
766 			    opcookie, auxt->pvnr_cookie_targ, &pcn);
767 			break;
768 		}
769 
770 		case PUFFS_VN_SYMLINK:
771 		{
772 			struct puffs_vnmsg_symlink *auxt = auxbuf;
773 			struct puffs_newinfo pni;
774 			struct puffs_cn pcn;
775 
776 			if (pops->puffs_node_symlink == NULL) {
777 				error = 0;
778 				break;
779 			}
780 
781 			pcn.pcn_pkcnp = &auxt->pvnr_cn;
782 			PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
783 
784 			memset(&pni, 0, sizeof(pni));
785 			pni.pni_cookie = &auxt->pvnr_newnode;
786 
787 			if (buildpath) {
788 				error = puffs_path_pcnbuild(pu, &pcn, opcookie);
789 				if (error)
790 					break;
791 			}
792 
793 			error = pops->puffs_node_symlink(pu,
794 			    opcookie, &pni, &pcn,
795 			    &auxt->pvnr_va, auxt->pvnr_link);
796 
797 			if (buildpath) {
798 				if (error) {
799 					pu->pu_pathfree(pu, &pcn.pcn_po_full);
800 				} else {
801 					struct puffs_node *pn;
802 
803 					pn = PU_CMAP(pu, auxt->pvnr_newnode);
804 					pn->pn_po = pcn.pcn_po_full;
805 				}
806 			}
807 
808 			break;
809 		}
810 
811 		case PUFFS_VN_READDIR:
812 		{
813 			struct puffs_vnmsg_readdir *auxt = auxbuf;
814 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
815 			struct dirent *dent;
816 			off_t *cookies;
817 			size_t res, origcookies;
818 
819 			if (pops->puffs_node_readdir == NULL) {
820 				error = 0;
821 				break;
822 			}
823 
824 			if (auxt->pvnr_ncookies) {
825 				/* LINTED: pvnr_data is __aligned() */
826 				cookies = (off_t *)auxt->pvnr_data;
827 				origcookies = auxt->pvnr_ncookies;
828 			} else {
829 				cookies = NULL;
830 				origcookies = 0;
831 			}
832 			/* LINTED: dentoff is aligned in the kernel */
833 			dent = (struct dirent *)
834 			    (auxt->pvnr_data + auxt->pvnr_dentoff);
835 
836 			res = auxt->pvnr_resid;
837 			error = pops->puffs_node_readdir(pu,
838 			    opcookie, dent, &auxt->pvnr_offset,
839 			    &auxt->pvnr_resid, pcr, &auxt->pvnr_eofflag,
840 			    cookies, &auxt->pvnr_ncookies);
841 
842 			/* much easier to track non-working NFS */
843 			assert(auxt->pvnr_ncookies <= origcookies);
844 
845 			/* need to move a bit more */
846 			preq->preq_buflen = sizeof(struct puffs_vnmsg_readdir)
847 			    + auxt->pvnr_dentoff + (res - auxt->pvnr_resid);
848 			break;
849 		}
850 
851 		case PUFFS_VN_READLINK:
852 		{
853 			struct puffs_vnmsg_readlink *auxt = auxbuf;
854 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
855 
856 			if (pops->puffs_node_readlink == NULL) {
857 				error = EOPNOTSUPP;
858 				break;
859 			}
860 
861 			/*LINTED*/
862 			error = pops->puffs_node_readlink(pu, opcookie, pcr,
863 			    auxt->pvnr_link, &auxt->pvnr_linklen);
864 			break;
865 		}
866 
867 		case PUFFS_VN_RECLAIM:
868 		{
869 
870 			if (pops->puffs_node_reclaim == NULL) {
871 				error = 0;
872 				break;
873 			}
874 
875 			error = pops->puffs_node_reclaim(pu, opcookie);
876 			break;
877 		}
878 
879 		case PUFFS_VN_INACTIVE:
880 		{
881 
882 			if (pops->puffs_node_inactive == NULL) {
883 				error = EOPNOTSUPP;
884 				break;
885 			}
886 
887 			error = pops->puffs_node_inactive(pu, opcookie);
888 			break;
889 		}
890 
891 		case PUFFS_VN_PATHCONF:
892 		{
893 			struct puffs_vnmsg_pathconf *auxt = auxbuf;
894 			if (pops->puffs_node_pathconf == NULL) {
895 				error = 0;
896 				break;
897 			}
898 
899 			error = pops->puffs_node_pathconf(pu,
900 			    opcookie, auxt->pvnr_name,
901 			    &auxt->pvnr_retval);
902 			break;
903 		}
904 
905 		case PUFFS_VN_ADVLOCK:
906 		{
907 			struct puffs_vnmsg_advlock *auxt = auxbuf;
908 			if (pops->puffs_node_advlock == NULL) {
909 				error = 0;
910 				break;
911 			}
912 
913 			error = pops->puffs_node_advlock(pu,
914 			    opcookie, auxt->pvnr_id, auxt->pvnr_op,
915 			    &auxt->pvnr_fl, auxt->pvnr_flags);
916 			break;
917 		}
918 
919 		case PUFFS_VN_PRINT:
920 		{
921 			if (pops->puffs_node_print == NULL) {
922 				error = 0;
923 				break;
924 			}
925 
926 			error = pops->puffs_node_print(pu,
927 			    opcookie);
928 			break;
929 		}
930 
931 		case PUFFS_VN_READ:
932 		{
933 			struct puffs_vnmsg_read *auxt = auxbuf;
934 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
935 			size_t res;
936 
937 			if (pops->puffs_node_read == NULL) {
938 				error = EIO;
939 				break;
940 			}
941 
942 			res = auxt->pvnr_resid;
943 			error = pops->puffs_node_read(pu,
944 			    opcookie, auxt->pvnr_data,
945 			    auxt->pvnr_offset, &auxt->pvnr_resid,
946 			    pcr, auxt->pvnr_ioflag);
947 
948 			/* need to move a bit more */
949 			preq->preq_buflen = sizeof(struct puffs_vnmsg_read)
950 			    + (res - auxt->pvnr_resid);
951 			break;
952 		}
953 
954 		case PUFFS_VN_WRITE:
955 		{
956 			struct puffs_vnmsg_write *auxt = auxbuf;
957 			PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
958 
959 			if (pops->puffs_node_write == NULL) {
960 				error = EIO;
961 				break;
962 			}
963 
964 			error = pops->puffs_node_write(pu,
965 			    opcookie, auxt->pvnr_data,
966 			    auxt->pvnr_offset, &auxt->pvnr_resid,
967 			    pcr, auxt->pvnr_ioflag);
968 
969 			/* don't need to move data back to the kernel */
970 			preq->preq_buflen = sizeof(struct puffs_vnmsg_write);
971 			break;
972 		}
973 
974 		case PUFFS_VN_POLL:
975 		{
976 			struct puffs_vnmsg_poll *auxt = auxbuf;
977 
978 			if (pops->puffs_node_poll == NULL) {
979 				error = 0;
980 
981 				/* emulate genfs_poll() */
982 				auxt->pvnr_events &= (POLLIN | POLLOUT
983 						    | POLLRDNORM | POLLWRNORM);
984 
985 				break;
986 			}
987 
988 			error = pops->puffs_node_poll(pu,
989 			    opcookie, &auxt->pvnr_events);
990 			break;
991 		}
992 
993 		default:
994 			printf("inval op %d\n", preq->preq_optype);
995 			error = EINVAL;
996 			break;
997 		}
998 	} else {
999 		/*
1000 		 * this one also
1001 		 */
1002 		error = EINVAL;
1003 	}
1004 
1005 	preq->preq_rv = error;
1006 	pcc->pcc_flags |= PCC_DONE;
1007 
1008 	if (pu->pu_oppost)
1009 		pu->pu_oppost(pu);
1010 
1011 	/*
1012 	 * Note, we are calling this from here so that we can run it
1013 	 * off of the continuation stack.  Otherwise puffs_goto() would
1014 	 * not work.
1015 	 */
1016 	processresult(pcc, rv);
1017 }
1018 
1019 static void
1020 processresult(struct puffs_cc *pcc, int how)
1021 {
1022 	struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
1023 	struct puffs_req *preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
1024 	int pccflags = pcc->pcc_flags;
1025 
1026 	/* check if we need to store this reply */
1027 	switch (how) {
1028 	case PUFFCALL_ANSWER:
1029 		if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
1030 			puffsdump_rv(preq);
1031 
1032 		puffs_framev_enqueue_justsend(pu, pu->pu_fd,
1033 		    pcc->pcc_pb, 0, 0);
1034 		/*FALLTHROUGH*/
1035 
1036 	case PUFFCALL_IGNORE:
1037 		PU_LOCK();
1038 		LIST_INSERT_HEAD(&pu->pu_ccnukelst, pcc, nlst_entries);
1039 		PU_UNLOCK();
1040 		break;
1041 
1042 	case PUFFCALL_AGAIN:
1043 		if ((pcc->pcc_flags & PCC_REALCC) == 0)
1044 			assert(pcc->pcc_flags & PCC_DONE);
1045 		break;
1046 
1047 	default:
1048 		assert(/*CONSTCOND*/0);
1049 	}
1050 
1051 	/* who needs information when you're living on borrowed time? */
1052 	if (pccflags & PCC_BORROWED) {
1053 		assert((pccflags & PCC_THREADED) == 0);
1054 		puffs_cc_yield(pcc); /* back to borrow source */
1055 	}
1056 }
1057