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