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