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