dispatcher.c revision 1.26 1 /* $NetBSD: dispatcher.c,v 1.26 2007/12/08 19:57:03 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.26 2007/12/08 19:57:03 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 pni.pni_cookie = &auxt->pvnr_newnode;
366 pni.pni_vtype = &auxt->pvnr_vtype;
367 pni.pni_size = &auxt->pvnr_size;
368 pni.pni_rdev = &auxt->pvnr_rdev;
369
370 if (buildpath) {
371 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
372 if (error)
373 break;
374 }
375
376 /* lookup *must* be present */
377 error = pops->puffs_node_lookup(pu, opcookie,
378 &pni, &pcn);
379
380 if (buildpath) {
381 if (error) {
382 pu->pu_pathfree(pu, &pcn.pcn_po_full);
383 } else {
384 struct puffs_node *pn;
385
386 /*
387 * did we get a new node or a
388 * recycled node?
389 */
390 pn = PU_CMAP(pu, auxt->pvnr_newnode);
391 if (pn->pn_po.po_path == NULL)
392 pn->pn_po = pcn.pcn_po_full;
393 else
394 pu->pu_pathfree(pu,
395 &pcn.pcn_po_full);
396 }
397 }
398
399 break;
400 }
401
402 case PUFFS_VN_CREATE:
403 {
404 struct puffs_vnmsg_create *auxt = auxbuf;
405 struct puffs_newinfo pni;
406 struct puffs_cn pcn;
407
408 if (pops->puffs_node_create == NULL) {
409 error = 0;
410 break;
411 }
412
413 pcn.pcn_pkcnp = &auxt->pvnr_cn;
414 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
415
416 memset(&pni, 0, sizeof(pni));
417 pni.pni_cookie = &auxt->pvnr_newnode;
418
419 if (buildpath) {
420 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
421 if (error)
422 break;
423 }
424
425 error = pops->puffs_node_create(pu,
426 opcookie, &pni, &pcn, &auxt->pvnr_va);
427
428 if (buildpath) {
429 if (error) {
430 pu->pu_pathfree(pu, &pcn.pcn_po_full);
431 } else {
432 struct puffs_node *pn;
433
434 pn = PU_CMAP(pu, auxt->pvnr_newnode);
435 pn->pn_po = pcn.pcn_po_full;
436 }
437 }
438
439 break;
440 }
441
442 case PUFFS_VN_MKNOD:
443 {
444 struct puffs_vnmsg_mknod *auxt = auxbuf;
445 struct puffs_newinfo pni;
446 struct puffs_cn pcn;
447
448 if (pops->puffs_node_mknod == NULL) {
449 error = 0;
450 break;
451 }
452
453 pcn.pcn_pkcnp = &auxt->pvnr_cn;
454 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
455
456 memset(&pni, 0, sizeof(pni));
457 pni.pni_cookie = &auxt->pvnr_newnode;
458
459 if (buildpath) {
460 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
461 if (error)
462 break;
463 }
464
465 error = pops->puffs_node_mknod(pu,
466 opcookie, &pni, &pcn, &auxt->pvnr_va);
467
468 if (buildpath) {
469 if (error) {
470 pu->pu_pathfree(pu, &pcn.pcn_po_full);
471 } else {
472 struct puffs_node *pn;
473
474 pn = PU_CMAP(pu, auxt->pvnr_newnode);
475 pn->pn_po = pcn.pcn_po_full;
476 }
477 }
478
479 break;
480 }
481
482 case PUFFS_VN_OPEN:
483 {
484 struct puffs_vnmsg_open *auxt = auxbuf;
485 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
486
487 if (pops->puffs_node_open == NULL) {
488 error = 0;
489 break;
490 }
491
492 error = pops->puffs_node_open(pu,
493 opcookie, auxt->pvnr_mode, pcr);
494 break;
495 }
496
497 case PUFFS_VN_CLOSE:
498 {
499 struct puffs_vnmsg_close *auxt = auxbuf;
500 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
501
502 if (pops->puffs_node_close == NULL) {
503 error = 0;
504 break;
505 }
506
507 error = pops->puffs_node_close(pu,
508 opcookie, auxt->pvnr_fflag, pcr);
509 break;
510 }
511
512 case PUFFS_VN_ACCESS:
513 {
514 struct puffs_vnmsg_access *auxt = auxbuf;
515 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
516
517 if (pops->puffs_node_access == NULL) {
518 error = 0;
519 break;
520 }
521
522 error = pops->puffs_node_access(pu,
523 opcookie, auxt->pvnr_mode, pcr);
524 break;
525 }
526
527 case PUFFS_VN_GETATTR:
528 {
529 struct puffs_vnmsg_getattr *auxt = auxbuf;
530 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
531
532 if (pops->puffs_node_getattr == NULL) {
533 error = EOPNOTSUPP;
534 break;
535 }
536
537 error = pops->puffs_node_getattr(pu,
538 opcookie, &auxt->pvnr_va, pcr);
539 break;
540 }
541
542 case PUFFS_VN_SETATTR:
543 {
544 struct puffs_vnmsg_setattr *auxt = auxbuf;
545 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
546
547 if (pops->puffs_node_setattr == NULL) {
548 error = EOPNOTSUPP;
549 break;
550 }
551
552 error = pops->puffs_node_setattr(pu,
553 opcookie, &auxt->pvnr_va, pcr);
554 break;
555 }
556
557 case PUFFS_VN_MMAP:
558 {
559 struct puffs_vnmsg_mmap *auxt = auxbuf;
560 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
561
562 if (pops->puffs_node_mmap == NULL) {
563 error = 0;
564 break;
565 }
566
567 error = pops->puffs_node_mmap(pu,
568 opcookie, auxt->pvnr_prot, pcr);
569 break;
570 }
571
572 case PUFFS_VN_FSYNC:
573 {
574 struct puffs_vnmsg_fsync *auxt = auxbuf;
575 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
576
577 if (pops->puffs_node_fsync == NULL) {
578 error = 0;
579 break;
580 }
581
582 error = pops->puffs_node_fsync(pu, opcookie, pcr,
583 auxt->pvnr_flags, auxt->pvnr_offlo,
584 auxt->pvnr_offhi);
585 break;
586 }
587
588 case PUFFS_VN_SEEK:
589 {
590 struct puffs_vnmsg_seek *auxt = auxbuf;
591 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
592
593 if (pops->puffs_node_seek == NULL) {
594 error = 0;
595 break;
596 }
597
598 error = pops->puffs_node_seek(pu,
599 opcookie, auxt->pvnr_oldoff,
600 auxt->pvnr_newoff, pcr);
601 break;
602 }
603
604 case PUFFS_VN_REMOVE:
605 {
606 struct puffs_vnmsg_remove *auxt = auxbuf;
607 struct puffs_cn pcn;
608 if (pops->puffs_node_remove == NULL) {
609 error = 0;
610 break;
611 }
612
613 pcn.pcn_pkcnp = &auxt->pvnr_cn;
614 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
615
616 error = pops->puffs_node_remove(pu,
617 opcookie, auxt->pvnr_cookie_targ, &pcn);
618 break;
619 }
620
621 case PUFFS_VN_LINK:
622 {
623 struct puffs_vnmsg_link *auxt = auxbuf;
624 struct puffs_cn pcn;
625 if (pops->puffs_node_link == NULL) {
626 error = 0;
627 break;
628 }
629
630 pcn.pcn_pkcnp = &auxt->pvnr_cn;
631 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
632
633 if (buildpath) {
634 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
635 if (error)
636 break;
637 }
638
639 error = pops->puffs_node_link(pu,
640 opcookie, auxt->pvnr_cookie_targ, &pcn);
641 if (buildpath)
642 pu->pu_pathfree(pu, &pcn.pcn_po_full);
643
644 break;
645 }
646
647 case PUFFS_VN_RENAME:
648 {
649 struct puffs_vnmsg_rename *auxt = auxbuf;
650 struct puffs_cn pcn_src, pcn_targ;
651 struct puffs_node *pn_src;
652
653 if (pops->puffs_node_rename == NULL) {
654 error = 0;
655 break;
656 }
657
658 pcn_src.pcn_pkcnp = &auxt->pvnr_cn_src;
659 PUFFS_KCREDTOCRED(pcn_src.pcn_cred,
660 &auxt->pvnr_cn_src_cred);
661
662 pcn_targ.pcn_pkcnp = &auxt->pvnr_cn_targ;
663 PUFFS_KCREDTOCRED(pcn_targ.pcn_cred,
664 &auxt->pvnr_cn_targ_cred);
665
666 if (buildpath) {
667 pn_src = auxt->pvnr_cookie_src;
668 pcn_src.pcn_po_full = pn_src->pn_po;
669
670 error = puffs_path_pcnbuild(pu, &pcn_targ,
671 auxt->pvnr_cookie_targdir);
672 if (error)
673 break;
674 }
675
676 error = pops->puffs_node_rename(pu,
677 opcookie, auxt->pvnr_cookie_src,
678 &pcn_src, auxt->pvnr_cookie_targdir,
679 auxt->pvnr_cookie_targ, &pcn_targ);
680
681 if (buildpath) {
682 if (error) {
683 pu->pu_pathfree(pu,
684 &pcn_targ.pcn_po_full);
685 } else {
686 struct puffs_pathinfo pi;
687 struct puffs_pathobj po_old;
688
689 /* handle this node */
690 po_old = pn_src->pn_po;
691 pn_src->pn_po = pcn_targ.pcn_po_full;
692
693 if (pn_src->pn_va.va_type != VDIR) {
694 pu->pu_pathfree(pu, &po_old);
695 break;
696 }
697
698 /* handle all child nodes for DIRs */
699 pi.pi_old = &pcn_src.pcn_po_full;
700 pi.pi_new = &pcn_targ.pcn_po_full;
701
702 PU_LOCK();
703 if (puffs_pn_nodewalk(pu,
704 puffs_path_prefixadj, &pi) != NULL)
705 error = ENOMEM;
706 PU_UNLOCK();
707 pu->pu_pathfree(pu, &po_old);
708 }
709 }
710 break;
711 }
712
713 case PUFFS_VN_MKDIR:
714 {
715 struct puffs_vnmsg_mkdir *auxt = auxbuf;
716 struct puffs_newinfo pni;
717 struct puffs_cn pcn;
718
719 if (pops->puffs_node_mkdir == NULL) {
720 error = 0;
721 break;
722 }
723
724 pcn.pcn_pkcnp = &auxt->pvnr_cn;
725 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
726
727 memset(&pni, 0, sizeof(pni));
728 pni.pni_cookie = &auxt->pvnr_newnode;
729
730 if (buildpath) {
731 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
732 if (error)
733 break;
734 }
735
736 error = pops->puffs_node_mkdir(pu,
737 opcookie, &pni, &pcn, &auxt->pvnr_va);
738
739 if (buildpath) {
740 if (error) {
741 pu->pu_pathfree(pu, &pcn.pcn_po_full);
742 } else {
743 struct puffs_node *pn;
744
745 pn = PU_CMAP(pu, auxt->pvnr_newnode);
746 pn->pn_po = pcn.pcn_po_full;
747 }
748 }
749
750 break;
751 }
752
753 case PUFFS_VN_RMDIR:
754 {
755 struct puffs_vnmsg_rmdir *auxt = auxbuf;
756 struct puffs_cn pcn;
757 if (pops->puffs_node_rmdir == NULL) {
758 error = 0;
759 break;
760 }
761
762 pcn.pcn_pkcnp = &auxt->pvnr_cn;
763 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
764
765 error = pops->puffs_node_rmdir(pu,
766 opcookie, auxt->pvnr_cookie_targ, &pcn);
767 break;
768 }
769
770 case PUFFS_VN_SYMLINK:
771 {
772 struct puffs_vnmsg_symlink *auxt = auxbuf;
773 struct puffs_newinfo pni;
774 struct puffs_cn pcn;
775
776 if (pops->puffs_node_symlink == NULL) {
777 error = 0;
778 break;
779 }
780
781 pcn.pcn_pkcnp = &auxt->pvnr_cn;
782 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
783
784 memset(&pni, 0, sizeof(pni));
785 pni.pni_cookie = &auxt->pvnr_newnode;
786
787 if (buildpath) {
788 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
789 if (error)
790 break;
791 }
792
793 error = pops->puffs_node_symlink(pu,
794 opcookie, &pni, &pcn,
795 &auxt->pvnr_va, auxt->pvnr_link);
796
797 if (buildpath) {
798 if (error) {
799 pu->pu_pathfree(pu, &pcn.pcn_po_full);
800 } else {
801 struct puffs_node *pn;
802
803 pn = PU_CMAP(pu, auxt->pvnr_newnode);
804 pn->pn_po = pcn.pcn_po_full;
805 }
806 }
807
808 break;
809 }
810
811 case PUFFS_VN_READDIR:
812 {
813 struct puffs_vnmsg_readdir *auxt = auxbuf;
814 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
815 struct dirent *dent;
816 off_t *cookies;
817 size_t res, origcookies;
818
819 if (pops->puffs_node_readdir == NULL) {
820 error = 0;
821 break;
822 }
823
824 if (auxt->pvnr_ncookies) {
825 /* LINTED: pvnr_data is __aligned() */
826 cookies = (off_t *)auxt->pvnr_data;
827 origcookies = auxt->pvnr_ncookies;
828 } else {
829 cookies = NULL;
830 origcookies = 0;
831 }
832 /* LINTED: dentoff is aligned in the kernel */
833 dent = (struct dirent *)
834 (auxt->pvnr_data + auxt->pvnr_dentoff);
835
836 res = auxt->pvnr_resid;
837 error = pops->puffs_node_readdir(pu,
838 opcookie, dent, &auxt->pvnr_offset,
839 &auxt->pvnr_resid, pcr, &auxt->pvnr_eofflag,
840 cookies, &auxt->pvnr_ncookies);
841
842 /* much easier to track non-working NFS */
843 assert(auxt->pvnr_ncookies <= origcookies);
844
845 /* need to move a bit more */
846 preq->preq_buflen = sizeof(struct puffs_vnmsg_readdir)
847 + auxt->pvnr_dentoff + (res - auxt->pvnr_resid);
848 break;
849 }
850
851 case PUFFS_VN_READLINK:
852 {
853 struct puffs_vnmsg_readlink *auxt = auxbuf;
854 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
855
856 if (pops->puffs_node_readlink == NULL) {
857 error = EOPNOTSUPP;
858 break;
859 }
860
861 /*LINTED*/
862 error = pops->puffs_node_readlink(pu, opcookie, pcr,
863 auxt->pvnr_link, &auxt->pvnr_linklen);
864 break;
865 }
866
867 case PUFFS_VN_RECLAIM:
868 {
869
870 if (pops->puffs_node_reclaim == NULL) {
871 error = 0;
872 break;
873 }
874
875 error = pops->puffs_node_reclaim(pu, opcookie);
876 break;
877 }
878
879 case PUFFS_VN_INACTIVE:
880 {
881
882 if (pops->puffs_node_inactive == NULL) {
883 error = EOPNOTSUPP;
884 break;
885 }
886
887 error = pops->puffs_node_inactive(pu, opcookie);
888 break;
889 }
890
891 case PUFFS_VN_PATHCONF:
892 {
893 struct puffs_vnmsg_pathconf *auxt = auxbuf;
894 if (pops->puffs_node_pathconf == NULL) {
895 error = 0;
896 break;
897 }
898
899 error = pops->puffs_node_pathconf(pu,
900 opcookie, auxt->pvnr_name,
901 &auxt->pvnr_retval);
902 break;
903 }
904
905 case PUFFS_VN_ADVLOCK:
906 {
907 struct puffs_vnmsg_advlock *auxt = auxbuf;
908 if (pops->puffs_node_advlock == NULL) {
909 error = 0;
910 break;
911 }
912
913 error = pops->puffs_node_advlock(pu,
914 opcookie, auxt->pvnr_id, auxt->pvnr_op,
915 &auxt->pvnr_fl, auxt->pvnr_flags);
916 break;
917 }
918
919 case PUFFS_VN_PRINT:
920 {
921 if (pops->puffs_node_print == NULL) {
922 error = 0;
923 break;
924 }
925
926 error = pops->puffs_node_print(pu,
927 opcookie);
928 break;
929 }
930
931 case PUFFS_VN_READ:
932 {
933 struct puffs_vnmsg_read *auxt = auxbuf;
934 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
935 size_t res;
936
937 if (pops->puffs_node_read == NULL) {
938 error = EIO;
939 break;
940 }
941
942 res = auxt->pvnr_resid;
943 error = pops->puffs_node_read(pu,
944 opcookie, auxt->pvnr_data,
945 auxt->pvnr_offset, &auxt->pvnr_resid,
946 pcr, auxt->pvnr_ioflag);
947
948 /* need to move a bit more */
949 preq->preq_buflen = sizeof(struct puffs_vnmsg_read)
950 + (res - auxt->pvnr_resid);
951 break;
952 }
953
954 case PUFFS_VN_WRITE:
955 {
956 struct puffs_vnmsg_write *auxt = auxbuf;
957 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
958
959 if (pops->puffs_node_write == NULL) {
960 error = EIO;
961 break;
962 }
963
964 error = pops->puffs_node_write(pu,
965 opcookie, auxt->pvnr_data,
966 auxt->pvnr_offset, &auxt->pvnr_resid,
967 pcr, auxt->pvnr_ioflag);
968
969 /* don't need to move data back to the kernel */
970 preq->preq_buflen = sizeof(struct puffs_vnmsg_write);
971 break;
972 }
973
974 case PUFFS_VN_POLL:
975 {
976 struct puffs_vnmsg_poll *auxt = auxbuf;
977
978 if (pops->puffs_node_poll == NULL) {
979 error = 0;
980
981 /* emulate genfs_poll() */
982 auxt->pvnr_events &= (POLLIN | POLLOUT
983 | POLLRDNORM | POLLWRNORM);
984
985 break;
986 }
987
988 error = pops->puffs_node_poll(pu,
989 opcookie, &auxt->pvnr_events);
990 break;
991 }
992
993 default:
994 printf("inval op %d\n", preq->preq_optype);
995 error = EINVAL;
996 break;
997 }
998 } else {
999 /*
1000 * this one also
1001 */
1002 error = EINVAL;
1003 }
1004
1005 preq->preq_rv = error;
1006 pcc->pcc_flags |= PCC_DONE;
1007
1008 if (pu->pu_oppost)
1009 pu->pu_oppost(pu);
1010
1011 /*
1012 * Note, we are calling this from here so that we can run it
1013 * off of the continuation stack. Otherwise puffs_goto() would
1014 * not work.
1015 */
1016 processresult(pcc, rv);
1017 }
1018
1019 static void
1020 processresult(struct puffs_cc *pcc, int how)
1021 {
1022 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
1023 struct puffs_req *preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
1024 int pccflags = pcc->pcc_flags;
1025
1026 /* check if we need to store this reply */
1027 switch (how) {
1028 case PUFFCALL_ANSWER:
1029 if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
1030 puffsdump_rv(preq);
1031
1032 puffs_framev_enqueue_justsend(pu, pu->pu_fd,
1033 pcc->pcc_pb, 0, 0);
1034 /*FALLTHROUGH*/
1035
1036 case PUFFCALL_IGNORE:
1037 PU_LOCK();
1038 LIST_INSERT_HEAD(&pu->pu_ccnukelst, pcc, nlst_entries);
1039 PU_UNLOCK();
1040 break;
1041
1042 case PUFFCALL_AGAIN:
1043 if ((pcc->pcc_flags & PCC_REALCC) == 0)
1044 assert(pcc->pcc_flags & PCC_DONE);
1045 break;
1046
1047 default:
1048 assert(/*CONSTCOND*/0);
1049 }
1050
1051 /* who needs information when you're living on borrowed time? */
1052 if (pccflags & PCC_BORROWED) {
1053 assert((pccflags & PCC_THREADED) == 0);
1054 puffs_cc_yield(pcc); /* back to borrow source */
1055 }
1056 }
1057