dispatcher.c revision 1.44 1 /* $NetBSD: dispatcher.c,v 1.44 2012/08/16 09:25:43 manu 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.44 2012/08/16 09:25:43 manu 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 }
630
631 error = pops->puffs_node_rename(pu,
632 opcookie, auxt->pvnr_cookie_src,
633 &pcn_src, auxt->pvnr_cookie_targdir,
634 auxt->pvnr_cookie_targ, &pcn_targ);
635
636 if (buildpath) {
637 if (error) {
638 pu->pu_pathfree(pu,
639 &pcn_targ.pcn_po_full);
640 } else {
641 struct puffs_pathinfo pi;
642 struct puffs_pathobj po_old;
643
644 /* handle this node */
645 po_old = pn_src->pn_po;
646 pn_src->pn_po = pcn_targ.pcn_po_full;
647
648 if (pn_src->pn_va.va_type != VDIR) {
649 pu->pu_pathfree(pu, &po_old);
650 break;
651 }
652
653 /* handle all child nodes for DIRs */
654 pi.pi_old = &pcn_src.pcn_po_full;
655 pi.pi_new = &pcn_targ.pcn_po_full;
656
657 PU_LOCK();
658 if (puffs_pn_nodewalk(pu,
659 puffs_path_prefixadj, &pi) != NULL)
660 error = ENOMEM;
661 PU_UNLOCK();
662 pu->pu_pathfree(pu, &po_old);
663 }
664 }
665 break;
666 }
667
668 case PUFFS_VN_MKDIR:
669 {
670 struct puffs_vnmsg_mkdir *auxt = auxbuf;
671 struct puffs_newinfo pni;
672 struct puffs_cn pcn;
673 struct puffs_node *pn = NULL;
674
675 if (pops->puffs_node_mkdir == NULL) {
676 error = 0;
677 break;
678 }
679
680 pcn.pcn_pkcnp = &auxt->pvnr_cn;
681 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
682
683 memset(&pni, 0, sizeof(pni));
684 pni.pni_cookie = &auxt->pvnr_newnode;
685 pni.pni_va = &auxt->pvnr_va;
686 pni.pni_va_ttl = &auxt->pvnr_va_ttl;
687 pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
688
689 if (buildpath) {
690 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
691 if (error)
692 break;
693 }
694
695 error = pops->puffs_node_mkdir(pu,
696 opcookie, &pni, &pcn, &auxt->pvnr_va);
697
698 if (buildpath) {
699 if (error) {
700 pu->pu_pathfree(pu, &pcn.pcn_po_full);
701 } else {
702 pn = PU_CMAP(pu, auxt->pvnr_newnode);
703 pn->pn_po = pcn.pcn_po_full;
704 }
705 }
706
707 if (pncookie && !error) {
708 if (pn == NULL)
709 pn = PU_CMAP(pu, auxt->pvnr_newnode);
710 pn->pn_nlookup++;
711 }
712 break;
713 }
714
715 case PUFFS_VN_RMDIR:
716 {
717 struct puffs_vnmsg_rmdir *auxt = auxbuf;
718 struct puffs_cn pcn;
719 if (pops->puffs_node_rmdir == 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 error = pops->puffs_node_rmdir(pu,
728 opcookie, auxt->pvnr_cookie_targ, &pcn);
729 break;
730 }
731
732 case PUFFS_VN_SYMLINK:
733 {
734 struct puffs_vnmsg_symlink *auxt = auxbuf;
735 struct puffs_newinfo pni;
736 struct puffs_cn pcn;
737 struct puffs_node *pn = NULL;
738
739 if (pops->puffs_node_symlink == NULL) {
740 error = 0;
741 break;
742 }
743
744 pcn.pcn_pkcnp = &auxt->pvnr_cn;
745 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
746
747 memset(&pni, 0, sizeof(pni));
748 pni.pni_cookie = &auxt->pvnr_newnode;
749 pni.pni_va = &auxt->pvnr_va;
750 pni.pni_va_ttl = &auxt->pvnr_va_ttl;
751 pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
752
753 if (buildpath) {
754 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
755 if (error)
756 break;
757 }
758
759 error = pops->puffs_node_symlink(pu,
760 opcookie, &pni, &pcn,
761 &auxt->pvnr_va, auxt->pvnr_link);
762
763 if (buildpath) {
764 if (error) {
765 pu->pu_pathfree(pu, &pcn.pcn_po_full);
766 } else {
767 pn = PU_CMAP(pu, auxt->pvnr_newnode);
768 pn->pn_po = pcn.pcn_po_full;
769 }
770 }
771
772 if (pncookie && !error) {
773 if (pn == NULL)
774 pn = PU_CMAP(pu, auxt->pvnr_newnode);
775 pn->pn_nlookup++;
776 }
777 break;
778 }
779
780 case PUFFS_VN_READDIR:
781 {
782 struct puffs_vnmsg_readdir *auxt = auxbuf;
783 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
784 struct dirent *dent;
785 off_t *cookies;
786 size_t res, origcookies;
787
788 if (pops->puffs_node_readdir == NULL) {
789 error = 0;
790 break;
791 }
792
793 if (auxt->pvnr_ncookies) {
794 /* LINTED: pvnr_data is __aligned() */
795 cookies = (off_t *)auxt->pvnr_data;
796 origcookies = auxt->pvnr_ncookies;
797 } else {
798 cookies = NULL;
799 origcookies = 0;
800 }
801 /* LINTED: dentoff is aligned in the kernel */
802 dent = (struct dirent *)
803 (auxt->pvnr_data + auxt->pvnr_dentoff);
804
805 res = auxt->pvnr_resid;
806 error = pops->puffs_node_readdir(pu,
807 opcookie, dent, &auxt->pvnr_offset,
808 &auxt->pvnr_resid, pcr, &auxt->pvnr_eofflag,
809 cookies, &auxt->pvnr_ncookies);
810
811 /* much easier to track non-working NFS */
812 assert(auxt->pvnr_ncookies <= origcookies);
813
814 /* need to move a bit more */
815 preq->preq_buflen = sizeof(struct puffs_vnmsg_readdir)
816 + auxt->pvnr_dentoff + (res - auxt->pvnr_resid);
817 break;
818 }
819
820 case PUFFS_VN_READLINK:
821 {
822 struct puffs_vnmsg_readlink *auxt = auxbuf;
823 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
824
825 if (pops->puffs_node_readlink == NULL) {
826 error = EOPNOTSUPP;
827 break;
828 }
829
830 /*LINTED*/
831 error = pops->puffs_node_readlink(pu, opcookie, pcr,
832 auxt->pvnr_link, &auxt->pvnr_linklen);
833 break;
834 }
835
836 case PUFFS_VN_RECLAIM:
837 {
838 struct puffs_vnmsg_reclaim *auxt = auxbuf;
839 struct puffs_node *pn;
840
841 if (pops->puffs_node_reclaim2 != NULL) {
842 error = pops->puffs_node_reclaim2(pu, opcookie,
843 auxt->pvnr_nlookup);
844 break;
845 }
846
847 if (pops->puffs_node_reclaim == NULL) {
848 error = 0;
849 break;
850 }
851
852 /*
853 * This fixes a race condition,
854 * where a node in reclaimed by kernel
855 * after a lookup request is sent,
856 * but before the reply, leaving the kernel
857 * with a invalid vnode/cookie reference.
858 */
859 if (pncookie) {
860 pn = PU_CMAP(pu, opcookie);
861 pn->pn_nlookup -= auxt->pvnr_nlookup;
862 if (pn->pn_nlookup >= 1) {
863 error = 0;
864 break;
865 }
866 }
867
868 error = pops->puffs_node_reclaim(pu, opcookie);
869 break;
870 }
871
872 case PUFFS_VN_INACTIVE:
873 {
874
875 if (pops->puffs_node_inactive == NULL) {
876 error = EOPNOTSUPP;
877 break;
878 }
879
880 error = pops->puffs_node_inactive(pu, opcookie);
881 break;
882 }
883
884 case PUFFS_VN_PATHCONF:
885 {
886 struct puffs_vnmsg_pathconf *auxt = auxbuf;
887 if (pops->puffs_node_pathconf == NULL) {
888 error = 0;
889 break;
890 }
891
892 error = pops->puffs_node_pathconf(pu,
893 opcookie, auxt->pvnr_name,
894 &auxt->pvnr_retval);
895 break;
896 }
897
898 case PUFFS_VN_ADVLOCK:
899 {
900 struct puffs_vnmsg_advlock *auxt = auxbuf;
901 if (pops->puffs_node_advlock == NULL) {
902 error = 0;
903 break;
904 }
905
906 error = pops->puffs_node_advlock(pu,
907 opcookie, auxt->pvnr_id, auxt->pvnr_op,
908 &auxt->pvnr_fl, auxt->pvnr_flags);
909 break;
910 }
911
912 case PUFFS_VN_PRINT:
913 {
914 if (pops->puffs_node_print == NULL) {
915 error = 0;
916 break;
917 }
918
919 error = pops->puffs_node_print(pu,
920 opcookie);
921 break;
922 }
923
924 case PUFFS_VN_ABORTOP:
925 {
926 struct puffs_vnmsg_abortop *auxt = auxbuf;
927 struct puffs_cn pcn;
928
929 if (pops->puffs_node_abortop == NULL) {
930 error = 0;
931 break;
932 }
933
934 pcn.pcn_pkcnp = &auxt->pvnr_cn;
935 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
936
937 error = pops->puffs_node_abortop(pu, opcookie, &pcn);
938
939 break;
940 }
941
942 case PUFFS_VN_READ:
943 {
944 struct puffs_vnmsg_read *auxt = auxbuf;
945 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
946 size_t res;
947
948 if (pops->puffs_node_read == NULL) {
949 error = EIO;
950 break;
951 }
952
953 res = auxt->pvnr_resid;
954 error = pops->puffs_node_read(pu,
955 opcookie, auxt->pvnr_data,
956 auxt->pvnr_offset, &auxt->pvnr_resid,
957 pcr, auxt->pvnr_ioflag);
958
959 /* need to move a bit more */
960 preq->preq_buflen = sizeof(struct puffs_vnmsg_read)
961 + (res - auxt->pvnr_resid);
962 break;
963 }
964
965 case PUFFS_VN_WRITE:
966 {
967 struct puffs_vnmsg_write *auxt = auxbuf;
968 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
969
970 if (pops->puffs_node_write2 != NULL) {
971 int xflag = 0;
972
973 if (!PUFFSOP_WANTREPLY(preq->preq_opclass))
974 xflag |= PUFFS_SETATTR_FAF;
975
976 error = pops->puffs_node_write2(pu,
977 opcookie, auxt->pvnr_data,
978 auxt->pvnr_offset, &auxt->pvnr_resid,
979 pcr, auxt->pvnr_ioflag, xflag);
980
981 } else if (pops->puffs_node_write != NULL) {
982 error = pops->puffs_node_write(pu,
983 opcookie, auxt->pvnr_data,
984 auxt->pvnr_offset, &auxt->pvnr_resid,
985 pcr, auxt->pvnr_ioflag);
986 } else {
987 error = EIO;
988 break;
989 }
990
991
992 /* don't need to move data back to the kernel */
993 preq->preq_buflen = sizeof(struct puffs_vnmsg_write);
994 break;
995 }
996
997 case PUFFS_VN_POLL:
998 {
999 struct puffs_vnmsg_poll *auxt = auxbuf;
1000
1001 if (pops->puffs_node_poll == NULL) {
1002 error = 0;
1003
1004 /* emulate genfs_poll() */
1005 auxt->pvnr_events &= (POLLIN | POLLOUT
1006 | POLLRDNORM | POLLWRNORM);
1007
1008 break;
1009 }
1010
1011 error = pops->puffs_node_poll(pu,
1012 opcookie, &auxt->pvnr_events);
1013 break;
1014 }
1015
1016 case PUFFS_VN_GETEXTATTR:
1017 {
1018 struct puffs_vnmsg_getextattr *auxt = auxbuf;
1019 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
1020 size_t res, *resp, *sizep;
1021 uint8_t *data;
1022
1023 if (pops->puffs_node_getextattr == NULL) {
1024 error = EOPNOTSUPP;
1025 break;
1026 }
1027
1028 if (auxt->pvnr_datasize)
1029 sizep = &auxt->pvnr_datasize;
1030 else
1031 sizep = NULL;
1032
1033 res = auxt->pvnr_resid;
1034 if (res > 0) {
1035 data = auxt->pvnr_data;
1036 resp = &auxt->pvnr_resid;
1037 } else {
1038 data = NULL;
1039 resp = NULL;
1040 }
1041
1042 error = pops->puffs_node_getextattr(pu,
1043 opcookie, auxt->pvnr_attrnamespace,
1044 auxt->pvnr_attrname, sizep, data, resp, pcr);
1045
1046 /* need to move a bit more? */
1047 preq->preq_buflen =
1048 sizeof(struct puffs_vnmsg_getextattr)
1049 + (res - auxt->pvnr_resid);
1050 break;
1051 }
1052
1053 case PUFFS_VN_SETEXTATTR:
1054 {
1055 struct puffs_vnmsg_setextattr *auxt = auxbuf;
1056 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
1057 size_t *resp;
1058 uint8_t *data;
1059
1060 if (pops->puffs_node_setextattr == NULL) {
1061 error = EOPNOTSUPP;
1062 break;
1063 }
1064
1065 if (auxt->pvnr_resid > 0) {
1066 data = auxt->pvnr_data;
1067 resp = &auxt->pvnr_resid;
1068 } else {
1069 data = NULL;
1070 resp = NULL;
1071 }
1072
1073 error = pops->puffs_node_setextattr(pu,
1074 opcookie, auxt->pvnr_attrnamespace,
1075 auxt->pvnr_attrname, data, resp, pcr);
1076 break;
1077 }
1078
1079 case PUFFS_VN_LISTEXTATTR:
1080 {
1081 struct puffs_vnmsg_listextattr *auxt = auxbuf;
1082 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
1083 size_t res, *resp, *sizep;
1084 int flag;
1085 uint8_t *data;
1086
1087 if (pops->puffs_node_listextattr == NULL) {
1088 error = EOPNOTSUPP;
1089 break;
1090 }
1091
1092 if (auxt->pvnr_datasize)
1093 sizep = &auxt->pvnr_datasize;
1094 else
1095 sizep = NULL;
1096
1097 res = auxt->pvnr_resid;
1098 if (res > 0) {
1099 data = auxt->pvnr_data;
1100 resp = &auxt->pvnr_resid;
1101 } else {
1102 data = NULL;
1103 resp = NULL;
1104 }
1105
1106 res = auxt->pvnr_resid;
1107 flag = auxt->pvnr_flag;
1108 error = pops->puffs_node_listextattr(pu,
1109 opcookie, auxt->pvnr_attrnamespace,
1110 sizep, data, resp, flag, pcr);
1111
1112 /* need to move a bit more? */
1113 preq->preq_buflen =
1114 sizeof(struct puffs_vnmsg_listextattr)
1115 + (res - auxt->pvnr_resid);
1116 break;
1117 }
1118
1119 case PUFFS_VN_DELETEEXTATTR:
1120 {
1121 struct puffs_vnmsg_deleteextattr *auxt = auxbuf;
1122 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
1123
1124 if (pops->puffs_node_deleteextattr == NULL) {
1125 error = EOPNOTSUPP;
1126 break;
1127 }
1128
1129 error = pops->puffs_node_deleteextattr(pu,
1130 opcookie, auxt->pvnr_attrnamespace,
1131 auxt->pvnr_attrname, pcr);
1132 break;
1133 }
1134
1135 default:
1136 printf("inval op %d\n", preq->preq_optype);
1137 error = EINVAL;
1138 break;
1139 }
1140
1141 #if 0
1142 /* not issued by kernel currently */
1143 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_CACHE) {
1144 struct puffs_cacheinfo *pci = (void *)preq;
1145
1146 if (pu->pu_ops.puffs_cache_write) {
1147 pu->pu_ops.puffs_cache_write(pu, preq->preq_cookie,
1148 pci->pcache_nruns, pci->pcache_runs);
1149 }
1150 error = 0;
1151 #endif
1152
1153 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_ERROR) {
1154 struct puffs_error *perr = (void *)preq;
1155
1156 pu->pu_errnotify(pu, preq->preq_optype,
1157 perr->perr_error, perr->perr_str, preq->preq_cookie);
1158 error = 0;
1159 } else {
1160 /*
1161 * I guess the kernel sees this one coming also
1162 */
1163 error = EINVAL;
1164 }
1165
1166 out:
1167 preq->preq_rv = error;
1168
1169 if (pu->pu_oppost)
1170 pu->pu_oppost(pu);
1171
1172 pcc->pcc_flags |= PCC_DONE;
1173 }
1174