dispatcher.c revision 1.45 1 /* $NetBSD: dispatcher.c,v 1.45 2013/11/06 19:50:10 christos Exp $ */
2
3 /*
4 * Copyright (c) 2006, 2007, 2008 Antti Kantee. All Rights Reserved.
5 *
6 * Development of this software was supported by the
7 * Ulla Tuominen Foundation, the Finnish Cultural Foundation and
8 * Research Foundation of Helsinki University of Technology.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
20 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 #if !defined(lint)
34 __RCSID("$NetBSD: dispatcher.c,v 1.45 2013/11/06 19:50:10 christos Exp $");
35 #endif /* !lint */
36
37 #include <sys/types.h>
38 #include <sys/poll.h>
39
40 #include <assert.h>
41 #include <errno.h>
42 #include <pthread.h>
43 #include <puffs.h>
44 #include <puffsdump.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <unistd.h>
48
49 #include "puffs_priv.h"
50
51 #define PUFFS_USE_FS_TTL(pu) (pu->pu_flags & PUFFS_KFLAG_CACHE_FS_TTL)
52
53 static void dispatch(struct puffs_cc *);
54
55 /* for our eyes only */
56 void
57 puffs__ml_dispatch(struct puffs_usermount *pu, struct puffs_framebuf *pb)
58 {
59 struct puffs_cc *pcc = puffs_cc_getcc(pu);
60 struct puffs_req *preq;
61
62 pcc->pcc_pb = pb;
63 pcc->pcc_flags |= PCC_MLCONT;
64 dispatch(pcc);
65
66 /* Put result to kernel sendqueue if necessary */
67 preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
68 if (PUFFSOP_WANTREPLY(preq->preq_opclass)) {
69 if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
70 puffsdump_rv(preq);
71
72 puffs_framev_enqueue_justsend(pu, pu->pu_fd,
73 pcc->pcc_pb, 0, 0);
74 } else {
75 puffs_framebuf_destroy(pcc->pcc_pb);
76 }
77
78 /* who needs information when you're living on borrowed time? */
79 if (pcc->pcc_flags & PCC_BORROWED) {
80 puffs_cc_yield(pcc); /* back to borrow source */
81 }
82 pcc->pcc_flags = 0;
83 }
84
85 /* public, but not really tested and only semi-supported */
86 int
87 puffs_dispatch_create(struct puffs_usermount *pu, struct puffs_framebuf *pb,
88 struct puffs_cc **pccp)
89 {
90 struct puffs_cc *pcc;
91
92 if (puffs__cc_create(pu, dispatch, &pcc) == -1)
93 return -1;
94
95 pcc->pcc_pb = pb;
96 *pccp = pcc;
97
98 return 0;
99 }
100
101 int
102 puffs_dispatch_exec(struct puffs_cc *pcc, struct puffs_framebuf **pbp)
103 {
104 int rv;
105
106 puffs_cc_continue(pcc);
107
108 if (pcc->pcc_flags & PCC_DONE) {
109 rv = 1;
110 *pbp = pcc->pcc_pb;
111 pcc->pcc_flags = 0;
112 puffs__cc_destroy(pcc, 0);
113 } else {
114 rv = 0;
115 }
116
117 return rv;
118 }
119
120 static void
121 dispatch(struct puffs_cc *pcc)
122 {
123 struct puffs_usermount *pu = pcc->pcc_pu;
124 struct puffs_ops *pops = &pu->pu_ops;
125 struct puffs_req *preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
126 void *auxbuf; /* help with typecasting */
127 puffs_cookie_t opcookie;
128 int error = 0, buildpath, pncookie;
129
130 /* XXX: smaller hammer, please */
131 if ((PUFFSOP_OPCLASS(preq->preq_opclass == PUFFSOP_VFS &&
132 preq->preq_optype == PUFFS_VFS_VPTOFH)) ||
133 (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN &&
134 (preq->preq_optype == PUFFS_VN_READDIR
135 || preq->preq_optype == PUFFS_VN_READ))) {
136 if (puffs_framebuf_reserve_space(pcc->pcc_pb,
137 PUFFS_MSG_MAXSIZE) == -1)
138 error = errno;
139 preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
140 }
141
142 auxbuf = preq;
143 opcookie = preq->preq_cookie;
144
145 assert((pcc->pcc_flags & PCC_DONE) == 0);
146
147 buildpath = pu->pu_flags & PUFFS_FLAG_BUILDPATH;
148 pncookie = pu->pu_flags & PUFFS_FLAG_PNCOOKIE;
149 assert(!buildpath || pncookie);
150
151 preq->preq_setbacks = 0;
152
153 if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
154 puffsdump_req(preq);
155
156 puffs__cc_setcaller(pcc, preq->preq_pid, preq->preq_lid);
157
158 /* pre-operation */
159 if (pu->pu_oppre)
160 pu->pu_oppre(pu);
161
162 if (error)
163 goto out;
164
165 /* Execute actual operation */
166 if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) {
167 switch (preq->preq_optype) {
168 case PUFFS_VFS_UNMOUNT:
169 {
170 struct puffs_vfsmsg_unmount *auxt = auxbuf;
171
172 PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTING);
173 error = pops->puffs_fs_unmount(pu, auxt->pvfsr_flags);
174 if (!error)
175 PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTED);
176 else
177 PU_SETSTATE(pu, PUFFS_STATE_RUNNING);
178 break;
179 }
180
181 case PUFFS_VFS_STATVFS:
182 {
183 struct puffs_vfsmsg_statvfs *auxt = auxbuf;
184
185 error = pops->puffs_fs_statvfs(pu, &auxt->pvfsr_sb);
186 break;
187 }
188
189 case PUFFS_VFS_SYNC:
190 {
191 struct puffs_vfsmsg_sync *auxt = auxbuf;
192 PUFFS_MAKECRED(pcr, &auxt->pvfsr_cred);
193
194 error = pops->puffs_fs_sync(pu,
195 auxt->pvfsr_waitfor, pcr);
196 break;
197 }
198
199 case PUFFS_VFS_FHTOVP:
200 {
201 struct puffs_vfsmsg_fhtonode *auxt = auxbuf;
202 struct puffs_newinfo pni;
203
204 pni.pni_cookie = &auxt->pvfsr_fhcookie;
205 pni.pni_vtype = &auxt->pvfsr_vtype;
206 pni.pni_size = &auxt->pvfsr_size;
207 pni.pni_rdev = &auxt->pvfsr_rdev;
208 pni.pni_va = NULL;
209 pni.pni_va_ttl = NULL;
210 pni.pni_cn_ttl = NULL;
211
212 error = pops->puffs_fs_fhtonode(pu, auxt->pvfsr_data,
213 auxt->pvfsr_dsize, &pni);
214
215 break;
216 }
217
218 case PUFFS_VFS_VPTOFH:
219 {
220 struct puffs_vfsmsg_nodetofh *auxt = auxbuf;
221
222 error = pops->puffs_fs_nodetofh(pu,
223 auxt->pvfsr_fhcookie, auxt->pvfsr_data,
224 &auxt->pvfsr_dsize);
225
226 break;
227 }
228
229 case PUFFS_VFS_EXTATTRCTL:
230 {
231 struct puffs_vfsmsg_extattrctl *auxt = auxbuf;
232 const char *attrname;
233 int flags;
234
235 if (pops->puffs_fs_extattrctl == NULL) {
236 error = EOPNOTSUPP;
237 break;
238 }
239
240 if (auxt->pvfsr_flags & PUFFS_EXTATTRCTL_HASATTRNAME)
241 attrname = auxt->pvfsr_attrname;
242 else
243 attrname = NULL;
244
245 flags = auxt->pvfsr_flags & PUFFS_EXTATTRCTL_HASNODE;
246 error = pops->puffs_fs_extattrctl(pu, auxt->pvfsr_cmd,
247 opcookie, flags,
248 auxt->pvfsr_attrnamespace, attrname);
249 break;
250 }
251
252 default:
253 /*
254 * I guess the kernel sees this one coming
255 */
256 error = EINVAL;
257 break;
258 }
259
260 /* XXX: audit return values */
261 /* XXX: sync with kernel */
262 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) {
263 switch (preq->preq_optype) {
264 case PUFFS_VN_LOOKUP:
265 {
266 struct puffs_vnmsg_lookup *auxt = auxbuf;
267 struct puffs_newinfo pni;
268 struct puffs_cn pcn;
269 struct puffs_node *pn = NULL;
270
271 pcn.pcn_pkcnp = &auxt->pvnr_cn;
272 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
273 pni.pni_cookie = &auxt->pvnr_newnode;
274 pni.pni_vtype = &auxt->pvnr_vtype;
275 pni.pni_size = &auxt->pvnr_size;
276 pni.pni_rdev = &auxt->pvnr_rdev;
277 pni.pni_va = &auxt->pvnr_va;
278 pni.pni_va_ttl = &auxt->pvnr_va_ttl;
279 pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
280
281 if (buildpath) {
282 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
283 if (error)
284 break;
285 }
286
287 /* lookup *must* be present */
288 error = pops->puffs_node_lookup(pu, opcookie,
289 &pni, &pcn);
290
291 if (buildpath) {
292 if (error) {
293 pu->pu_pathfree(pu, &pcn.pcn_po_full);
294 } else {
295 /*
296 * did we get a new node or a
297 * recycled node?
298 */
299 pn = PU_CMAP(pu, auxt->pvnr_newnode);
300 if (pn->pn_po.po_path == NULL)
301 pn->pn_po = pcn.pcn_po_full;
302 else
303 pu->pu_pathfree(pu,
304 &pcn.pcn_po_full);
305 }
306 }
307
308 if (pncookie && !error) {
309 if (pn == NULL)
310 pn = PU_CMAP(pu, auxt->pvnr_newnode);
311 pn->pn_nlookup++;
312 }
313 break;
314 }
315
316 case PUFFS_VN_CREATE:
317 {
318 struct puffs_vnmsg_create *auxt = auxbuf;
319 struct puffs_newinfo pni;
320 struct puffs_cn pcn;
321 struct puffs_node *pn = NULL;
322
323 if (pops->puffs_node_create == NULL) {
324 error = 0;
325 break;
326 }
327
328 pcn.pcn_pkcnp = &auxt->pvnr_cn;
329 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
330
331 memset(&pni, 0, sizeof(pni));
332 pni.pni_cookie = &auxt->pvnr_newnode;
333 pni.pni_va = &auxt->pvnr_va;
334 pni.pni_va_ttl = &auxt->pvnr_va_ttl;
335 pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
336
337 if (buildpath) {
338 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
339 if (error)
340 break;
341 }
342
343 error = pops->puffs_node_create(pu,
344 opcookie, &pni, &pcn, &auxt->pvnr_va);
345
346 if (buildpath) {
347 if (error) {
348 pu->pu_pathfree(pu, &pcn.pcn_po_full);
349 } else {
350 pn = PU_CMAP(pu, auxt->pvnr_newnode);
351 pn->pn_po = pcn.pcn_po_full;
352 }
353 }
354
355 if (pncookie && !error) {
356 if (pn == NULL)
357 pn = PU_CMAP(pu, auxt->pvnr_newnode);
358 pn->pn_nlookup++;
359 }
360 break;
361 }
362
363 case PUFFS_VN_MKNOD:
364 {
365 struct puffs_vnmsg_mknod *auxt = auxbuf;
366 struct puffs_newinfo pni;
367 struct puffs_cn pcn;
368 struct puffs_node *pn = NULL;
369
370 if (pops->puffs_node_mknod == NULL) {
371 error = 0;
372 break;
373 }
374
375 pcn.pcn_pkcnp = &auxt->pvnr_cn;
376 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
377
378 memset(&pni, 0, sizeof(pni));
379 pni.pni_cookie = &auxt->pvnr_newnode;
380 pni.pni_va = &auxt->pvnr_va;
381 pni.pni_va_ttl = &auxt->pvnr_va_ttl;
382 pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
383
384 if (buildpath) {
385 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
386 if (error)
387 break;
388 }
389
390 error = pops->puffs_node_mknod(pu,
391 opcookie, &pni, &pcn, &auxt->pvnr_va);
392
393 if (buildpath) {
394 if (error) {
395 pu->pu_pathfree(pu, &pcn.pcn_po_full);
396 } else {
397 pn = PU_CMAP(pu, auxt->pvnr_newnode);
398 pn->pn_po = pcn.pcn_po_full;
399 }
400 }
401
402 if (pncookie && !error) {
403 if (pn == NULL)
404 pn = PU_CMAP(pu, auxt->pvnr_newnode);
405 pn->pn_nlookup++;
406 }
407 break;
408 }
409
410 case PUFFS_VN_OPEN:
411 {
412 struct puffs_vnmsg_open *auxt = auxbuf;
413 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
414
415 if (pops->puffs_node_open == NULL) {
416 error = 0;
417 break;
418 }
419
420 error = pops->puffs_node_open(pu,
421 opcookie, auxt->pvnr_mode, pcr);
422 break;
423 }
424
425 case PUFFS_VN_CLOSE:
426 {
427 struct puffs_vnmsg_close *auxt = auxbuf;
428 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
429
430 if (pops->puffs_node_close == NULL) {
431 error = 0;
432 break;
433 }
434
435 error = pops->puffs_node_close(pu,
436 opcookie, auxt->pvnr_fflag, pcr);
437 break;
438 }
439
440 case PUFFS_VN_ACCESS:
441 {
442 struct puffs_vnmsg_access *auxt = auxbuf;
443 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
444
445 if (pops->puffs_node_access == NULL) {
446 error = 0;
447 break;
448 }
449
450 error = pops->puffs_node_access(pu,
451 opcookie, auxt->pvnr_mode, pcr);
452 break;
453 }
454
455 case PUFFS_VN_GETATTR:
456 {
457 struct puffs_vnmsg_getattr *auxt = auxbuf;
458 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
459
460 if (PUFFS_USE_FS_TTL(pu)) {
461 if (pops->puffs_node_getattr_ttl == NULL) {
462 error = EOPNOTSUPP;
463 break;
464 }
465
466 error = pops->puffs_node_getattr_ttl(pu,
467 opcookie, &auxt->pvnr_va, pcr,
468 &auxt->pvnr_va_ttl);
469 } else {
470 if (pops->puffs_node_getattr == NULL) {
471 error = EOPNOTSUPP;
472 break;
473 }
474
475 error = pops->puffs_node_getattr(pu,
476 opcookie, &auxt->pvnr_va, pcr);
477 }
478 break;
479 }
480
481 case PUFFS_VN_SETATTR:
482 {
483 struct puffs_vnmsg_setattr *auxt = auxbuf;
484 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
485
486 if (PUFFS_USE_FS_TTL(pu)) {
487 int xflag = 0;
488
489 if (pops->puffs_node_setattr_ttl == NULL) {
490 error = EOPNOTSUPP;
491 break;
492 }
493
494 if (!PUFFSOP_WANTREPLY(preq->preq_opclass))
495 xflag |= PUFFS_SETATTR_FAF;
496
497 error = pops->puffs_node_setattr_ttl(pu,
498 opcookie, &auxt->pvnr_va, pcr,
499 &auxt->pvnr_va_ttl, xflag);
500 } else {
501 if (pops->puffs_node_setattr == NULL) {
502 error = EOPNOTSUPP;
503 break;
504 }
505
506 error = pops->puffs_node_setattr(pu,
507 opcookie, &auxt->pvnr_va, pcr);
508 }
509 break;
510 }
511
512 case PUFFS_VN_MMAP:
513 {
514 struct puffs_vnmsg_mmap *auxt = auxbuf;
515 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
516
517 if (pops->puffs_node_mmap == NULL) {
518 error = 0;
519 break;
520 }
521
522 error = pops->puffs_node_mmap(pu,
523 opcookie, auxt->pvnr_prot, pcr);
524 break;
525 }
526
527 case PUFFS_VN_FSYNC:
528 {
529 struct puffs_vnmsg_fsync *auxt = auxbuf;
530 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
531
532 if (pops->puffs_node_fsync == NULL) {
533 error = 0;
534 break;
535 }
536
537 error = pops->puffs_node_fsync(pu, opcookie, pcr,
538 auxt->pvnr_flags, auxt->pvnr_offlo,
539 auxt->pvnr_offhi);
540 break;
541 }
542
543 case PUFFS_VN_SEEK:
544 {
545 struct puffs_vnmsg_seek *auxt = auxbuf;
546 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
547
548 if (pops->puffs_node_seek == NULL) {
549 error = 0;
550 break;
551 }
552
553 error = pops->puffs_node_seek(pu,
554 opcookie, auxt->pvnr_oldoff,
555 auxt->pvnr_newoff, pcr);
556 break;
557 }
558
559 case PUFFS_VN_REMOVE:
560 {
561 struct puffs_vnmsg_remove *auxt = auxbuf;
562 struct puffs_cn pcn;
563 if (pops->puffs_node_remove == NULL) {
564 error = 0;
565 break;
566 }
567
568 pcn.pcn_pkcnp = &auxt->pvnr_cn;
569 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
570
571 error = pops->puffs_node_remove(pu,
572 opcookie, auxt->pvnr_cookie_targ, &pcn);
573 break;
574 }
575
576 case PUFFS_VN_LINK:
577 {
578 struct puffs_vnmsg_link *auxt = auxbuf;
579 struct puffs_cn pcn;
580 if (pops->puffs_node_link == NULL) {
581 error = 0;
582 break;
583 }
584
585 pcn.pcn_pkcnp = &auxt->pvnr_cn;
586 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
587
588 if (buildpath) {
589 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
590 if (error)
591 break;
592 }
593
594 error = pops->puffs_node_link(pu,
595 opcookie, auxt->pvnr_cookie_targ, &pcn);
596 if (buildpath)
597 pu->pu_pathfree(pu, &pcn.pcn_po_full);
598
599 break;
600 }
601
602 case PUFFS_VN_RENAME:
603 {
604 struct puffs_vnmsg_rename *auxt = auxbuf;
605 struct puffs_cn pcn_src, pcn_targ;
606 struct puffs_node *pn_src;
607
608 if (pops->puffs_node_rename == NULL) {
609 error = 0;
610 break;
611 }
612
613 pcn_src.pcn_pkcnp = &auxt->pvnr_cn_src;
614 PUFFS_KCREDTOCRED(pcn_src.pcn_cred,
615 &auxt->pvnr_cn_src_cred);
616
617 pcn_targ.pcn_pkcnp = &auxt->pvnr_cn_targ;
618 PUFFS_KCREDTOCRED(pcn_targ.pcn_cred,
619 &auxt->pvnr_cn_targ_cred);
620
621 if (buildpath) {
622 pn_src = auxt->pvnr_cookie_src;
623 pcn_src.pcn_po_full = pn_src->pn_po;
624
625 error = puffs_path_pcnbuild(pu, &pcn_targ,
626 auxt->pvnr_cookie_targdir);
627 if (error)
628 break;
629 } else
630 pn_src = NULL; /* XXX: gcc */
631
632 error = pops->puffs_node_rename(pu,
633 opcookie, auxt->pvnr_cookie_src,
634 &pcn_src, auxt->pvnr_cookie_targdir,
635 auxt->pvnr_cookie_targ, &pcn_targ);
636
637 if (buildpath) {
638 if (error) {
639 pu->pu_pathfree(pu,
640 &pcn_targ.pcn_po_full);
641 } else {
642 struct puffs_pathinfo pi;
643 struct puffs_pathobj po_old;
644
645 /* handle this node */
646 po_old = pn_src->pn_po;
647 pn_src->pn_po = pcn_targ.pcn_po_full;
648
649 if (pn_src->pn_va.va_type != VDIR) {
650 pu->pu_pathfree(pu, &po_old);
651 break;
652 }
653
654 /* handle all child nodes for DIRs */
655 pi.pi_old = &pcn_src.pcn_po_full;
656 pi.pi_new = &pcn_targ.pcn_po_full;
657
658 PU_LOCK();
659 if (puffs_pn_nodewalk(pu,
660 puffs_path_prefixadj, &pi) != NULL)
661 error = ENOMEM;
662 PU_UNLOCK();
663 pu->pu_pathfree(pu, &po_old);
664 }
665 }
666 break;
667 }
668
669 case PUFFS_VN_MKDIR:
670 {
671 struct puffs_vnmsg_mkdir *auxt = auxbuf;
672 struct puffs_newinfo pni;
673 struct puffs_cn pcn;
674 struct puffs_node *pn = NULL;
675
676 if (pops->puffs_node_mkdir == NULL) {
677 error = 0;
678 break;
679 }
680
681 pcn.pcn_pkcnp = &auxt->pvnr_cn;
682 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
683
684 memset(&pni, 0, sizeof(pni));
685 pni.pni_cookie = &auxt->pvnr_newnode;
686 pni.pni_va = &auxt->pvnr_va;
687 pni.pni_va_ttl = &auxt->pvnr_va_ttl;
688 pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
689
690 if (buildpath) {
691 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
692 if (error)
693 break;
694 }
695
696 error = pops->puffs_node_mkdir(pu,
697 opcookie, &pni, &pcn, &auxt->pvnr_va);
698
699 if (buildpath) {
700 if (error) {
701 pu->pu_pathfree(pu, &pcn.pcn_po_full);
702 } else {
703 pn = PU_CMAP(pu, auxt->pvnr_newnode);
704 pn->pn_po = pcn.pcn_po_full;
705 }
706 }
707
708 if (pncookie && !error) {
709 if (pn == NULL)
710 pn = PU_CMAP(pu, auxt->pvnr_newnode);
711 pn->pn_nlookup++;
712 }
713 break;
714 }
715
716 case PUFFS_VN_RMDIR:
717 {
718 struct puffs_vnmsg_rmdir *auxt = auxbuf;
719 struct puffs_cn pcn;
720 if (pops->puffs_node_rmdir == NULL) {
721 error = 0;
722 break;
723 }
724
725 pcn.pcn_pkcnp = &auxt->pvnr_cn;
726 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
727
728 error = pops->puffs_node_rmdir(pu,
729 opcookie, auxt->pvnr_cookie_targ, &pcn);
730 break;
731 }
732
733 case PUFFS_VN_SYMLINK:
734 {
735 struct puffs_vnmsg_symlink *auxt = auxbuf;
736 struct puffs_newinfo pni;
737 struct puffs_cn pcn;
738 struct puffs_node *pn = NULL;
739
740 if (pops->puffs_node_symlink == NULL) {
741 error = 0;
742 break;
743 }
744
745 pcn.pcn_pkcnp = &auxt->pvnr_cn;
746 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
747
748 memset(&pni, 0, sizeof(pni));
749 pni.pni_cookie = &auxt->pvnr_newnode;
750 pni.pni_va = &auxt->pvnr_va;
751 pni.pni_va_ttl = &auxt->pvnr_va_ttl;
752 pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
753
754 if (buildpath) {
755 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
756 if (error)
757 break;
758 }
759
760 error = pops->puffs_node_symlink(pu,
761 opcookie, &pni, &pcn,
762 &auxt->pvnr_va, auxt->pvnr_link);
763
764 if (buildpath) {
765 if (error) {
766 pu->pu_pathfree(pu, &pcn.pcn_po_full);
767 } else {
768 pn = PU_CMAP(pu, auxt->pvnr_newnode);
769 pn->pn_po = pcn.pcn_po_full;
770 }
771 }
772
773 if (pncookie && !error) {
774 if (pn == NULL)
775 pn = PU_CMAP(pu, auxt->pvnr_newnode);
776 pn->pn_nlookup++;
777 }
778 break;
779 }
780
781 case PUFFS_VN_READDIR:
782 {
783 struct puffs_vnmsg_readdir *auxt = auxbuf;
784 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
785 struct dirent *dent;
786 off_t *cookies;
787 size_t res, origcookies;
788
789 if (pops->puffs_node_readdir == NULL) {
790 error = 0;
791 break;
792 }
793
794 if (auxt->pvnr_ncookies) {
795 /* LINTED: pvnr_data is __aligned() */
796 cookies = (off_t *)auxt->pvnr_data;
797 origcookies = auxt->pvnr_ncookies;
798 } else {
799 cookies = NULL;
800 origcookies = 0;
801 }
802 /* LINTED: dentoff is aligned in the kernel */
803 dent = (struct dirent *)
804 (auxt->pvnr_data + auxt->pvnr_dentoff);
805
806 res = auxt->pvnr_resid;
807 error = pops->puffs_node_readdir(pu,
808 opcookie, dent, &auxt->pvnr_offset,
809 &auxt->pvnr_resid, pcr, &auxt->pvnr_eofflag,
810 cookies, &auxt->pvnr_ncookies);
811
812 /* much easier to track non-working NFS */
813 assert(auxt->pvnr_ncookies <= origcookies);
814
815 /* need to move a bit more */
816 preq->preq_buflen = sizeof(struct puffs_vnmsg_readdir)
817 + auxt->pvnr_dentoff + (res - auxt->pvnr_resid);
818 break;
819 }
820
821 case PUFFS_VN_READLINK:
822 {
823 struct puffs_vnmsg_readlink *auxt = auxbuf;
824 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
825
826 if (pops->puffs_node_readlink == NULL) {
827 error = EOPNOTSUPP;
828 break;
829 }
830
831 /*LINTED*/
832 error = pops->puffs_node_readlink(pu, opcookie, pcr,
833 auxt->pvnr_link, &auxt->pvnr_linklen);
834 break;
835 }
836
837 case PUFFS_VN_RECLAIM:
838 {
839 struct puffs_vnmsg_reclaim *auxt = auxbuf;
840 struct puffs_node *pn;
841
842 if (pops->puffs_node_reclaim2 != NULL) {
843 error = pops->puffs_node_reclaim2(pu, opcookie,
844 auxt->pvnr_nlookup);
845 break;
846 }
847
848 if (pops->puffs_node_reclaim == NULL) {
849 error = 0;
850 break;
851 }
852
853 /*
854 * This fixes a race condition,
855 * where a node in reclaimed by kernel
856 * after a lookup request is sent,
857 * but before the reply, leaving the kernel
858 * with a invalid vnode/cookie reference.
859 */
860 if (pncookie) {
861 pn = PU_CMAP(pu, opcookie);
862 pn->pn_nlookup -= auxt->pvnr_nlookup;
863 if (pn->pn_nlookup >= 1) {
864 error = 0;
865 break;
866 }
867 }
868
869 error = pops->puffs_node_reclaim(pu, opcookie);
870 break;
871 }
872
873 case PUFFS_VN_INACTIVE:
874 {
875
876 if (pops->puffs_node_inactive == NULL) {
877 error = EOPNOTSUPP;
878 break;
879 }
880
881 error = pops->puffs_node_inactive(pu, opcookie);
882 break;
883 }
884
885 case PUFFS_VN_PATHCONF:
886 {
887 struct puffs_vnmsg_pathconf *auxt = auxbuf;
888 if (pops->puffs_node_pathconf == NULL) {
889 error = 0;
890 break;
891 }
892
893 error = pops->puffs_node_pathconf(pu,
894 opcookie, auxt->pvnr_name,
895 &auxt->pvnr_retval);
896 break;
897 }
898
899 case PUFFS_VN_ADVLOCK:
900 {
901 struct puffs_vnmsg_advlock *auxt = auxbuf;
902 if (pops->puffs_node_advlock == NULL) {
903 error = 0;
904 break;
905 }
906
907 error = pops->puffs_node_advlock(pu,
908 opcookie, auxt->pvnr_id, auxt->pvnr_op,
909 &auxt->pvnr_fl, auxt->pvnr_flags);
910 break;
911 }
912
913 case PUFFS_VN_PRINT:
914 {
915 if (pops->puffs_node_print == NULL) {
916 error = 0;
917 break;
918 }
919
920 error = pops->puffs_node_print(pu,
921 opcookie);
922 break;
923 }
924
925 case PUFFS_VN_ABORTOP:
926 {
927 struct puffs_vnmsg_abortop *auxt = auxbuf;
928 struct puffs_cn pcn;
929
930 if (pops->puffs_node_abortop == NULL) {
931 error = 0;
932 break;
933 }
934
935 pcn.pcn_pkcnp = &auxt->pvnr_cn;
936 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
937
938 error = pops->puffs_node_abortop(pu, opcookie, &pcn);
939
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_write2 != NULL) {
972 int xflag = 0;
973
974 if (!PUFFSOP_WANTREPLY(preq->preq_opclass))
975 xflag |= PUFFS_SETATTR_FAF;
976
977 error = pops->puffs_node_write2(pu,
978 opcookie, auxt->pvnr_data,
979 auxt->pvnr_offset, &auxt->pvnr_resid,
980 pcr, auxt->pvnr_ioflag, xflag);
981
982 } else if (pops->puffs_node_write != NULL) {
983 error = pops->puffs_node_write(pu,
984 opcookie, auxt->pvnr_data,
985 auxt->pvnr_offset, &auxt->pvnr_resid,
986 pcr, auxt->pvnr_ioflag);
987 } else {
988 error = EIO;
989 break;
990 }
991
992
993 /* don't need to move data back to the kernel */
994 preq->preq_buflen = sizeof(struct puffs_vnmsg_write);
995 break;
996 }
997
998 case PUFFS_VN_POLL:
999 {
1000 struct puffs_vnmsg_poll *auxt = auxbuf;
1001
1002 if (pops->puffs_node_poll == NULL) {
1003 error = 0;
1004
1005 /* emulate genfs_poll() */
1006 auxt->pvnr_events &= (POLLIN | POLLOUT
1007 | POLLRDNORM | POLLWRNORM);
1008
1009 break;
1010 }
1011
1012 error = pops->puffs_node_poll(pu,
1013 opcookie, &auxt->pvnr_events);
1014 break;
1015 }
1016
1017 case PUFFS_VN_GETEXTATTR:
1018 {
1019 struct puffs_vnmsg_getextattr *auxt = auxbuf;
1020 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
1021 size_t res, *resp, *sizep;
1022 uint8_t *data;
1023
1024 if (pops->puffs_node_getextattr == NULL) {
1025 error = EOPNOTSUPP;
1026 break;
1027 }
1028
1029 if (auxt->pvnr_datasize)
1030 sizep = &auxt->pvnr_datasize;
1031 else
1032 sizep = NULL;
1033
1034 res = auxt->pvnr_resid;
1035 if (res > 0) {
1036 data = auxt->pvnr_data;
1037 resp = &auxt->pvnr_resid;
1038 } else {
1039 data = NULL;
1040 resp = NULL;
1041 }
1042
1043 error = pops->puffs_node_getextattr(pu,
1044 opcookie, auxt->pvnr_attrnamespace,
1045 auxt->pvnr_attrname, sizep, data, resp, pcr);
1046
1047 /* need to move a bit more? */
1048 preq->preq_buflen =
1049 sizeof(struct puffs_vnmsg_getextattr)
1050 + (res - auxt->pvnr_resid);
1051 break;
1052 }
1053
1054 case PUFFS_VN_SETEXTATTR:
1055 {
1056 struct puffs_vnmsg_setextattr *auxt = auxbuf;
1057 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
1058 size_t *resp;
1059 uint8_t *data;
1060
1061 if (pops->puffs_node_setextattr == NULL) {
1062 error = EOPNOTSUPP;
1063 break;
1064 }
1065
1066 if (auxt->pvnr_resid > 0) {
1067 data = auxt->pvnr_data;
1068 resp = &auxt->pvnr_resid;
1069 } else {
1070 data = NULL;
1071 resp = NULL;
1072 }
1073
1074 error = pops->puffs_node_setextattr(pu,
1075 opcookie, auxt->pvnr_attrnamespace,
1076 auxt->pvnr_attrname, data, resp, pcr);
1077 break;
1078 }
1079
1080 case PUFFS_VN_LISTEXTATTR:
1081 {
1082 struct puffs_vnmsg_listextattr *auxt = auxbuf;
1083 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
1084 size_t res, *resp, *sizep;
1085 int flag;
1086 uint8_t *data;
1087
1088 if (pops->puffs_node_listextattr == NULL) {
1089 error = EOPNOTSUPP;
1090 break;
1091 }
1092
1093 if (auxt->pvnr_datasize)
1094 sizep = &auxt->pvnr_datasize;
1095 else
1096 sizep = NULL;
1097
1098 res = auxt->pvnr_resid;
1099 if (res > 0) {
1100 data = auxt->pvnr_data;
1101 resp = &auxt->pvnr_resid;
1102 } else {
1103 data = NULL;
1104 resp = NULL;
1105 }
1106
1107 res = auxt->pvnr_resid;
1108 flag = auxt->pvnr_flag;
1109 error = pops->puffs_node_listextattr(pu,
1110 opcookie, auxt->pvnr_attrnamespace,
1111 sizep, data, resp, flag, pcr);
1112
1113 /* need to move a bit more? */
1114 preq->preq_buflen =
1115 sizeof(struct puffs_vnmsg_listextattr)
1116 + (res - auxt->pvnr_resid);
1117 break;
1118 }
1119
1120 case PUFFS_VN_DELETEEXTATTR:
1121 {
1122 struct puffs_vnmsg_deleteextattr *auxt = auxbuf;
1123 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
1124
1125 if (pops->puffs_node_deleteextattr == NULL) {
1126 error = EOPNOTSUPP;
1127 break;
1128 }
1129
1130 error = pops->puffs_node_deleteextattr(pu,
1131 opcookie, auxt->pvnr_attrnamespace,
1132 auxt->pvnr_attrname, pcr);
1133 break;
1134 }
1135
1136 default:
1137 printf("inval op %d\n", preq->preq_optype);
1138 error = EINVAL;
1139 break;
1140 }
1141
1142 #if 0
1143 /* not issued by kernel currently */
1144 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_CACHE) {
1145 struct puffs_cacheinfo *pci = (void *)preq;
1146
1147 if (pu->pu_ops.puffs_cache_write) {
1148 pu->pu_ops.puffs_cache_write(pu, preq->preq_cookie,
1149 pci->pcache_nruns, pci->pcache_runs);
1150 }
1151 error = 0;
1152 #endif
1153
1154 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_ERROR) {
1155 struct puffs_error *perr = (void *)preq;
1156
1157 pu->pu_errnotify(pu, preq->preq_optype,
1158 perr->perr_error, perr->perr_str, preq->preq_cookie);
1159 error = 0;
1160 } else {
1161 /*
1162 * I guess the kernel sees this one coming also
1163 */
1164 error = EINVAL;
1165 }
1166
1167 out:
1168 preq->preq_rv = error;
1169
1170 if (pu->pu_oppost)
1171 pu->pu_oppost(pu);
1172
1173 pcc->pcc_flags |= PCC_DONE;
1174 }
1175