dispatcher.c revision 1.42 1 /* $NetBSD: dispatcher.c,v 1.42 2012/07/21 05:17:10 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.42 2012/07/21 05:17:10 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;
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 preq->preq_setbacks = 0;
149
150 if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
151 puffsdump_req(preq);
152
153 puffs__cc_setcaller(pcc, preq->preq_pid, preq->preq_lid);
154
155 /* pre-operation */
156 if (pu->pu_oppre)
157 pu->pu_oppre(pu);
158
159 if (error)
160 goto out;
161
162 /* Execute actual operation */
163 if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) {
164 switch (preq->preq_optype) {
165 case PUFFS_VFS_UNMOUNT:
166 {
167 struct puffs_vfsmsg_unmount *auxt = auxbuf;
168
169 PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTING);
170 error = pops->puffs_fs_unmount(pu, auxt->pvfsr_flags);
171 if (!error)
172 PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTED);
173 else
174 PU_SETSTATE(pu, PUFFS_STATE_RUNNING);
175 break;
176 }
177
178 case PUFFS_VFS_STATVFS:
179 {
180 struct puffs_vfsmsg_statvfs *auxt = auxbuf;
181
182 error = pops->puffs_fs_statvfs(pu, &auxt->pvfsr_sb);
183 break;
184 }
185
186 case PUFFS_VFS_SYNC:
187 {
188 struct puffs_vfsmsg_sync *auxt = auxbuf;
189 PUFFS_MAKECRED(pcr, &auxt->pvfsr_cred);
190
191 error = pops->puffs_fs_sync(pu,
192 auxt->pvfsr_waitfor, pcr);
193 break;
194 }
195
196 case PUFFS_VFS_FHTOVP:
197 {
198 struct puffs_vfsmsg_fhtonode *auxt = auxbuf;
199 struct puffs_newinfo pni;
200
201 pni.pni_cookie = &auxt->pvfsr_fhcookie;
202 pni.pni_vtype = &auxt->pvfsr_vtype;
203 pni.pni_size = &auxt->pvfsr_size;
204 pni.pni_rdev = &auxt->pvfsr_rdev;
205 pni.pni_va = NULL;
206 pni.pni_va_ttl = NULL;
207 pni.pni_cn_ttl = NULL;
208
209 error = pops->puffs_fs_fhtonode(pu, auxt->pvfsr_data,
210 auxt->pvfsr_dsize, &pni);
211
212 break;
213 }
214
215 case PUFFS_VFS_VPTOFH:
216 {
217 struct puffs_vfsmsg_nodetofh *auxt = auxbuf;
218
219 error = pops->puffs_fs_nodetofh(pu,
220 auxt->pvfsr_fhcookie, auxt->pvfsr_data,
221 &auxt->pvfsr_dsize);
222
223 break;
224 }
225
226 case PUFFS_VFS_EXTATTRCTL:
227 {
228 struct puffs_vfsmsg_extattrctl *auxt = auxbuf;
229 const char *attrname;
230 int flags;
231
232 if (pops->puffs_fs_extattrctl == NULL) {
233 error = EOPNOTSUPP;
234 break;
235 }
236
237 if (auxt->pvfsr_flags & PUFFS_EXTATTRCTL_HASATTRNAME)
238 attrname = auxt->pvfsr_attrname;
239 else
240 attrname = NULL;
241
242 flags = auxt->pvfsr_flags & PUFFS_EXTATTRCTL_HASNODE;
243 error = pops->puffs_fs_extattrctl(pu, auxt->pvfsr_cmd,
244 opcookie, flags,
245 auxt->pvfsr_attrnamespace, attrname);
246 break;
247 }
248
249 default:
250 /*
251 * I guess the kernel sees this one coming
252 */
253 error = EINVAL;
254 break;
255 }
256
257 /* XXX: audit return values */
258 /* XXX: sync with kernel */
259 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) {
260 switch (preq->preq_optype) {
261 case PUFFS_VN_LOOKUP:
262 {
263 struct puffs_vnmsg_lookup *auxt = auxbuf;
264 struct puffs_newinfo pni;
265 struct puffs_cn pcn;
266 struct puffs_node *pn = NULL;
267
268 pcn.pcn_pkcnp = &auxt->pvnr_cn;
269 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
270 pni.pni_cookie = &auxt->pvnr_newnode;
271 pni.pni_vtype = &auxt->pvnr_vtype;
272 pni.pni_size = &auxt->pvnr_size;
273 pni.pni_rdev = &auxt->pvnr_rdev;
274 pni.pni_va = &auxt->pvnr_va;
275 pni.pni_va_ttl = &auxt->pvnr_va_ttl;
276 pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
277
278 if (buildpath) {
279 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
280 if (error)
281 break;
282 }
283
284 /* lookup *must* be present */
285 error = pops->puffs_node_lookup(pu, opcookie,
286 &pni, &pcn);
287
288 if (buildpath) {
289 if (error) {
290 pu->pu_pathfree(pu, &pcn.pcn_po_full);
291 } else {
292 /*
293 * did we get a new node or a
294 * recycled node?
295 */
296 pn = PU_CMAP(pu, auxt->pvnr_newnode);
297 if (pn->pn_po.po_path == NULL)
298 pn->pn_po = pcn.pcn_po_full;
299 else
300 pu->pu_pathfree(pu,
301 &pcn.pcn_po_full);
302 }
303 }
304
305 if (!error) {
306 if (pn == NULL)
307 pn = PU_CMAP(pu, auxt->pvnr_newnode);
308 pn->pn_nlookup++;
309 }
310 break;
311 }
312
313 case PUFFS_VN_CREATE:
314 {
315 struct puffs_vnmsg_create *auxt = auxbuf;
316 struct puffs_newinfo pni;
317 struct puffs_cn pcn;
318
319 if (pops->puffs_node_create == NULL) {
320 error = 0;
321 break;
322 }
323
324 pcn.pcn_pkcnp = &auxt->pvnr_cn;
325 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
326
327 memset(&pni, 0, sizeof(pni));
328 pni.pni_cookie = &auxt->pvnr_newnode;
329 pni.pni_va = &auxt->pvnr_va;
330 pni.pni_va_ttl = &auxt->pvnr_va_ttl;
331 pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
332
333 if (buildpath) {
334 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
335 if (error)
336 break;
337 }
338
339 error = pops->puffs_node_create(pu,
340 opcookie, &pni, &pcn, &auxt->pvnr_va);
341
342 if (buildpath) {
343 if (error) {
344 pu->pu_pathfree(pu, &pcn.pcn_po_full);
345 } else {
346 struct puffs_node *pn;
347
348 pn = PU_CMAP(pu, auxt->pvnr_newnode);
349 pn->pn_po = pcn.pcn_po_full;
350 }
351 }
352
353 break;
354 }
355
356 case PUFFS_VN_MKNOD:
357 {
358 struct puffs_vnmsg_mknod *auxt = auxbuf;
359 struct puffs_newinfo pni;
360 struct puffs_cn pcn;
361
362 if (pops->puffs_node_mknod == NULL) {
363 error = 0;
364 break;
365 }
366
367 pcn.pcn_pkcnp = &auxt->pvnr_cn;
368 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
369
370 memset(&pni, 0, sizeof(pni));
371 pni.pni_cookie = &auxt->pvnr_newnode;
372 pni.pni_va = &auxt->pvnr_va;
373 pni.pni_va_ttl = &auxt->pvnr_va_ttl;
374 pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
375
376 if (buildpath) {
377 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
378 if (error)
379 break;
380 }
381
382 error = pops->puffs_node_mknod(pu,
383 opcookie, &pni, &pcn, &auxt->pvnr_va);
384
385 if (buildpath) {
386 if (error) {
387 pu->pu_pathfree(pu, &pcn.pcn_po_full);
388 } else {
389 struct puffs_node *pn;
390
391 pn = PU_CMAP(pu, auxt->pvnr_newnode);
392 pn->pn_po = pcn.pcn_po_full;
393 }
394 }
395
396 break;
397 }
398
399 case PUFFS_VN_OPEN:
400 {
401 struct puffs_vnmsg_open *auxt = auxbuf;
402 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
403
404 if (pops->puffs_node_open == NULL) {
405 error = 0;
406 break;
407 }
408
409 error = pops->puffs_node_open(pu,
410 opcookie, auxt->pvnr_mode, pcr);
411 break;
412 }
413
414 case PUFFS_VN_CLOSE:
415 {
416 struct puffs_vnmsg_close *auxt = auxbuf;
417 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
418
419 if (pops->puffs_node_close == NULL) {
420 error = 0;
421 break;
422 }
423
424 error = pops->puffs_node_close(pu,
425 opcookie, auxt->pvnr_fflag, pcr);
426 break;
427 }
428
429 case PUFFS_VN_ACCESS:
430 {
431 struct puffs_vnmsg_access *auxt = auxbuf;
432 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
433
434 if (pops->puffs_node_access == NULL) {
435 error = 0;
436 break;
437 }
438
439 error = pops->puffs_node_access(pu,
440 opcookie, auxt->pvnr_mode, pcr);
441 break;
442 }
443
444 case PUFFS_VN_GETATTR:
445 {
446 struct puffs_vnmsg_getattr *auxt = auxbuf;
447 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
448
449 if (PUFFS_USE_FS_TTL(pu)) {
450 if (pops->puffs_node_getattr_ttl == NULL) {
451 error = EOPNOTSUPP;
452 break;
453 }
454
455 error = pops->puffs_node_getattr_ttl(pu,
456 opcookie, &auxt->pvnr_va, pcr,
457 &auxt->pvnr_va_ttl);
458 } else {
459 if (pops->puffs_node_getattr == NULL) {
460 error = EOPNOTSUPP;
461 break;
462 }
463
464 error = pops->puffs_node_getattr(pu,
465 opcookie, &auxt->pvnr_va, pcr);
466 }
467 break;
468 }
469
470 case PUFFS_VN_SETATTR:
471 {
472 struct puffs_vnmsg_setattr *auxt = auxbuf;
473 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
474
475 if (PUFFS_USE_FS_TTL(pu)) {
476 int xflag = 0;
477
478 if (pops->puffs_node_setattr_ttl == NULL) {
479 error = EOPNOTSUPP;
480 break;
481 }
482
483 if (!PUFFSOP_WANTREPLY(preq->preq_opclass))
484 xflag |= PUFFS_SETATTR_FAF;
485
486 error = pops->puffs_node_setattr_ttl(pu,
487 opcookie, &auxt->pvnr_va, pcr,
488 &auxt->pvnr_va_ttl, xflag);
489 } else {
490 if (pops->puffs_node_setattr == NULL) {
491 error = EOPNOTSUPP;
492 break;
493 }
494
495 error = pops->puffs_node_setattr(pu,
496 opcookie, &auxt->pvnr_va, pcr);
497 }
498 break;
499 }
500
501 case PUFFS_VN_MMAP:
502 {
503 struct puffs_vnmsg_mmap *auxt = auxbuf;
504 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
505
506 if (pops->puffs_node_mmap == NULL) {
507 error = 0;
508 break;
509 }
510
511 error = pops->puffs_node_mmap(pu,
512 opcookie, auxt->pvnr_prot, pcr);
513 break;
514 }
515
516 case PUFFS_VN_FSYNC:
517 {
518 struct puffs_vnmsg_fsync *auxt = auxbuf;
519 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
520
521 if (pops->puffs_node_fsync == NULL) {
522 error = 0;
523 break;
524 }
525
526 error = pops->puffs_node_fsync(pu, opcookie, pcr,
527 auxt->pvnr_flags, auxt->pvnr_offlo,
528 auxt->pvnr_offhi);
529 break;
530 }
531
532 case PUFFS_VN_SEEK:
533 {
534 struct puffs_vnmsg_seek *auxt = auxbuf;
535 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
536
537 if (pops->puffs_node_seek == NULL) {
538 error = 0;
539 break;
540 }
541
542 error = pops->puffs_node_seek(pu,
543 opcookie, auxt->pvnr_oldoff,
544 auxt->pvnr_newoff, pcr);
545 break;
546 }
547
548 case PUFFS_VN_REMOVE:
549 {
550 struct puffs_vnmsg_remove *auxt = auxbuf;
551 struct puffs_cn pcn;
552 if (pops->puffs_node_remove == NULL) {
553 error = 0;
554 break;
555 }
556
557 pcn.pcn_pkcnp = &auxt->pvnr_cn;
558 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
559
560 error = pops->puffs_node_remove(pu,
561 opcookie, auxt->pvnr_cookie_targ, &pcn);
562 break;
563 }
564
565 case PUFFS_VN_LINK:
566 {
567 struct puffs_vnmsg_link *auxt = auxbuf;
568 struct puffs_cn pcn;
569 if (pops->puffs_node_link == NULL) {
570 error = 0;
571 break;
572 }
573
574 pcn.pcn_pkcnp = &auxt->pvnr_cn;
575 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
576
577 if (buildpath) {
578 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
579 if (error)
580 break;
581 }
582
583 error = pops->puffs_node_link(pu,
584 opcookie, auxt->pvnr_cookie_targ, &pcn);
585 if (buildpath)
586 pu->pu_pathfree(pu, &pcn.pcn_po_full);
587
588 break;
589 }
590
591 case PUFFS_VN_RENAME:
592 {
593 struct puffs_vnmsg_rename *auxt = auxbuf;
594 struct puffs_cn pcn_src, pcn_targ;
595 struct puffs_node *pn_src;
596
597 if (pops->puffs_node_rename == NULL) {
598 error = 0;
599 break;
600 }
601
602 pcn_src.pcn_pkcnp = &auxt->pvnr_cn_src;
603 PUFFS_KCREDTOCRED(pcn_src.pcn_cred,
604 &auxt->pvnr_cn_src_cred);
605
606 pcn_targ.pcn_pkcnp = &auxt->pvnr_cn_targ;
607 PUFFS_KCREDTOCRED(pcn_targ.pcn_cred,
608 &auxt->pvnr_cn_targ_cred);
609
610 if (buildpath) {
611 pn_src = auxt->pvnr_cookie_src;
612 pcn_src.pcn_po_full = pn_src->pn_po;
613
614 error = puffs_path_pcnbuild(pu, &pcn_targ,
615 auxt->pvnr_cookie_targdir);
616 if (error)
617 break;
618 }
619
620 error = pops->puffs_node_rename(pu,
621 opcookie, auxt->pvnr_cookie_src,
622 &pcn_src, auxt->pvnr_cookie_targdir,
623 auxt->pvnr_cookie_targ, &pcn_targ);
624
625 if (buildpath) {
626 if (error) {
627 pu->pu_pathfree(pu,
628 &pcn_targ.pcn_po_full);
629 } else {
630 struct puffs_pathinfo pi;
631 struct puffs_pathobj po_old;
632
633 /* handle this node */
634 po_old = pn_src->pn_po;
635 pn_src->pn_po = pcn_targ.pcn_po_full;
636
637 if (pn_src->pn_va.va_type != VDIR) {
638 pu->pu_pathfree(pu, &po_old);
639 break;
640 }
641
642 /* handle all child nodes for DIRs */
643 pi.pi_old = &pcn_src.pcn_po_full;
644 pi.pi_new = &pcn_targ.pcn_po_full;
645
646 PU_LOCK();
647 if (puffs_pn_nodewalk(pu,
648 puffs_path_prefixadj, &pi) != NULL)
649 error = ENOMEM;
650 PU_UNLOCK();
651 pu->pu_pathfree(pu, &po_old);
652 }
653 }
654 break;
655 }
656
657 case PUFFS_VN_MKDIR:
658 {
659 struct puffs_vnmsg_mkdir *auxt = auxbuf;
660 struct puffs_newinfo pni;
661 struct puffs_cn pcn;
662
663 if (pops->puffs_node_mkdir == NULL) {
664 error = 0;
665 break;
666 }
667
668 pcn.pcn_pkcnp = &auxt->pvnr_cn;
669 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
670
671 memset(&pni, 0, sizeof(pni));
672 pni.pni_cookie = &auxt->pvnr_newnode;
673 pni.pni_va = &auxt->pvnr_va;
674 pni.pni_va_ttl = &auxt->pvnr_va_ttl;
675 pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
676
677 if (buildpath) {
678 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
679 if (error)
680 break;
681 }
682
683 error = pops->puffs_node_mkdir(pu,
684 opcookie, &pni, &pcn, &auxt->pvnr_va);
685
686 if (buildpath) {
687 if (error) {
688 pu->pu_pathfree(pu, &pcn.pcn_po_full);
689 } else {
690 struct puffs_node *pn;
691
692 pn = PU_CMAP(pu, auxt->pvnr_newnode);
693 pn->pn_po = pcn.pcn_po_full;
694 }
695 }
696
697 break;
698 }
699
700 case PUFFS_VN_RMDIR:
701 {
702 struct puffs_vnmsg_rmdir *auxt = auxbuf;
703 struct puffs_cn pcn;
704 if (pops->puffs_node_rmdir == NULL) {
705 error = 0;
706 break;
707 }
708
709 pcn.pcn_pkcnp = &auxt->pvnr_cn;
710 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
711
712 error = pops->puffs_node_rmdir(pu,
713 opcookie, auxt->pvnr_cookie_targ, &pcn);
714 break;
715 }
716
717 case PUFFS_VN_SYMLINK:
718 {
719 struct puffs_vnmsg_symlink *auxt = auxbuf;
720 struct puffs_newinfo pni;
721 struct puffs_cn pcn;
722
723 if (pops->puffs_node_symlink == NULL) {
724 error = 0;
725 break;
726 }
727
728 pcn.pcn_pkcnp = &auxt->pvnr_cn;
729 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
730
731 memset(&pni, 0, sizeof(pni));
732 pni.pni_cookie = &auxt->pvnr_newnode;
733 pni.pni_va = &auxt->pvnr_va;
734 pni.pni_va_ttl = &auxt->pvnr_va_ttl;
735 pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
736
737 if (buildpath) {
738 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
739 if (error)
740 break;
741 }
742
743 error = pops->puffs_node_symlink(pu,
744 opcookie, &pni, &pcn,
745 &auxt->pvnr_va, auxt->pvnr_link);
746
747 if (buildpath) {
748 if (error) {
749 pu->pu_pathfree(pu, &pcn.pcn_po_full);
750 } else {
751 struct puffs_node *pn;
752
753 pn = PU_CMAP(pu, auxt->pvnr_newnode);
754 pn->pn_po = pcn.pcn_po_full;
755 }
756 }
757
758 break;
759 }
760
761 case PUFFS_VN_READDIR:
762 {
763 struct puffs_vnmsg_readdir *auxt = auxbuf;
764 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
765 struct dirent *dent;
766 off_t *cookies;
767 size_t res, origcookies;
768
769 if (pops->puffs_node_readdir == NULL) {
770 error = 0;
771 break;
772 }
773
774 if (auxt->pvnr_ncookies) {
775 /* LINTED: pvnr_data is __aligned() */
776 cookies = (off_t *)auxt->pvnr_data;
777 origcookies = auxt->pvnr_ncookies;
778 } else {
779 cookies = NULL;
780 origcookies = 0;
781 }
782 /* LINTED: dentoff is aligned in the kernel */
783 dent = (struct dirent *)
784 (auxt->pvnr_data + auxt->pvnr_dentoff);
785
786 res = auxt->pvnr_resid;
787 error = pops->puffs_node_readdir(pu,
788 opcookie, dent, &auxt->pvnr_offset,
789 &auxt->pvnr_resid, pcr, &auxt->pvnr_eofflag,
790 cookies, &auxt->pvnr_ncookies);
791
792 /* much easier to track non-working NFS */
793 assert(auxt->pvnr_ncookies <= origcookies);
794
795 /* need to move a bit more */
796 preq->preq_buflen = sizeof(struct puffs_vnmsg_readdir)
797 + auxt->pvnr_dentoff + (res - auxt->pvnr_resid);
798 break;
799 }
800
801 case PUFFS_VN_READLINK:
802 {
803 struct puffs_vnmsg_readlink *auxt = auxbuf;
804 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
805
806 if (pops->puffs_node_readlink == NULL) {
807 error = EOPNOTSUPP;
808 break;
809 }
810
811 /*LINTED*/
812 error = pops->puffs_node_readlink(pu, opcookie, pcr,
813 auxt->pvnr_link, &auxt->pvnr_linklen);
814 break;
815 }
816
817 case PUFFS_VN_RECLAIM:
818 {
819 struct puffs_vnmsg_reclaim *auxt = auxbuf;
820 struct puffs_node *pn;
821
822 if (pops->puffs_node_reclaim == NULL) {
823 error = 0;
824 break;
825 }
826
827 /*
828 * This fixes a race condition,
829 * where a node in reclaimed by kernel
830 * after a lookup request is sent,
831 * but before the reply, leaving the kernel
832 * with a invalid vnode/cookie reference.
833 */
834 pn = PU_CMAP(pu, opcookie);
835 pn->pn_nlookup -= auxt->pvnr_nlookup;
836 if (pn->pn_nlookup >= 1) {
837 error = 0;
838 break;
839 }
840
841 error = pops->puffs_node_reclaim(pu, opcookie);
842 break;
843 }
844
845 case PUFFS_VN_INACTIVE:
846 {
847
848 if (pops->puffs_node_inactive == NULL) {
849 error = EOPNOTSUPP;
850 break;
851 }
852
853 error = pops->puffs_node_inactive(pu, opcookie);
854 break;
855 }
856
857 case PUFFS_VN_PATHCONF:
858 {
859 struct puffs_vnmsg_pathconf *auxt = auxbuf;
860 if (pops->puffs_node_pathconf == NULL) {
861 error = 0;
862 break;
863 }
864
865 error = pops->puffs_node_pathconf(pu,
866 opcookie, auxt->pvnr_name,
867 &auxt->pvnr_retval);
868 break;
869 }
870
871 case PUFFS_VN_ADVLOCK:
872 {
873 struct puffs_vnmsg_advlock *auxt = auxbuf;
874 if (pops->puffs_node_advlock == NULL) {
875 error = 0;
876 break;
877 }
878
879 error = pops->puffs_node_advlock(pu,
880 opcookie, auxt->pvnr_id, auxt->pvnr_op,
881 &auxt->pvnr_fl, auxt->pvnr_flags);
882 break;
883 }
884
885 case PUFFS_VN_PRINT:
886 {
887 if (pops->puffs_node_print == NULL) {
888 error = 0;
889 break;
890 }
891
892 error = pops->puffs_node_print(pu,
893 opcookie);
894 break;
895 }
896
897 case PUFFS_VN_ABORTOP:
898 {
899 struct puffs_vnmsg_abortop *auxt = auxbuf;
900 struct puffs_cn pcn;
901
902 if (pops->puffs_node_abortop == NULL) {
903 error = 0;
904 break;
905 }
906
907 pcn.pcn_pkcnp = &auxt->pvnr_cn;
908 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
909
910 error = pops->puffs_node_abortop(pu, opcookie, &pcn);
911
912 break;
913 }
914
915 case PUFFS_VN_READ:
916 {
917 struct puffs_vnmsg_read *auxt = auxbuf;
918 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
919 size_t res;
920
921 if (pops->puffs_node_read == NULL) {
922 error = EIO;
923 break;
924 }
925
926 res = auxt->pvnr_resid;
927 error = pops->puffs_node_read(pu,
928 opcookie, auxt->pvnr_data,
929 auxt->pvnr_offset, &auxt->pvnr_resid,
930 pcr, auxt->pvnr_ioflag);
931
932 /* need to move a bit more */
933 preq->preq_buflen = sizeof(struct puffs_vnmsg_read)
934 + (res - auxt->pvnr_resid);
935 break;
936 }
937
938 case PUFFS_VN_WRITE:
939 {
940 struct puffs_vnmsg_write *auxt = auxbuf;
941 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
942
943 if (pops->puffs_node_write2 != NULL) {
944 int xflag = 0;
945
946 if (!PUFFSOP_WANTREPLY(preq->preq_opclass))
947 xflag |= PUFFS_SETATTR_FAF;
948
949 error = pops->puffs_node_write2(pu,
950 opcookie, auxt->pvnr_data,
951 auxt->pvnr_offset, &auxt->pvnr_resid,
952 pcr, auxt->pvnr_ioflag, xflag);
953
954 } else if (pops->puffs_node_write != NULL) {
955 error = pops->puffs_node_write(pu,
956 opcookie, auxt->pvnr_data,
957 auxt->pvnr_offset, &auxt->pvnr_resid,
958 pcr, auxt->pvnr_ioflag);
959 } else {
960 error = EIO;
961 break;
962 }
963
964
965 /* don't need to move data back to the kernel */
966 preq->preq_buflen = sizeof(struct puffs_vnmsg_write);
967 break;
968 }
969
970 case PUFFS_VN_POLL:
971 {
972 struct puffs_vnmsg_poll *auxt = auxbuf;
973
974 if (pops->puffs_node_poll == NULL) {
975 error = 0;
976
977 /* emulate genfs_poll() */
978 auxt->pvnr_events &= (POLLIN | POLLOUT
979 | POLLRDNORM | POLLWRNORM);
980
981 break;
982 }
983
984 error = pops->puffs_node_poll(pu,
985 opcookie, &auxt->pvnr_events);
986 break;
987 }
988
989 case PUFFS_VN_GETEXTATTR:
990 {
991 struct puffs_vnmsg_getextattr *auxt = auxbuf;
992 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
993 size_t res, *resp, *sizep;
994 uint8_t *data;
995
996 if (pops->puffs_node_getextattr == NULL) {
997 error = EOPNOTSUPP;
998 break;
999 }
1000
1001 if (auxt->pvnr_datasize)
1002 sizep = &auxt->pvnr_datasize;
1003 else
1004 sizep = NULL;
1005
1006 res = auxt->pvnr_resid;
1007 if (res > 0) {
1008 data = auxt->pvnr_data;
1009 resp = &auxt->pvnr_resid;
1010 } else {
1011 data = NULL;
1012 resp = NULL;
1013 }
1014
1015 error = pops->puffs_node_getextattr(pu,
1016 opcookie, auxt->pvnr_attrnamespace,
1017 auxt->pvnr_attrname, sizep, data, resp, pcr);
1018
1019 /* need to move a bit more? */
1020 preq->preq_buflen =
1021 sizeof(struct puffs_vnmsg_getextattr)
1022 + (res - auxt->pvnr_resid);
1023 break;
1024 }
1025
1026 case PUFFS_VN_SETEXTATTR:
1027 {
1028 struct puffs_vnmsg_setextattr *auxt = auxbuf;
1029 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
1030 size_t *resp;
1031 uint8_t *data;
1032
1033 if (pops->puffs_node_setextattr == NULL) {
1034 error = EOPNOTSUPP;
1035 break;
1036 }
1037
1038 if (auxt->pvnr_resid > 0) {
1039 data = auxt->pvnr_data;
1040 resp = &auxt->pvnr_resid;
1041 } else {
1042 data = NULL;
1043 resp = NULL;
1044 }
1045
1046 error = pops->puffs_node_setextattr(pu,
1047 opcookie, auxt->pvnr_attrnamespace,
1048 auxt->pvnr_attrname, data, resp, pcr);
1049 break;
1050 }
1051
1052 case PUFFS_VN_LISTEXTATTR:
1053 {
1054 struct puffs_vnmsg_listextattr *auxt = auxbuf;
1055 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
1056 size_t res, *resp, *sizep;
1057 int flag;
1058 uint8_t *data;
1059
1060 if (pops->puffs_node_listextattr == NULL) {
1061 error = EOPNOTSUPP;
1062 break;
1063 }
1064
1065 if (auxt->pvnr_datasize)
1066 sizep = &auxt->pvnr_datasize;
1067 else
1068 sizep = NULL;
1069
1070 res = auxt->pvnr_resid;
1071 if (res > 0) {
1072 data = auxt->pvnr_data;
1073 resp = &auxt->pvnr_resid;
1074 } else {
1075 data = NULL;
1076 resp = NULL;
1077 }
1078
1079 res = auxt->pvnr_resid;
1080 flag = auxt->pvnr_flag;
1081 error = pops->puffs_node_listextattr(pu,
1082 opcookie, auxt->pvnr_attrnamespace,
1083 sizep, data, resp, flag, pcr);
1084
1085 /* need to move a bit more? */
1086 preq->preq_buflen =
1087 sizeof(struct puffs_vnmsg_listextattr)
1088 + (res - auxt->pvnr_resid);
1089 break;
1090 }
1091
1092 case PUFFS_VN_DELETEEXTATTR:
1093 {
1094 struct puffs_vnmsg_deleteextattr *auxt = auxbuf;
1095 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
1096
1097 if (pops->puffs_node_deleteextattr == NULL) {
1098 error = EOPNOTSUPP;
1099 break;
1100 }
1101
1102 error = pops->puffs_node_deleteextattr(pu,
1103 opcookie, auxt->pvnr_attrnamespace,
1104 auxt->pvnr_attrname, pcr);
1105 break;
1106 }
1107
1108 default:
1109 printf("inval op %d\n", preq->preq_optype);
1110 error = EINVAL;
1111 break;
1112 }
1113
1114 #if 0
1115 /* not issued by kernel currently */
1116 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_CACHE) {
1117 struct puffs_cacheinfo *pci = (void *)preq;
1118
1119 if (pu->pu_ops.puffs_cache_write) {
1120 pu->pu_ops.puffs_cache_write(pu, preq->preq_cookie,
1121 pci->pcache_nruns, pci->pcache_runs);
1122 }
1123 error = 0;
1124 #endif
1125
1126 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_ERROR) {
1127 struct puffs_error *perr = (void *)preq;
1128
1129 pu->pu_errnotify(pu, preq->preq_optype,
1130 perr->perr_error, perr->perr_str, preq->preq_cookie);
1131 error = 0;
1132 } else {
1133 /*
1134 * I guess the kernel sees this one coming also
1135 */
1136 error = EINVAL;
1137 }
1138
1139 out:
1140 preq->preq_rv = error;
1141
1142 if (pu->pu_oppost)
1143 pu->pu_oppost(pu);
1144
1145 pcc->pcc_flags |= PCC_DONE;
1146 }
1147