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