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