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