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