1 /* $NetBSD: dispatcher.c,v 1.48 2014/10/31 13:56:04 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.48 2014/10/31 13:56:04 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
puffs__ml_dispatch(struct puffs_usermount * pu,struct puffs_framebuf * pb)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
puffs_dispatch_create(struct puffs_usermount * pu,struct puffs_framebuf * pb,struct puffs_cc ** pccp)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
puffs_dispatch_exec(struct puffs_cc * pcc,struct puffs_framebuf ** pbp)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
dispatch(struct puffs_cc * pcc)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_open2 != NULL) {
416 error = pops->puffs_node_open2(pu,
417 opcookie, auxt->pvnr_mode, pcr,
418 &auxt->pvnr_oflags);
419
420 break;
421 }
422
423 if (pops->puffs_node_open == NULL) {
424 error = 0;
425 break;
426 }
427
428 error = pops->puffs_node_open(pu,
429 opcookie, auxt->pvnr_mode, pcr);
430 break;
431 }
432
433 case PUFFS_VN_CLOSE:
434 {
435 struct puffs_vnmsg_close *auxt = auxbuf;
436 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
437
438 if (pops->puffs_node_close == NULL) {
439 error = 0;
440 break;
441 }
442
443 error = pops->puffs_node_close(pu,
444 opcookie, auxt->pvnr_fflag, pcr);
445 break;
446 }
447
448 case PUFFS_VN_ACCESS:
449 {
450 struct puffs_vnmsg_access *auxt = auxbuf;
451 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
452
453 if (pops->puffs_node_access == NULL) {
454 error = 0;
455 break;
456 }
457
458 error = pops->puffs_node_access(pu,
459 opcookie, auxt->pvnr_mode, pcr);
460 break;
461 }
462
463 case PUFFS_VN_GETATTR:
464 {
465 struct puffs_vnmsg_getattr *auxt = auxbuf;
466 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
467
468 if (PUFFS_USE_FS_TTL(pu)) {
469 if (pops->puffs_node_getattr_ttl == NULL) {
470 error = EOPNOTSUPP;
471 break;
472 }
473
474 error = pops->puffs_node_getattr_ttl(pu,
475 opcookie, &auxt->pvnr_va, pcr,
476 &auxt->pvnr_va_ttl);
477 } else {
478 if (pops->puffs_node_getattr == NULL) {
479 error = EOPNOTSUPP;
480 break;
481 }
482
483 error = pops->puffs_node_getattr(pu,
484 opcookie, &auxt->pvnr_va, pcr);
485 }
486 break;
487 }
488
489 case PUFFS_VN_SETATTR:
490 {
491 struct puffs_vnmsg_setattr *auxt = auxbuf;
492 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
493
494 if (PUFFS_USE_FS_TTL(pu)) {
495 int xflag = 0;
496
497 if (pops->puffs_node_setattr_ttl == NULL) {
498 error = EOPNOTSUPP;
499 break;
500 }
501
502 if (!PUFFSOP_WANTREPLY(preq->preq_opclass))
503 xflag |= PUFFS_SETATTR_FAF;
504
505 error = pops->puffs_node_setattr_ttl(pu,
506 opcookie, &auxt->pvnr_va, pcr,
507 &auxt->pvnr_va_ttl, xflag);
508 } else {
509 if (pops->puffs_node_setattr == NULL) {
510 error = EOPNOTSUPP;
511 break;
512 }
513
514 error = pops->puffs_node_setattr(pu,
515 opcookie, &auxt->pvnr_va, pcr);
516 }
517 break;
518 }
519
520 case PUFFS_VN_MMAP:
521 {
522 struct puffs_vnmsg_mmap *auxt = auxbuf;
523 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
524
525 if (pops->puffs_node_mmap == NULL) {
526 error = 0;
527 break;
528 }
529
530 error = pops->puffs_node_mmap(pu,
531 opcookie, auxt->pvnr_prot, pcr);
532 break;
533 }
534
535 case PUFFS_VN_FSYNC:
536 {
537 struct puffs_vnmsg_fsync *auxt = auxbuf;
538 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
539
540 if (pops->puffs_node_fsync == NULL) {
541 error = 0;
542 break;
543 }
544
545 error = pops->puffs_node_fsync(pu, opcookie, pcr,
546 auxt->pvnr_flags, auxt->pvnr_offlo,
547 auxt->pvnr_offhi);
548 break;
549 }
550
551 case PUFFS_VN_SEEK:
552 {
553 struct puffs_vnmsg_seek *auxt = auxbuf;
554 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
555
556 if (pops->puffs_node_seek == NULL) {
557 error = 0;
558 break;
559 }
560
561 error = pops->puffs_node_seek(pu,
562 opcookie, auxt->pvnr_oldoff,
563 auxt->pvnr_newoff, pcr);
564 break;
565 }
566
567 case PUFFS_VN_REMOVE:
568 {
569 struct puffs_vnmsg_remove *auxt = auxbuf;
570 struct puffs_cn pcn;
571 if (pops->puffs_node_remove == NULL) {
572 error = 0;
573 break;
574 }
575
576 pcn.pcn_pkcnp = &auxt->pvnr_cn;
577 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
578
579 error = pops->puffs_node_remove(pu,
580 opcookie, auxt->pvnr_cookie_targ, &pcn);
581 break;
582 }
583
584 case PUFFS_VN_LINK:
585 {
586 struct puffs_vnmsg_link *auxt = auxbuf;
587 struct puffs_cn pcn;
588 if (pops->puffs_node_link == NULL) {
589 error = 0;
590 break;
591 }
592
593 pcn.pcn_pkcnp = &auxt->pvnr_cn;
594 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
595
596 if (buildpath) {
597 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
598 if (error)
599 break;
600 }
601
602 error = pops->puffs_node_link(pu,
603 opcookie, auxt->pvnr_cookie_targ, &pcn);
604 if (buildpath)
605 pu->pu_pathfree(pu, &pcn.pcn_po_full);
606
607 break;
608 }
609
610 case PUFFS_VN_RENAME:
611 {
612 struct puffs_vnmsg_rename *auxt = auxbuf;
613 struct puffs_cn pcn_src, pcn_targ;
614 struct puffs_node *pn_src;
615
616 if (pops->puffs_node_rename == NULL) {
617 error = 0;
618 break;
619 }
620
621 pcn_src.pcn_pkcnp = &auxt->pvnr_cn_src;
622 PUFFS_KCREDTOCRED(pcn_src.pcn_cred,
623 &auxt->pvnr_cn_src_cred);
624
625 pcn_targ.pcn_pkcnp = &auxt->pvnr_cn_targ;
626 PUFFS_KCREDTOCRED(pcn_targ.pcn_cred,
627 &auxt->pvnr_cn_targ_cred);
628
629 if (buildpath) {
630 pn_src = auxt->pvnr_cookie_src;
631 pcn_src.pcn_po_full = pn_src->pn_po;
632
633 error = puffs_path_pcnbuild(pu, &pcn_targ,
634 auxt->pvnr_cookie_targdir);
635 if (error)
636 break;
637 }
638
639 error = pops->puffs_node_rename(pu,
640 opcookie, auxt->pvnr_cookie_src,
641 &pcn_src, auxt->pvnr_cookie_targdir,
642 auxt->pvnr_cookie_targ, &pcn_targ);
643
644 if (buildpath) {
645 if (error) {
646 pu->pu_pathfree(pu,
647 &pcn_targ.pcn_po_full);
648 } else {
649 struct puffs_pathinfo pi;
650 struct puffs_pathobj po_old;
651
652 /* handle this node */
653 po_old = pn_src->pn_po;
654 pn_src->pn_po = pcn_targ.pcn_po_full;
655
656 if (pn_src->pn_va.va_type != VDIR) {
657 pu->pu_pathfree(pu, &po_old);
658 break;
659 }
660
661 /* handle all child nodes for DIRs */
662 pi.pi_old = &pcn_src.pcn_po_full;
663 pi.pi_new = &pcn_targ.pcn_po_full;
664
665 PU_LOCK();
666 if (puffs_pn_nodewalk(pu,
667 puffs_path_prefixadj, &pi) != NULL)
668 error = ENOMEM;
669 PU_UNLOCK();
670 pu->pu_pathfree(pu, &po_old);
671 }
672 }
673 break;
674 }
675
676 case PUFFS_VN_MKDIR:
677 {
678 struct puffs_vnmsg_mkdir *auxt = auxbuf;
679 struct puffs_newinfo pni;
680 struct puffs_cn pcn;
681 struct puffs_node *pn = NULL;
682
683 if (pops->puffs_node_mkdir == NULL) {
684 error = 0;
685 break;
686 }
687
688 pcn.pcn_pkcnp = &auxt->pvnr_cn;
689 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
690
691 memset(&pni, 0, sizeof(pni));
692 pni.pni_cookie = &auxt->pvnr_newnode;
693 pni.pni_va = &auxt->pvnr_va;
694 pni.pni_va_ttl = &auxt->pvnr_va_ttl;
695 pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
696
697 if (buildpath) {
698 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
699 if (error)
700 break;
701 }
702
703 error = pops->puffs_node_mkdir(pu,
704 opcookie, &pni, &pcn, &auxt->pvnr_va);
705
706 if (buildpath) {
707 if (error) {
708 pu->pu_pathfree(pu, &pcn.pcn_po_full);
709 } else {
710 pn = PU_CMAP(pu, auxt->pvnr_newnode);
711 pn->pn_po = pcn.pcn_po_full;
712 }
713 }
714
715 if (pncookie && !error) {
716 if (pn == NULL)
717 pn = PU_CMAP(pu, auxt->pvnr_newnode);
718 pn->pn_nlookup++;
719 }
720 break;
721 }
722
723 case PUFFS_VN_RMDIR:
724 {
725 struct puffs_vnmsg_rmdir *auxt = auxbuf;
726 struct puffs_cn pcn;
727 if (pops->puffs_node_rmdir == NULL) {
728 error = 0;
729 break;
730 }
731
732 pcn.pcn_pkcnp = &auxt->pvnr_cn;
733 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
734
735 error = pops->puffs_node_rmdir(pu,
736 opcookie, auxt->pvnr_cookie_targ, &pcn);
737 break;
738 }
739
740 case PUFFS_VN_SYMLINK:
741 {
742 struct puffs_vnmsg_symlink *auxt = auxbuf;
743 struct puffs_newinfo pni;
744 struct puffs_cn pcn;
745 struct puffs_node *pn = NULL;
746
747 if (pops->puffs_node_symlink == NULL) {
748 error = 0;
749 break;
750 }
751
752 pcn.pcn_pkcnp = &auxt->pvnr_cn;
753 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
754
755 memset(&pni, 0, sizeof(pni));
756 pni.pni_cookie = &auxt->pvnr_newnode;
757 pni.pni_va = &auxt->pvnr_va;
758 pni.pni_va_ttl = &auxt->pvnr_va_ttl;
759 pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
760
761 if (buildpath) {
762 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
763 if (error)
764 break;
765 }
766
767 error = pops->puffs_node_symlink(pu,
768 opcookie, &pni, &pcn,
769 &auxt->pvnr_va, auxt->pvnr_link);
770
771 if (buildpath) {
772 if (error) {
773 pu->pu_pathfree(pu, &pcn.pcn_po_full);
774 } else {
775 pn = PU_CMAP(pu, auxt->pvnr_newnode);
776 pn->pn_po = pcn.pcn_po_full;
777 }
778 }
779
780 if (pncookie && !error) {
781 if (pn == NULL)
782 pn = PU_CMAP(pu, auxt->pvnr_newnode);
783 pn->pn_nlookup++;
784 }
785 break;
786 }
787
788 case PUFFS_VN_READDIR:
789 {
790 struct puffs_vnmsg_readdir *auxt = auxbuf;
791 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
792 struct dirent *dent;
793 off_t *cookies;
794 size_t res, origcookies;
795
796 if (pops->puffs_node_readdir == NULL) {
797 error = 0;
798 break;
799 }
800
801 if (auxt->pvnr_ncookies) {
802 /* LINTED: pvnr_data is __aligned() */
803 cookies = (off_t *)auxt->pvnr_data;
804 origcookies = auxt->pvnr_ncookies;
805 } else {
806 cookies = NULL;
807 origcookies = 0;
808 }
809 /* LINTED: dentoff is aligned in the kernel */
810 dent = (struct dirent *)
811 (auxt->pvnr_data + auxt->pvnr_dentoff);
812
813 res = auxt->pvnr_resid;
814 error = pops->puffs_node_readdir(pu,
815 opcookie, dent, &auxt->pvnr_offset,
816 &auxt->pvnr_resid, pcr, &auxt->pvnr_eofflag,
817 cookies, &auxt->pvnr_ncookies);
818
819 /* much easier to track non-working NFS */
820 assert(auxt->pvnr_ncookies <= origcookies);
821
822 /* need to move a bit more */
823 preq->preq_buflen = sizeof(struct puffs_vnmsg_readdir)
824 + auxt->pvnr_dentoff + (res - auxt->pvnr_resid);
825 break;
826 }
827
828 case PUFFS_VN_READLINK:
829 {
830 struct puffs_vnmsg_readlink *auxt = auxbuf;
831 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
832
833 if (pops->puffs_node_readlink == NULL) {
834 error = EOPNOTSUPP;
835 break;
836 }
837
838 /*LINTED*/
839 error = pops->puffs_node_readlink(pu, opcookie, pcr,
840 auxt->pvnr_link, &auxt->pvnr_linklen);
841 break;
842 }
843
844 case PUFFS_VN_RECLAIM:
845 {
846 struct puffs_vnmsg_reclaim *auxt = auxbuf;
847 struct puffs_node *pn;
848
849 if (pops->puffs_node_reclaim2 != NULL) {
850 error = pops->puffs_node_reclaim2(pu, opcookie,
851 auxt->pvnr_nlookup);
852 break;
853 }
854
855 if (pops->puffs_node_reclaim == NULL) {
856 error = 0;
857 break;
858 }
859
860 /*
861 * This fixes a race condition,
862 * where a node in reclaimed by kernel
863 * after a lookup request is sent,
864 * but before the reply, leaving the kernel
865 * with a invalid vnode/cookie reference.
866 */
867 if (pncookie) {
868 pn = PU_CMAP(pu, opcookie);
869 pn->pn_nlookup -= auxt->pvnr_nlookup;
870 if (pn->pn_nlookup >= 1) {
871 error = 0;
872 break;
873 }
874 }
875
876 error = pops->puffs_node_reclaim(pu, opcookie);
877 break;
878 }
879
880 case PUFFS_VN_INACTIVE:
881 {
882
883 if (pops->puffs_node_inactive == NULL) {
884 error = EOPNOTSUPP;
885 break;
886 }
887
888 error = pops->puffs_node_inactive(pu, opcookie);
889 break;
890 }
891
892 case PUFFS_VN_PATHCONF:
893 {
894 struct puffs_vnmsg_pathconf *auxt = auxbuf;
895 if (pops->puffs_node_pathconf == NULL) {
896 error = 0;
897 break;
898 }
899
900 error = pops->puffs_node_pathconf(pu,
901 opcookie, auxt->pvnr_name,
902 &auxt->pvnr_retval);
903 break;
904 }
905
906 case PUFFS_VN_ADVLOCK:
907 {
908 struct puffs_vnmsg_advlock *auxt = auxbuf;
909 if (pops->puffs_node_advlock == NULL) {
910 error = 0;
911 break;
912 }
913
914 error = pops->puffs_node_advlock(pu,
915 opcookie, auxt->pvnr_id, auxt->pvnr_op,
916 &auxt->pvnr_fl, auxt->pvnr_flags);
917 break;
918 }
919
920 case PUFFS_VN_PRINT:
921 {
922 if (pops->puffs_node_print == NULL) {
923 error = 0;
924 break;
925 }
926
927 error = pops->puffs_node_print(pu,
928 opcookie);
929 break;
930 }
931
932 case PUFFS_VN_ABORTOP:
933 {
934 struct puffs_vnmsg_abortop *auxt = auxbuf;
935 struct puffs_cn pcn;
936
937 if (pops->puffs_node_abortop == NULL) {
938 error = 0;
939 break;
940 }
941
942 pcn.pcn_pkcnp = &auxt->pvnr_cn;
943 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
944
945 error = pops->puffs_node_abortop(pu, opcookie, &pcn);
946
947 break;
948 }
949
950 case PUFFS_VN_READ:
951 {
952 struct puffs_vnmsg_read *auxt = auxbuf;
953 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
954 size_t res;
955
956 if (pops->puffs_node_read == NULL) {
957 error = EIO;
958 break;
959 }
960
961 res = auxt->pvnr_resid;
962 error = pops->puffs_node_read(pu,
963 opcookie, auxt->pvnr_data,
964 auxt->pvnr_offset, &auxt->pvnr_resid,
965 pcr, auxt->pvnr_ioflag);
966
967 /* need to move a bit more */
968 preq->preq_buflen = sizeof(struct puffs_vnmsg_read)
969 + (res - auxt->pvnr_resid);
970 break;
971 }
972
973 case PUFFS_VN_WRITE:
974 {
975 struct puffs_vnmsg_write *auxt = auxbuf;
976 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
977
978 if (pops->puffs_node_write2 != NULL) {
979 int xflag = 0;
980
981 if (!PUFFSOP_WANTREPLY(preq->preq_opclass))
982 xflag |= PUFFS_SETATTR_FAF;
983
984 error = pops->puffs_node_write2(pu,
985 opcookie, auxt->pvnr_data,
986 auxt->pvnr_offset, &auxt->pvnr_resid,
987 pcr, auxt->pvnr_ioflag, xflag);
988
989 } else if (pops->puffs_node_write != NULL) {
990 error = pops->puffs_node_write(pu,
991 opcookie, auxt->pvnr_data,
992 auxt->pvnr_offset, &auxt->pvnr_resid,
993 pcr, auxt->pvnr_ioflag);
994 } else {
995 error = EIO;
996 break;
997 }
998
999
1000 /* don't need to move data back to the kernel */
1001 preq->preq_buflen = sizeof(struct puffs_vnmsg_write);
1002 break;
1003 }
1004
1005 case PUFFS_VN_POLL:
1006 {
1007 struct puffs_vnmsg_poll *auxt = auxbuf;
1008
1009 if (pops->puffs_node_poll == NULL) {
1010 error = 0;
1011
1012 /* emulate genfs_poll() */
1013 auxt->pvnr_events &= (POLLIN | POLLOUT
1014 | POLLRDNORM | POLLWRNORM);
1015
1016 break;
1017 }
1018
1019 error = pops->puffs_node_poll(pu,
1020 opcookie, &auxt->pvnr_events);
1021 break;
1022 }
1023
1024 case PUFFS_VN_GETEXTATTR:
1025 {
1026 struct puffs_vnmsg_getextattr *auxt = auxbuf;
1027 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
1028 size_t res, *resp, *sizep;
1029 uint8_t *data;
1030
1031 if (pops->puffs_node_getextattr == NULL) {
1032 error = EOPNOTSUPP;
1033 break;
1034 }
1035
1036 if (auxt->pvnr_datasize)
1037 sizep = &auxt->pvnr_datasize;
1038 else
1039 sizep = NULL;
1040
1041 res = auxt->pvnr_resid;
1042 if (res > 0) {
1043 data = auxt->pvnr_data;
1044 resp = &auxt->pvnr_resid;
1045 } else {
1046 data = NULL;
1047 resp = NULL;
1048 }
1049
1050 error = pops->puffs_node_getextattr(pu,
1051 opcookie, auxt->pvnr_attrnamespace,
1052 auxt->pvnr_attrname, sizep, data, resp, pcr);
1053
1054 /* need to move a bit more? */
1055 preq->preq_buflen =
1056 sizeof(struct puffs_vnmsg_getextattr)
1057 + (res - auxt->pvnr_resid);
1058 break;
1059 }
1060
1061 case PUFFS_VN_SETEXTATTR:
1062 {
1063 struct puffs_vnmsg_setextattr *auxt = auxbuf;
1064 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
1065 size_t *resp;
1066 uint8_t *data;
1067
1068 if (pops->puffs_node_setextattr == NULL) {
1069 error = EOPNOTSUPP;
1070 break;
1071 }
1072
1073 if (auxt->pvnr_resid > 0) {
1074 data = auxt->pvnr_data;
1075 resp = &auxt->pvnr_resid;
1076 } else {
1077 data = NULL;
1078 resp = NULL;
1079 }
1080
1081 error = pops->puffs_node_setextattr(pu,
1082 opcookie, auxt->pvnr_attrnamespace,
1083 auxt->pvnr_attrname, data, resp, pcr);
1084 break;
1085 }
1086
1087 case PUFFS_VN_LISTEXTATTR:
1088 {
1089 struct puffs_vnmsg_listextattr *auxt = auxbuf;
1090 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
1091 size_t res, *resp, *sizep;
1092 int flag;
1093 uint8_t *data;
1094
1095 if (pops->puffs_node_listextattr == NULL) {
1096 error = EOPNOTSUPP;
1097 break;
1098 }
1099
1100 if (auxt->pvnr_datasize)
1101 sizep = &auxt->pvnr_datasize;
1102 else
1103 sizep = NULL;
1104
1105 res = auxt->pvnr_resid;
1106 if (res > 0) {
1107 data = auxt->pvnr_data;
1108 resp = &auxt->pvnr_resid;
1109 } else {
1110 data = NULL;
1111 resp = NULL;
1112 }
1113
1114 res = auxt->pvnr_resid;
1115 flag = auxt->pvnr_flag;
1116 error = pops->puffs_node_listextattr(pu,
1117 opcookie, auxt->pvnr_attrnamespace,
1118 sizep, data, resp, flag, pcr);
1119
1120 /* need to move a bit more? */
1121 preq->preq_buflen =
1122 sizeof(struct puffs_vnmsg_listextattr)
1123 + (res - auxt->pvnr_resid);
1124 break;
1125 }
1126
1127 case PUFFS_VN_DELETEEXTATTR:
1128 {
1129 struct puffs_vnmsg_deleteextattr *auxt = auxbuf;
1130 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
1131
1132 if (pops->puffs_node_deleteextattr == NULL) {
1133 error = EOPNOTSUPP;
1134 break;
1135 }
1136
1137 error = pops->puffs_node_deleteextattr(pu,
1138 opcookie, auxt->pvnr_attrnamespace,
1139 auxt->pvnr_attrname, pcr);
1140 break;
1141 }
1142
1143 case PUFFS_VN_FALLOCATE:
1144 {
1145 struct puffs_vnmsg_fallocate *auxt = auxbuf;
1146
1147 if (pops->puffs_node_fallocate == NULL) {
1148 error = EOPNOTSUPP;
1149 break;
1150 }
1151
1152 error = pops->puffs_node_fallocate(pu,
1153 opcookie, auxt->pvnr_off, auxt->pvnr_len);
1154 break;
1155 }
1156
1157 case PUFFS_VN_FDISCARD:
1158 {
1159 struct puffs_vnmsg_fdiscard *auxt = auxbuf;
1160
1161 if (pops->puffs_node_fdiscard == NULL) {
1162 error = EOPNOTSUPP;
1163 break;
1164 }
1165
1166 error = pops->puffs_node_fdiscard(pu,
1167 opcookie, auxt->pvnr_off, auxt->pvnr_len);
1168 break;
1169 }
1170
1171 default:
1172 printf("inval op %d\n", preq->preq_optype);
1173 error = EINVAL;
1174 break;
1175 }
1176
1177 #if 0
1178 /* not issued by kernel currently */
1179 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_CACHE) {
1180 struct puffs_cacheinfo *pci = (void *)preq;
1181
1182 if (pu->pu_ops.puffs_cache_write) {
1183 pu->pu_ops.puffs_cache_write(pu, preq->preq_cookie,
1184 pci->pcache_nruns, pci->pcache_runs);
1185 }
1186 error = 0;
1187 #endif
1188
1189 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_ERROR) {
1190 struct puffs_error *perr = (void *)preq;
1191
1192 pu->pu_errnotify(pu, preq->preq_optype,
1193 perr->perr_error, perr->perr_str, preq->preq_cookie);
1194 error = 0;
1195 } else {
1196 /*
1197 * I guess the kernel sees this one coming also
1198 */
1199 error = EINVAL;
1200 }
1201
1202 out:
1203 preq->preq_rv = error;
1204
1205 if (pu->pu_oppost)
1206 pu->pu_oppost(pu);
1207
1208 pcc->pcc_flags |= PCC_DONE;
1209 }
1210