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