dispatcher.c revision 1.29 1 /* $NetBSD: dispatcher.c,v 1.29 2008/01/16 23:17:43 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 and the Finnish Cultural 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.29 2008/01/16 23:17:43 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 #ifdef PUFFS_WITH_THREADS
42 #include <pthread.h>
43 #endif
44 #include <puffs.h>
45 #include <puffsdump.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <unistd.h>
49
50 #include "puffs_priv.h"
51
52 static void processresult(struct puffs_usermount *, int);
53
54 /*
55 * Set the following to 1 to not handle each request on a separate
56 * stack. This is highly volatile kludge, therefore no external
57 * interface.
58 */
59 int puffs_fakecc;
60
61 /*
62 * Set the following to 1 to handle each request in a separate pthread.
63 * This is not exported as it should not be used yet unless having a
64 * very good knowledge of what you're signing up for (libpuffs is not
65 * threadsafe).
66 */
67 int puffs_usethreads;
68
69 static int
70 dopufbuf2(struct puffs_usermount *pu, struct puffs_framebuf *pb)
71 {
72 struct puffs_req *preq = puffs__framebuf_getdataptr(pb);
73 struct puffs_cc *pcc;
74 int type;
75
76 if (puffs_fakecc) {
77 type = PCC_FAKECC;
78 } else if (puffs_usethreads) {
79 type = PCC_THREADED;
80 #ifndef PUFFS_WITH_THREADS
81 type = PCC_FAKECC;
82 #endif
83 } else {
84 type = PCC_REALCC;
85 }
86
87 if (puffs_cc_create(pu, pb, type, &pcc) == -1)
88 return errno;
89
90 puffs_cc_setcaller(pcc, preq->preq_pid, preq->preq_lid);
91
92 #ifdef PUFFS_WITH_THREADS
93 if (puffs_usethreads) {
94 pthread_attr_t pattr;
95 pthread_t ptid;
96 int rv;
97
98 pthread_attr_init(&pattr);
99 pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_DETACHED);
100 pthread_attr_destroy(&pattr);
101
102 ap->pwa_pcc = pcc;
103
104 rv = pthread_create(&ptid, &pattr, puffs_docc, pcc);
105
106 return rv;
107 }
108 #endif
109 puffs_docc(pcc);
110 return 0;
111 }
112
113 /*
114 * User-visible point to handle a request from.
115 *
116 * <insert text here>
117 */
118 int
119 puffs_dopufbuf(struct puffs_usermount *pu, struct puffs_framebuf *pb)
120 {
121 struct puffs_req *preq = puffs__framebuf_getdataptr(pb);
122
123 /*
124 * XXX: the structure is currently a mess. anyway, trap
125 * the cacheops here already, since they don't need a cc.
126 * I really should get around to revamping the operation
127 * dispatching code one of these days.
128 *
129 * Do the same for error notifications.
130 */
131 if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_CACHE) {
132 struct puffs_cacheinfo *pci = (void *)preq;
133
134 if (pu->pu_ops.puffs_cache_write == NULL)
135 return 0;
136
137 pu->pu_ops.puffs_cache_write(pu, preq->preq_cookie,
138 pci->pcache_nruns, pci->pcache_runs);
139 return 0;
140 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_ERROR) {
141 struct puffs_error *perr = (void *)preq;
142
143 pu->pu_errnotify(pu, preq->preq_optype,
144 perr->perr_error, perr->perr_str, preq->preq_cookie);
145 return 0;
146 }
147
148 if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
149 puffsdump_req(preq);
150
151 #if 0
152 XXX: we can't trust to hide preq in pufbuf
153
154 struct puffs_executor *pex;
155 /*
156 * Check if we are already processing an operation from the same
157 * caller. If so, queue this operation until the previous one
158 * finishes. This prevents us from executing certain operations
159 * out-of-order (e.g. fsync and reclaim).
160 *
161 * Each preq will only remove its own pex from the tailq.
162 * See puffs_docc() for the details on other-end removal
163 * and dispatching.
164 */
165 pex = malloc(sizeof(struct puffs_executor));
166 pex->pex_pufbuf = pb;
167 PU_LOCK();
168 TAILQ_INSERT_TAIL(&pu->pu_exq, pex, pex_entries);
169 TAILQ_FOREACH(pex, &pu->pu_exq, pex_entries) {
170 struct puffs_req *pb_preq;
171
172 pb_preq = puffs__framebuf_getdataptr(pex->pex_pufbuf);
173 if (pb_preq->preq_pid == preq->preq_pid
174 && pb_preq->preq_lid == preq->preq_lid) {
175 if (pb_preq != preq) {
176 PU_UNLOCK();
177 return 0;
178 }
179 }
180 }
181 PU_UNLOCK();
182 #endif
183
184 return dopufbuf2(pu, pb);
185 }
186
187 enum {PUFFCALL_ANSWER, PUFFCALL_IGNORE, PUFFCALL_AGAIN};
188
189 void *
190 puffs_docc(void *arg)
191 {
192 struct puffs_cc *pcc = arg;
193 struct puffs_usermount *pu = pcc->pcc_pu;
194 struct puffs_req *preq;
195 struct puffs_cc *pcc_iter;
196
197 assert((pcc->pcc_flags & PCC_DONE) == 0);
198
199 if (pcc->pcc_flags & PCC_REALCC)
200 puffs_cc_continue(pcc);
201 else
202 puffs_calldispatcher(pcc);
203
204 if ((pcc->pcc_flags & PCC_DONE) == 0) {
205 assert(pcc->pcc_flags & PCC_REALCC);
206 return NULL;
207 }
208
209 preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
210 #if 0
211 XXX: see above, needs more thought
212
213 struct puffs_executor *pex, *pex_n;
214 int found;
215 /* check if we need to schedule FAFs which were stalled */
216 found = 0;
217 PU_LOCK();
218 for (pex = TAILQ_FIRST(&pu->pu_exq); pex; pex = pex_n) {
219 struct puffs_req *pb_preq;
220
221 pb_preq = puffs__framebuf_getdataptr(pex->pex_pufbuf);
222 pex_n = TAILQ_NEXT(pex, pex_entries);
223 if (pb_preq->preq_pid == preq->preq_pid
224 && pb_preq->preq_lid == preq->preq_lid) {
225 if (found == 0) {
226 /* this is us */
227 assert(pb_preq == preq);
228 TAILQ_REMOVE(&pu->pu_exq, pex, pex_entries);
229 free(pex);
230 found = 1;
231 } else {
232 /* down at the mardi gras */
233 PU_UNLOCK();
234 dopufbuf2(pu, pex->pex_pufbuf);
235 PU_LOCK();
236 break;
237 }
238 }
239 }
240 #endif
241
242 if (!PUFFSOP_WANTREPLY(preq->preq_opclass))
243 puffs_framebuf_destroy(pcc->pcc_pb);
244
245 /* can't do this above due to PCC_BORROWED */
246 while ((pcc_iter = LIST_FIRST(&pu->pu_ccnukelst)) != NULL) {
247 LIST_REMOVE(pcc_iter, pcc_rope);
248 puffs_cc_destroy(pcc_iter);
249 }
250 PU_UNLOCK();
251
252 return NULL;
253 }
254
255 /* library private, but linked from callcontext.c */
256
257 void
258 puffs_calldispatcher(struct puffs_cc *pcc)
259 {
260 struct puffs_usermount *pu = pcc->pcc_pu;
261 struct puffs_ops *pops = &pu->pu_ops;
262 struct puffs_req *preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
263 void *auxbuf = preq; /* help with typecasting */
264 void *opcookie = preq->preq_cookie;
265 int error, rv, buildpath;
266
267 assert(pcc->pcc_flags & (PCC_FAKECC | PCC_REALCC | PCC_THREADED));
268 assert(pcc == puffs_cc_getcc(pu)); /* remove me soon */
269
270 if (PUFFSOP_WANTREPLY(preq->preq_opclass))
271 rv = PUFFCALL_ANSWER;
272 else
273 rv = PUFFCALL_IGNORE;
274
275 buildpath = pu->pu_flags & PUFFS_FLAG_BUILDPATH;
276 preq->preq_setbacks = 0;
277
278 if (pu->pu_oppre)
279 pu->pu_oppre(pu);
280
281 if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) {
282 switch (preq->preq_optype) {
283 case PUFFS_VFS_UNMOUNT:
284 {
285 struct puffs_vfsmsg_unmount *auxt = auxbuf;
286
287 PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTING);
288 error = pops->puffs_fs_unmount(pu, auxt->pvfsr_flags);
289 if (!error)
290 PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTED);
291 else
292 PU_SETSTATE(pu, PUFFS_STATE_RUNNING);
293 break;
294 }
295
296 case PUFFS_VFS_STATVFS:
297 {
298 struct puffs_vfsmsg_statvfs *auxt = auxbuf;
299
300 error = pops->puffs_fs_statvfs(pu, &auxt->pvfsr_sb);
301 break;
302 }
303
304 case PUFFS_VFS_SYNC:
305 {
306 struct puffs_vfsmsg_sync *auxt = auxbuf;
307 PUFFS_MAKECRED(pcr, &auxt->pvfsr_cred);
308
309 error = pops->puffs_fs_sync(pu,
310 auxt->pvfsr_waitfor, pcr);
311 break;
312 }
313
314 case PUFFS_VFS_FHTOVP:
315 {
316 struct puffs_vfsmsg_fhtonode *auxt = auxbuf;
317 struct puffs_newinfo pni;
318
319 pni.pni_cookie = &auxt->pvfsr_fhcookie;
320 pni.pni_vtype = &auxt->pvfsr_vtype;
321 pni.pni_size = &auxt->pvfsr_size;
322 pni.pni_rdev = &auxt->pvfsr_rdev;
323
324 error = pops->puffs_fs_fhtonode(pu, auxt->pvfsr_data,
325 auxt->pvfsr_dsize, &pni);
326
327 break;
328 }
329
330 case PUFFS_VFS_VPTOFH:
331 {
332 struct puffs_vfsmsg_nodetofh *auxt = auxbuf;
333
334 error = pops->puffs_fs_nodetofh(pu,
335 auxt->pvfsr_fhcookie, auxt->pvfsr_data,
336 &auxt->pvfsr_dsize);
337
338 break;
339 }
340
341 case PUFFS_VFS_SUSPEND:
342 {
343 struct puffs_vfsmsg_suspend *auxt = auxbuf;
344
345 error = 0;
346 if (pops->puffs_fs_suspend == NULL)
347 break;
348
349 pops->puffs_fs_suspend(pu, auxt->pvfsr_status);
350 break;
351 }
352
353 default:
354 /*
355 * I guess the kernel sees this one coming
356 */
357 error = EINVAL;
358 break;
359 }
360
361 /* XXX: audit return values */
362 /* XXX: sync with kernel */
363 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) {
364 switch (preq->preq_optype) {
365 case PUFFS_VN_LOOKUP:
366 {
367 struct puffs_vnmsg_lookup *auxt = auxbuf;
368 struct puffs_newinfo pni;
369 struct puffs_cn pcn;
370
371 pcn.pcn_pkcnp = &auxt->pvnr_cn;
372 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
373 pni.pni_cookie = &auxt->pvnr_newnode;
374 pni.pni_vtype = &auxt->pvnr_vtype;
375 pni.pni_size = &auxt->pvnr_size;
376 pni.pni_rdev = &auxt->pvnr_rdev;
377
378 if (buildpath) {
379 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
380 if (error)
381 break;
382 }
383
384 /* lookup *must* be present */
385 error = pops->puffs_node_lookup(pu, opcookie,
386 &pni, &pcn);
387
388 if (buildpath) {
389 if (error) {
390 pu->pu_pathfree(pu, &pcn.pcn_po_full);
391 } else {
392 struct puffs_node *pn;
393
394 /*
395 * did we get a new node or a
396 * recycled node?
397 */
398 pn = PU_CMAP(pu, auxt->pvnr_newnode);
399 if (pn->pn_po.po_path == NULL)
400 pn->pn_po = pcn.pcn_po_full;
401 else
402 pu->pu_pathfree(pu,
403 &pcn.pcn_po_full);
404 }
405 }
406
407 break;
408 }
409
410 case PUFFS_VN_CREATE:
411 {
412 struct puffs_vnmsg_create *auxt = auxbuf;
413 struct puffs_newinfo pni;
414 struct puffs_cn pcn;
415
416 if (pops->puffs_node_create == NULL) {
417 error = 0;
418 break;
419 }
420
421 pcn.pcn_pkcnp = &auxt->pvnr_cn;
422 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
423
424 memset(&pni, 0, sizeof(pni));
425 pni.pni_cookie = &auxt->pvnr_newnode;
426
427 if (buildpath) {
428 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
429 if (error)
430 break;
431 }
432
433 error = pops->puffs_node_create(pu,
434 opcookie, &pni, &pcn, &auxt->pvnr_va);
435
436 if (buildpath) {
437 if (error) {
438 pu->pu_pathfree(pu, &pcn.pcn_po_full);
439 } else {
440 struct puffs_node *pn;
441
442 pn = PU_CMAP(pu, auxt->pvnr_newnode);
443 pn->pn_po = pcn.pcn_po_full;
444 }
445 }
446
447 break;
448 }
449
450 case PUFFS_VN_MKNOD:
451 {
452 struct puffs_vnmsg_mknod *auxt = auxbuf;
453 struct puffs_newinfo pni;
454 struct puffs_cn pcn;
455
456 if (pops->puffs_node_mknod == NULL) {
457 error = 0;
458 break;
459 }
460
461 pcn.pcn_pkcnp = &auxt->pvnr_cn;
462 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
463
464 memset(&pni, 0, sizeof(pni));
465 pni.pni_cookie = &auxt->pvnr_newnode;
466
467 if (buildpath) {
468 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
469 if (error)
470 break;
471 }
472
473 error = pops->puffs_node_mknod(pu,
474 opcookie, &pni, &pcn, &auxt->pvnr_va);
475
476 if (buildpath) {
477 if (error) {
478 pu->pu_pathfree(pu, &pcn.pcn_po_full);
479 } else {
480 struct puffs_node *pn;
481
482 pn = PU_CMAP(pu, auxt->pvnr_newnode);
483 pn->pn_po = pcn.pcn_po_full;
484 }
485 }
486
487 break;
488 }
489
490 case PUFFS_VN_OPEN:
491 {
492 struct puffs_vnmsg_open *auxt = auxbuf;
493 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
494
495 if (pops->puffs_node_open == NULL) {
496 error = 0;
497 break;
498 }
499
500 error = pops->puffs_node_open(pu,
501 opcookie, auxt->pvnr_mode, pcr);
502 break;
503 }
504
505 case PUFFS_VN_CLOSE:
506 {
507 struct puffs_vnmsg_close *auxt = auxbuf;
508 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
509
510 if (pops->puffs_node_close == NULL) {
511 error = 0;
512 break;
513 }
514
515 error = pops->puffs_node_close(pu,
516 opcookie, auxt->pvnr_fflag, pcr);
517 break;
518 }
519
520 case PUFFS_VN_ACCESS:
521 {
522 struct puffs_vnmsg_access *auxt = auxbuf;
523 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
524
525 if (pops->puffs_node_access == NULL) {
526 error = 0;
527 break;
528 }
529
530 error = pops->puffs_node_access(pu,
531 opcookie, auxt->pvnr_mode, pcr);
532 break;
533 }
534
535 case PUFFS_VN_GETATTR:
536 {
537 struct puffs_vnmsg_getattr *auxt = auxbuf;
538 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
539
540 if (pops->puffs_node_getattr == NULL) {
541 error = EOPNOTSUPP;
542 break;
543 }
544
545 error = pops->puffs_node_getattr(pu,
546 opcookie, &auxt->pvnr_va, pcr);
547 break;
548 }
549
550 case PUFFS_VN_SETATTR:
551 {
552 struct puffs_vnmsg_setattr *auxt = auxbuf;
553 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
554
555 if (pops->puffs_node_setattr == NULL) {
556 error = EOPNOTSUPP;
557 break;
558 }
559
560 error = pops->puffs_node_setattr(pu,
561 opcookie, &auxt->pvnr_va, pcr);
562 break;
563 }
564
565 case PUFFS_VN_MMAP:
566 {
567 struct puffs_vnmsg_mmap *auxt = auxbuf;
568 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
569
570 if (pops->puffs_node_mmap == NULL) {
571 error = 0;
572 break;
573 }
574
575 error = pops->puffs_node_mmap(pu,
576 opcookie, auxt->pvnr_prot, pcr);
577 break;
578 }
579
580 case PUFFS_VN_FSYNC:
581 {
582 struct puffs_vnmsg_fsync *auxt = auxbuf;
583 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
584
585 if (pops->puffs_node_fsync == NULL) {
586 error = 0;
587 break;
588 }
589
590 error = pops->puffs_node_fsync(pu, opcookie, pcr,
591 auxt->pvnr_flags, auxt->pvnr_offlo,
592 auxt->pvnr_offhi);
593 break;
594 }
595
596 case PUFFS_VN_SEEK:
597 {
598 struct puffs_vnmsg_seek *auxt = auxbuf;
599 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
600
601 if (pops->puffs_node_seek == NULL) {
602 error = 0;
603 break;
604 }
605
606 error = pops->puffs_node_seek(pu,
607 opcookie, auxt->pvnr_oldoff,
608 auxt->pvnr_newoff, pcr);
609 break;
610 }
611
612 case PUFFS_VN_REMOVE:
613 {
614 struct puffs_vnmsg_remove *auxt = auxbuf;
615 struct puffs_cn pcn;
616 if (pops->puffs_node_remove == 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_remove(pu,
625 opcookie, auxt->pvnr_cookie_targ, &pcn);
626 break;
627 }
628
629 case PUFFS_VN_LINK:
630 {
631 struct puffs_vnmsg_link *auxt = auxbuf;
632 struct puffs_cn pcn;
633 if (pops->puffs_node_link == 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_link(pu,
648 opcookie, auxt->pvnr_cookie_targ, &pcn);
649 if (buildpath)
650 pu->pu_pathfree(pu, &pcn.pcn_po_full);
651
652 break;
653 }
654
655 case PUFFS_VN_RENAME:
656 {
657 struct puffs_vnmsg_rename *auxt = auxbuf;
658 struct puffs_cn pcn_src, pcn_targ;
659 struct puffs_node *pn_src;
660
661 if (pops->puffs_node_rename == NULL) {
662 error = 0;
663 break;
664 }
665
666 pcn_src.pcn_pkcnp = &auxt->pvnr_cn_src;
667 PUFFS_KCREDTOCRED(pcn_src.pcn_cred,
668 &auxt->pvnr_cn_src_cred);
669
670 pcn_targ.pcn_pkcnp = &auxt->pvnr_cn_targ;
671 PUFFS_KCREDTOCRED(pcn_targ.pcn_cred,
672 &auxt->pvnr_cn_targ_cred);
673
674 if (buildpath) {
675 pn_src = auxt->pvnr_cookie_src;
676 pcn_src.pcn_po_full = pn_src->pn_po;
677
678 error = puffs_path_pcnbuild(pu, &pcn_targ,
679 auxt->pvnr_cookie_targdir);
680 if (error)
681 break;
682 }
683
684 error = pops->puffs_node_rename(pu,
685 opcookie, auxt->pvnr_cookie_src,
686 &pcn_src, auxt->pvnr_cookie_targdir,
687 auxt->pvnr_cookie_targ, &pcn_targ);
688
689 if (buildpath) {
690 if (error) {
691 pu->pu_pathfree(pu,
692 &pcn_targ.pcn_po_full);
693 } else {
694 struct puffs_pathinfo pi;
695 struct puffs_pathobj po_old;
696
697 /* handle this node */
698 po_old = pn_src->pn_po;
699 pn_src->pn_po = pcn_targ.pcn_po_full;
700
701 if (pn_src->pn_va.va_type != VDIR) {
702 pu->pu_pathfree(pu, &po_old);
703 break;
704 }
705
706 /* handle all child nodes for DIRs */
707 pi.pi_old = &pcn_src.pcn_po_full;
708 pi.pi_new = &pcn_targ.pcn_po_full;
709
710 PU_LOCK();
711 if (puffs_pn_nodewalk(pu,
712 puffs_path_prefixadj, &pi) != NULL)
713 error = ENOMEM;
714 PU_UNLOCK();
715 pu->pu_pathfree(pu, &po_old);
716 }
717 }
718 break;
719 }
720
721 case PUFFS_VN_MKDIR:
722 {
723 struct puffs_vnmsg_mkdir *auxt = auxbuf;
724 struct puffs_newinfo pni;
725 struct puffs_cn pcn;
726
727 if (pops->puffs_node_mkdir == NULL) {
728 error = 0;
729 break;
730 }
731
732 pcn.pcn_pkcnp = &auxt->pvnr_cn;
733 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
734
735 memset(&pni, 0, sizeof(pni));
736 pni.pni_cookie = &auxt->pvnr_newnode;
737
738 if (buildpath) {
739 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
740 if (error)
741 break;
742 }
743
744 error = pops->puffs_node_mkdir(pu,
745 opcookie, &pni, &pcn, &auxt->pvnr_va);
746
747 if (buildpath) {
748 if (error) {
749 pu->pu_pathfree(pu, &pcn.pcn_po_full);
750 } else {
751 struct puffs_node *pn;
752
753 pn = PU_CMAP(pu, auxt->pvnr_newnode);
754 pn->pn_po = pcn.pcn_po_full;
755 }
756 }
757
758 break;
759 }
760
761 case PUFFS_VN_RMDIR:
762 {
763 struct puffs_vnmsg_rmdir *auxt = auxbuf;
764 struct puffs_cn pcn;
765 if (pops->puffs_node_rmdir == NULL) {
766 error = 0;
767 break;
768 }
769
770 pcn.pcn_pkcnp = &auxt->pvnr_cn;
771 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
772
773 error = pops->puffs_node_rmdir(pu,
774 opcookie, auxt->pvnr_cookie_targ, &pcn);
775 break;
776 }
777
778 case PUFFS_VN_SYMLINK:
779 {
780 struct puffs_vnmsg_symlink *auxt = auxbuf;
781 struct puffs_newinfo pni;
782 struct puffs_cn pcn;
783
784 if (pops->puffs_node_symlink == NULL) {
785 error = 0;
786 break;
787 }
788
789 pcn.pcn_pkcnp = &auxt->pvnr_cn;
790 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
791
792 memset(&pni, 0, sizeof(pni));
793 pni.pni_cookie = &auxt->pvnr_newnode;
794
795 if (buildpath) {
796 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
797 if (error)
798 break;
799 }
800
801 error = pops->puffs_node_symlink(pu,
802 opcookie, &pni, &pcn,
803 &auxt->pvnr_va, auxt->pvnr_link);
804
805 if (buildpath) {
806 if (error) {
807 pu->pu_pathfree(pu, &pcn.pcn_po_full);
808 } else {
809 struct puffs_node *pn;
810
811 pn = PU_CMAP(pu, auxt->pvnr_newnode);
812 pn->pn_po = pcn.pcn_po_full;
813 }
814 }
815
816 break;
817 }
818
819 case PUFFS_VN_READDIR:
820 {
821 struct puffs_vnmsg_readdir *auxt = auxbuf;
822 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
823 struct dirent *dent;
824 off_t *cookies;
825 size_t res, origcookies;
826
827 if (pops->puffs_node_readdir == NULL) {
828 error = 0;
829 break;
830 }
831
832 if (auxt->pvnr_ncookies) {
833 /* LINTED: pvnr_data is __aligned() */
834 cookies = (off_t *)auxt->pvnr_data;
835 origcookies = auxt->pvnr_ncookies;
836 } else {
837 cookies = NULL;
838 origcookies = 0;
839 }
840 /* LINTED: dentoff is aligned in the kernel */
841 dent = (struct dirent *)
842 (auxt->pvnr_data + auxt->pvnr_dentoff);
843
844 res = auxt->pvnr_resid;
845 error = pops->puffs_node_readdir(pu,
846 opcookie, dent, &auxt->pvnr_offset,
847 &auxt->pvnr_resid, pcr, &auxt->pvnr_eofflag,
848 cookies, &auxt->pvnr_ncookies);
849
850 /* much easier to track non-working NFS */
851 assert(auxt->pvnr_ncookies <= origcookies);
852
853 /* need to move a bit more */
854 preq->preq_buflen = sizeof(struct puffs_vnmsg_readdir)
855 + auxt->pvnr_dentoff + (res - auxt->pvnr_resid);
856 break;
857 }
858
859 case PUFFS_VN_READLINK:
860 {
861 struct puffs_vnmsg_readlink *auxt = auxbuf;
862 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
863
864 if (pops->puffs_node_readlink == NULL) {
865 error = EOPNOTSUPP;
866 break;
867 }
868
869 /*LINTED*/
870 error = pops->puffs_node_readlink(pu, opcookie, pcr,
871 auxt->pvnr_link, &auxt->pvnr_linklen);
872 break;
873 }
874
875 case PUFFS_VN_RECLAIM:
876 {
877
878 if (pops->puffs_node_reclaim == NULL) {
879 error = 0;
880 break;
881 }
882
883 error = pops->puffs_node_reclaim(pu, opcookie);
884 break;
885 }
886
887 case PUFFS_VN_INACTIVE:
888 {
889
890 if (pops->puffs_node_inactive == NULL) {
891 error = EOPNOTSUPP;
892 break;
893 }
894
895 error = pops->puffs_node_inactive(pu, opcookie);
896 break;
897 }
898
899 case PUFFS_VN_PATHCONF:
900 {
901 struct puffs_vnmsg_pathconf *auxt = auxbuf;
902 if (pops->puffs_node_pathconf == NULL) {
903 error = 0;
904 break;
905 }
906
907 error = pops->puffs_node_pathconf(pu,
908 opcookie, auxt->pvnr_name,
909 &auxt->pvnr_retval);
910 break;
911 }
912
913 case PUFFS_VN_ADVLOCK:
914 {
915 struct puffs_vnmsg_advlock *auxt = auxbuf;
916 if (pops->puffs_node_advlock == NULL) {
917 error = 0;
918 break;
919 }
920
921 error = pops->puffs_node_advlock(pu,
922 opcookie, auxt->pvnr_id, auxt->pvnr_op,
923 &auxt->pvnr_fl, auxt->pvnr_flags);
924 break;
925 }
926
927 case PUFFS_VN_PRINT:
928 {
929 if (pops->puffs_node_print == NULL) {
930 error = 0;
931 break;
932 }
933
934 error = pops->puffs_node_print(pu,
935 opcookie);
936 break;
937 }
938
939 case PUFFS_VN_READ:
940 {
941 struct puffs_vnmsg_read *auxt = auxbuf;
942 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
943 size_t res;
944
945 if (pops->puffs_node_read == NULL) {
946 error = EIO;
947 break;
948 }
949
950 res = auxt->pvnr_resid;
951 error = pops->puffs_node_read(pu,
952 opcookie, auxt->pvnr_data,
953 auxt->pvnr_offset, &auxt->pvnr_resid,
954 pcr, auxt->pvnr_ioflag);
955
956 /* need to move a bit more */
957 preq->preq_buflen = sizeof(struct puffs_vnmsg_read)
958 + (res - auxt->pvnr_resid);
959 break;
960 }
961
962 case PUFFS_VN_WRITE:
963 {
964 struct puffs_vnmsg_write *auxt = auxbuf;
965 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
966
967 if (pops->puffs_node_write == NULL) {
968 error = EIO;
969 break;
970 }
971
972 error = pops->puffs_node_write(pu,
973 opcookie, auxt->pvnr_data,
974 auxt->pvnr_offset, &auxt->pvnr_resid,
975 pcr, auxt->pvnr_ioflag);
976
977 /* don't need to move data back to the kernel */
978 preq->preq_buflen = sizeof(struct puffs_vnmsg_write);
979 break;
980 }
981
982 case PUFFS_VN_POLL:
983 {
984 struct puffs_vnmsg_poll *auxt = auxbuf;
985
986 if (pops->puffs_node_poll == NULL) {
987 error = 0;
988
989 /* emulate genfs_poll() */
990 auxt->pvnr_events &= (POLLIN | POLLOUT
991 | POLLRDNORM | POLLWRNORM);
992
993 break;
994 }
995
996 error = pops->puffs_node_poll(pu,
997 opcookie, &auxt->pvnr_events);
998 break;
999 }
1000
1001 default:
1002 printf("inval op %d\n", preq->preq_optype);
1003 error = EINVAL;
1004 break;
1005 }
1006 } else {
1007 /*
1008 * this one also
1009 */
1010 error = EINVAL;
1011 }
1012
1013 preq->preq_rv = error;
1014 pcc->pcc_flags |= PCC_DONE;
1015
1016 if (pu->pu_oppost)
1017 pu->pu_oppost(pu);
1018
1019 /*
1020 * Note, we are calling this from here so that we can run it
1021 * off of the continuation stack. Otherwise puffs_goto() would
1022 * not work.
1023 */
1024 processresult(pu, rv);
1025 }
1026
1027 static void
1028 processresult(struct puffs_usermount *pu, int how)
1029 {
1030 struct puffs_cc *pcc = puffs_cc_getcc(pu);
1031 struct puffs_req *preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
1032 int pccflags = pcc->pcc_flags;
1033
1034 /* check if we need to store this reply */
1035 switch (how) {
1036 case PUFFCALL_ANSWER:
1037 if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
1038 puffsdump_rv(preq);
1039
1040 puffs_framev_enqueue_justsend(pu, pu->pu_fd,
1041 pcc->pcc_pb, 0, 0);
1042 /*FALLTHROUGH*/
1043
1044 case PUFFCALL_IGNORE:
1045 PU_LOCK();
1046 LIST_INSERT_HEAD(&pu->pu_ccnukelst, pcc, pcc_rope);
1047 PU_UNLOCK();
1048 break;
1049
1050 case PUFFCALL_AGAIN:
1051 if ((pcc->pcc_flags & PCC_REALCC) == 0)
1052 assert(pcc->pcc_flags & PCC_DONE);
1053 break;
1054
1055 default:
1056 assert(/*CONSTCOND*/0);
1057 }
1058
1059 /* who needs information when you're living on borrowed time? */
1060 if (pccflags & PCC_BORROWED) {
1061 assert((pccflags & PCC_THREADED) == 0);
1062 puffs_cc_yield(pcc); /* back to borrow source */
1063 }
1064 }
1065