make vfs & filesystems use failable copying
[minix3.git] / lib / libpuffs / dispatcher.c
blob590c8a802ebbd20418b0b67fe1628948e8ae58ae
1 /* $NetBSD: dispatcher.c,v 1.46 2013/11/06 19:56:38 christos Exp $ */
3 /*
4 * Copyright (c) 2006, 2007, 2008 Antti Kantee. All Rights Reserved.
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.
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.
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.
32 #include <sys/cdefs.h>
33 #if !defined(lint)
34 __RCSID("$NetBSD: dispatcher.c,v 1.46 2013/11/06 19:56:38 christos Exp $");
35 #endif /* !lint */
37 #include <sys/types.h>
38 #include <sys/poll.h>
40 #include <assert.h>
41 #include <errno.h>
42 #if !defined(__minix)
43 #include <pthread.h>
44 #endif /* !defined(__minix) */
45 #include <puffs.h>
46 #include <puffsdump.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <unistd.h>
51 #include "puffs_priv.h"
53 #define PUFFS_USE_FS_TTL(pu) (pu->pu_flags & PUFFS_KFLAG_CACHE_FS_TTL)
55 static void dispatch(struct puffs_cc *);
57 /* for our eyes only */
58 void
59 puffs__ml_dispatch(struct puffs_usermount *pu, struct puffs_framebuf *pb)
61 struct puffs_cc *pcc = puffs_cc_getcc(pu);
62 struct puffs_req *preq;
64 pcc->pcc_pb = pb;
65 pcc->pcc_flags |= PCC_MLCONT;
66 dispatch(pcc);
68 /* Put result to kernel sendqueue if necessary */
69 preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
70 if (PUFFSOP_WANTREPLY(preq->preq_opclass)) {
71 if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
72 puffsdump_rv(preq);
74 puffs_framev_enqueue_justsend(pu, pu->pu_fd,
75 pcc->pcc_pb, 0, 0);
76 } else {
77 puffs_framebuf_destroy(pcc->pcc_pb);
80 /* who needs information when you're living on borrowed time? */
81 if (pcc->pcc_flags & PCC_BORROWED) {
82 puffs_cc_yield(pcc); /* back to borrow source */
84 pcc->pcc_flags = 0;
87 /* public, but not really tested and only semi-supported */
88 int
89 puffs_dispatch_create(struct puffs_usermount *pu, struct puffs_framebuf *pb,
90 struct puffs_cc **pccp)
92 struct puffs_cc *pcc;
94 if (puffs__cc_create(pu, dispatch, &pcc) == -1)
95 return -1;
97 pcc->pcc_pb = pb;
98 *pccp = pcc;
100 return 0;
104 puffs_dispatch_exec(struct puffs_cc *pcc, struct puffs_framebuf **pbp)
106 int rv;
108 puffs_cc_continue(pcc);
110 if (pcc->pcc_flags & PCC_DONE) {
111 rv = 1;
112 *pbp = pcc->pcc_pb;
113 pcc->pcc_flags = 0;
114 puffs__cc_destroy(pcc, 0);
115 } else {
116 rv = 0;
119 return rv;
122 static void
123 dispatch(struct puffs_cc *pcc)
125 struct puffs_usermount *pu = pcc->pcc_pu;
126 struct puffs_ops *pops = &pu->pu_ops;
127 struct puffs_req *preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
128 void *auxbuf; /* help with typecasting */
129 puffs_cookie_t opcookie;
130 int error = 0, buildpath, pncookie;
132 /* XXX: smaller hammer, please */
133 if ((PUFFSOP_OPCLASS(preq->preq_opclass == PUFFSOP_VFS &&
134 preq->preq_optype == PUFFS_VFS_VPTOFH)) ||
135 (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN &&
136 (preq->preq_optype == PUFFS_VN_READDIR
137 || preq->preq_optype == PUFFS_VN_READ))) {
138 if (puffs_framebuf_reserve_space(pcc->pcc_pb,
139 PUFFS_MSG_MAXSIZE) == -1)
140 error = errno;
141 preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
144 auxbuf = preq;
145 opcookie = preq->preq_cookie;
147 assert((pcc->pcc_flags & PCC_DONE) == 0);
149 buildpath = pu->pu_flags & PUFFS_FLAG_BUILDPATH;
150 pncookie = pu->pu_flags & PUFFS_FLAG_PNCOOKIE;
151 assert(!buildpath || pncookie);
153 preq->preq_setbacks = 0;
155 if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
156 puffsdump_req(preq);
158 puffs__cc_setcaller(pcc, preq->preq_pid, preq->preq_lid);
160 /* pre-operation */
161 if (pu->pu_oppre)
162 pu->pu_oppre(pu);
164 if (error)
165 goto out;
167 /* Execute actual operation */
168 if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) {
169 switch (preq->preq_optype) {
170 case PUFFS_VFS_UNMOUNT:
172 struct puffs_vfsmsg_unmount *auxt = auxbuf;
174 PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTING);
175 error = pops->puffs_fs_unmount(pu, auxt->pvfsr_flags);
176 if (!error)
177 PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTED);
178 else
179 PU_SETSTATE(pu, PUFFS_STATE_RUNNING);
180 break;
183 case PUFFS_VFS_STATVFS:
185 struct puffs_vfsmsg_statvfs *auxt = auxbuf;
187 error = pops->puffs_fs_statvfs(pu, &auxt->pvfsr_sb);
188 break;
191 case PUFFS_VFS_SYNC:
193 struct puffs_vfsmsg_sync *auxt = auxbuf;
194 PUFFS_MAKECRED(pcr, &auxt->pvfsr_cred);
196 error = pops->puffs_fs_sync(pu,
197 auxt->pvfsr_waitfor, pcr);
198 break;
201 case PUFFS_VFS_FHTOVP:
203 struct puffs_vfsmsg_fhtonode *auxt = auxbuf;
204 struct puffs_newinfo pni;
206 pni.pni_cookie = &auxt->pvfsr_fhcookie;
207 pni.pni_vtype = &auxt->pvfsr_vtype;
208 pni.pni_size = &auxt->pvfsr_size;
209 pni.pni_rdev = &auxt->pvfsr_rdev;
210 pni.pni_va = NULL;
211 pni.pni_va_ttl = NULL;
212 pni.pni_cn_ttl = NULL;
214 error = pops->puffs_fs_fhtonode(pu, auxt->pvfsr_data,
215 auxt->pvfsr_dsize, &pni);
217 break;
220 case PUFFS_VFS_VPTOFH:
222 struct puffs_vfsmsg_nodetofh *auxt = auxbuf;
224 error = pops->puffs_fs_nodetofh(pu,
225 auxt->pvfsr_fhcookie, auxt->pvfsr_data,
226 &auxt->pvfsr_dsize);
228 break;
231 case PUFFS_VFS_EXTATTRCTL:
233 struct puffs_vfsmsg_extattrctl *auxt = auxbuf;
234 const char *attrname;
235 int flags;
237 if (pops->puffs_fs_extattrctl == NULL) {
238 error = EOPNOTSUPP;
239 break;
242 if (auxt->pvfsr_flags & PUFFS_EXTATTRCTL_HASATTRNAME)
243 attrname = auxt->pvfsr_attrname;
244 else
245 attrname = NULL;
247 flags = auxt->pvfsr_flags & PUFFS_EXTATTRCTL_HASNODE;
248 error = pops->puffs_fs_extattrctl(pu, auxt->pvfsr_cmd,
249 opcookie, flags,
250 auxt->pvfsr_attrnamespace, attrname);
251 break;
254 default:
256 * I guess the kernel sees this one coming
258 error = EINVAL;
259 break;
262 /* XXX: audit return values */
263 /* XXX: sync with kernel */
264 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) {
265 switch (preq->preq_optype) {
266 case PUFFS_VN_LOOKUP:
268 struct puffs_vnmsg_lookup *auxt = auxbuf;
269 struct puffs_newinfo pni;
270 struct puffs_cn pcn;
271 struct puffs_node *pn = NULL;
273 pcn.pcn_pkcnp = &auxt->pvnr_cn;
274 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
275 pni.pni_cookie = &auxt->pvnr_newnode;
276 pni.pni_vtype = &auxt->pvnr_vtype;
277 pni.pni_size = &auxt->pvnr_size;
278 pni.pni_rdev = &auxt->pvnr_rdev;
279 pni.pni_va = &auxt->pvnr_va;
280 pni.pni_va_ttl = &auxt->pvnr_va_ttl;
281 pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
283 if (buildpath) {
284 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
285 if (error)
286 break;
289 /* lookup *must* be present */
290 error = pops->puffs_node_lookup(pu, opcookie,
291 &pni, &pcn);
293 if (buildpath) {
294 if (error) {
295 pu->pu_pathfree(pu, &pcn.pcn_po_full);
296 } else {
298 * did we get a new node or a
299 * recycled node?
301 pn = PU_CMAP(pu, auxt->pvnr_newnode);
302 if (pn->pn_po.po_path == NULL)
303 pn->pn_po = pcn.pcn_po_full;
304 else
305 pu->pu_pathfree(pu,
306 &pcn.pcn_po_full);
310 if (pncookie && !error) {
311 if (pn == NULL)
312 pn = PU_CMAP(pu, auxt->pvnr_newnode);
313 pn->pn_nlookup++;
315 break;
318 case PUFFS_VN_CREATE:
320 struct puffs_vnmsg_create *auxt = auxbuf;
321 struct puffs_newinfo pni;
322 struct puffs_cn pcn;
323 struct puffs_node *pn = NULL;
325 if (pops->puffs_node_create == NULL) {
326 error = 0;
327 break;
330 pcn.pcn_pkcnp = &auxt->pvnr_cn;
331 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
333 memset(&pni, 0, sizeof(pni));
334 pni.pni_cookie = &auxt->pvnr_newnode;
335 pni.pni_va = &auxt->pvnr_va;
336 pni.pni_va_ttl = &auxt->pvnr_va_ttl;
337 pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
339 if (buildpath) {
340 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
341 if (error)
342 break;
345 error = pops->puffs_node_create(pu,
346 opcookie, &pni, &pcn, &auxt->pvnr_va);
348 if (buildpath) {
349 if (error) {
350 pu->pu_pathfree(pu, &pcn.pcn_po_full);
351 } else {
352 pn = PU_CMAP(pu, auxt->pvnr_newnode);
353 pn->pn_po = pcn.pcn_po_full;
357 if (pncookie && !error) {
358 if (pn == NULL)
359 pn = PU_CMAP(pu, auxt->pvnr_newnode);
360 pn->pn_nlookup++;
362 break;
365 case PUFFS_VN_MKNOD:
367 struct puffs_vnmsg_mknod *auxt = auxbuf;
368 struct puffs_newinfo pni;
369 struct puffs_cn pcn;
370 struct puffs_node *pn = NULL;
372 if (pops->puffs_node_mknod == NULL) {
373 error = 0;
374 break;
377 pcn.pcn_pkcnp = &auxt->pvnr_cn;
378 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
380 memset(&pni, 0, sizeof(pni));
381 pni.pni_cookie = &auxt->pvnr_newnode;
382 pni.pni_va = &auxt->pvnr_va;
383 pni.pni_va_ttl = &auxt->pvnr_va_ttl;
384 pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
386 if (buildpath) {
387 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
388 if (error)
389 break;
392 error = pops->puffs_node_mknod(pu,
393 opcookie, &pni, &pcn, &auxt->pvnr_va);
395 if (buildpath) {
396 if (error) {
397 pu->pu_pathfree(pu, &pcn.pcn_po_full);
398 } else {
399 pn = PU_CMAP(pu, auxt->pvnr_newnode);
400 pn->pn_po = pcn.pcn_po_full;
404 if (pncookie && !error) {
405 if (pn == NULL)
406 pn = PU_CMAP(pu, auxt->pvnr_newnode);
407 pn->pn_nlookup++;
409 break;
412 case PUFFS_VN_OPEN:
414 struct puffs_vnmsg_open *auxt = auxbuf;
415 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
417 if (pops->puffs_node_open == NULL) {
418 error = 0;
419 break;
422 error = pops->puffs_node_open(pu,
423 opcookie, auxt->pvnr_mode, pcr);
424 break;
427 case PUFFS_VN_CLOSE:
429 struct puffs_vnmsg_close *auxt = auxbuf;
430 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
432 if (pops->puffs_node_close == NULL) {
433 error = 0;
434 break;
437 error = pops->puffs_node_close(pu,
438 opcookie, auxt->pvnr_fflag, pcr);
439 break;
442 case PUFFS_VN_ACCESS:
444 struct puffs_vnmsg_access *auxt = auxbuf;
445 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
447 if (pops->puffs_node_access == NULL) {
448 error = 0;
449 break;
452 error = pops->puffs_node_access(pu,
453 opcookie, auxt->pvnr_mode, pcr);
454 break;
457 case PUFFS_VN_GETATTR:
459 struct puffs_vnmsg_getattr *auxt = auxbuf;
460 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
462 if (PUFFS_USE_FS_TTL(pu)) {
463 if (pops->puffs_node_getattr_ttl == NULL) {
464 error = EOPNOTSUPP;
465 break;
468 error = pops->puffs_node_getattr_ttl(pu,
469 opcookie, &auxt->pvnr_va, pcr,
470 &auxt->pvnr_va_ttl);
471 } else {
472 if (pops->puffs_node_getattr == NULL) {
473 error = EOPNOTSUPP;
474 break;
477 error = pops->puffs_node_getattr(pu,
478 opcookie, &auxt->pvnr_va, pcr);
480 break;
483 case PUFFS_VN_SETATTR:
485 struct puffs_vnmsg_setattr *auxt = auxbuf;
486 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
488 if (PUFFS_USE_FS_TTL(pu)) {
489 int xflag = 0;
491 if (pops->puffs_node_setattr_ttl == NULL) {
492 error = EOPNOTSUPP;
493 break;
496 if (!PUFFSOP_WANTREPLY(preq->preq_opclass))
497 xflag |= PUFFS_SETATTR_FAF;
499 error = pops->puffs_node_setattr_ttl(pu,
500 opcookie, &auxt->pvnr_va, pcr,
501 &auxt->pvnr_va_ttl, xflag);
502 } else {
503 if (pops->puffs_node_setattr == NULL) {
504 error = EOPNOTSUPP;
505 break;
508 error = pops->puffs_node_setattr(pu,
509 opcookie, &auxt->pvnr_va, pcr);
511 break;
514 case PUFFS_VN_MMAP:
516 struct puffs_vnmsg_mmap *auxt = auxbuf;
517 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
519 if (pops->puffs_node_mmap == NULL) {
520 error = 0;
521 break;
524 error = pops->puffs_node_mmap(pu,
525 opcookie, auxt->pvnr_prot, pcr);
526 break;
529 case PUFFS_VN_FSYNC:
531 struct puffs_vnmsg_fsync *auxt = auxbuf;
532 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
534 if (pops->puffs_node_fsync == NULL) {
535 error = 0;
536 break;
539 error = pops->puffs_node_fsync(pu, opcookie, pcr,
540 auxt->pvnr_flags, auxt->pvnr_offlo,
541 auxt->pvnr_offhi);
542 break;
545 case PUFFS_VN_SEEK:
547 struct puffs_vnmsg_seek *auxt = auxbuf;
548 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
550 if (pops->puffs_node_seek == NULL) {
551 error = 0;
552 break;
555 error = pops->puffs_node_seek(pu,
556 opcookie, auxt->pvnr_oldoff,
557 auxt->pvnr_newoff, pcr);
558 break;
561 case PUFFS_VN_REMOVE:
563 struct puffs_vnmsg_remove *auxt = auxbuf;
564 struct puffs_cn pcn;
565 if (pops->puffs_node_remove == NULL) {
566 error = 0;
567 break;
570 pcn.pcn_pkcnp = &auxt->pvnr_cn;
571 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
573 error = pops->puffs_node_remove(pu,
574 opcookie, auxt->pvnr_cookie_targ, &pcn);
575 break;
578 case PUFFS_VN_LINK:
580 struct puffs_vnmsg_link *auxt = auxbuf;
581 struct puffs_cn pcn;
582 if (pops->puffs_node_link == NULL) {
583 error = 0;
584 break;
587 pcn.pcn_pkcnp = &auxt->pvnr_cn;
588 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
590 if (buildpath) {
591 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
592 if (error)
593 break;
596 error = pops->puffs_node_link(pu,
597 opcookie, auxt->pvnr_cookie_targ, &pcn);
598 if (buildpath)
599 pu->pu_pathfree(pu, &pcn.pcn_po_full);
601 break;
604 case PUFFS_VN_RENAME:
606 struct puffs_vnmsg_rename *auxt = auxbuf;
607 struct puffs_cn pcn_src, pcn_targ;
608 struct puffs_node *pn_src;
610 if (pops->puffs_node_rename == NULL) {
611 error = 0;
612 break;
615 pcn_src.pcn_pkcnp = &auxt->pvnr_cn_src;
616 PUFFS_KCREDTOCRED(pcn_src.pcn_cred,
617 &auxt->pvnr_cn_src_cred);
619 pcn_targ.pcn_pkcnp = &auxt->pvnr_cn_targ;
620 PUFFS_KCREDTOCRED(pcn_targ.pcn_cred,
621 &auxt->pvnr_cn_targ_cred);
623 if (buildpath) {
624 pn_src = auxt->pvnr_cookie_src;
625 pcn_src.pcn_po_full = pn_src->pn_po;
627 error = puffs_path_pcnbuild(pu, &pcn_targ,
628 auxt->pvnr_cookie_targdir);
629 if (error)
630 break;
633 error = pops->puffs_node_rename(pu,
634 opcookie, auxt->pvnr_cookie_src,
635 &pcn_src, auxt->pvnr_cookie_targdir,
636 auxt->pvnr_cookie_targ, &pcn_targ);
638 if (buildpath) {
639 if (error) {
640 pu->pu_pathfree(pu,
641 &pcn_targ.pcn_po_full);
642 } else {
643 struct puffs_pathinfo pi;
644 struct puffs_pathobj po_old;
646 /* handle this node */
647 po_old = pn_src->pn_po;
648 pn_src->pn_po = pcn_targ.pcn_po_full;
650 if (pn_src->pn_va.va_type != VDIR) {
651 pu->pu_pathfree(pu, &po_old);
652 break;
655 /* handle all child nodes for DIRs */
656 pi.pi_old = &pcn_src.pcn_po_full;
657 pi.pi_new = &pcn_targ.pcn_po_full;
659 PU_LOCK();
660 if (puffs_pn_nodewalk(pu,
661 puffs_path_prefixadj, &pi) != NULL)
662 error = ENOMEM;
663 PU_UNLOCK();
664 pu->pu_pathfree(pu, &po_old);
667 break;
670 case PUFFS_VN_MKDIR:
672 struct puffs_vnmsg_mkdir *auxt = auxbuf;
673 struct puffs_newinfo pni;
674 struct puffs_cn pcn;
675 struct puffs_node *pn = NULL;
677 if (pops->puffs_node_mkdir == NULL) {
678 error = 0;
679 break;
682 pcn.pcn_pkcnp = &auxt->pvnr_cn;
683 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
685 memset(&pni, 0, sizeof(pni));
686 pni.pni_cookie = &auxt->pvnr_newnode;
687 pni.pni_va = &auxt->pvnr_va;
688 pni.pni_va_ttl = &auxt->pvnr_va_ttl;
689 pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
691 if (buildpath) {
692 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
693 if (error)
694 break;
697 error = pops->puffs_node_mkdir(pu,
698 opcookie, &pni, &pcn, &auxt->pvnr_va);
700 if (buildpath) {
701 if (error) {
702 pu->pu_pathfree(pu, &pcn.pcn_po_full);
703 } else {
704 pn = PU_CMAP(pu, auxt->pvnr_newnode);
705 pn->pn_po = pcn.pcn_po_full;
709 if (pncookie && !error) {
710 if (pn == NULL)
711 pn = PU_CMAP(pu, auxt->pvnr_newnode);
712 pn->pn_nlookup++;
714 break;
717 case PUFFS_VN_RMDIR:
719 struct puffs_vnmsg_rmdir *auxt = auxbuf;
720 struct puffs_cn pcn;
721 if (pops->puffs_node_rmdir == NULL) {
722 error = 0;
723 break;
726 pcn.pcn_pkcnp = &auxt->pvnr_cn;
727 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
729 error = pops->puffs_node_rmdir(pu,
730 opcookie, auxt->pvnr_cookie_targ, &pcn);
731 break;
734 case PUFFS_VN_SYMLINK:
736 struct puffs_vnmsg_symlink *auxt = auxbuf;
737 struct puffs_newinfo pni;
738 struct puffs_cn pcn;
739 struct puffs_node *pn = NULL;
741 if (pops->puffs_node_symlink == NULL) {
742 error = 0;
743 break;
746 pcn.pcn_pkcnp = &auxt->pvnr_cn;
747 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
749 memset(&pni, 0, sizeof(pni));
750 pni.pni_cookie = &auxt->pvnr_newnode;
751 pni.pni_va = &auxt->pvnr_va;
752 pni.pni_va_ttl = &auxt->pvnr_va_ttl;
753 pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
755 if (buildpath) {
756 error = puffs_path_pcnbuild(pu, &pcn, opcookie);
757 if (error)
758 break;
761 error = pops->puffs_node_symlink(pu,
762 opcookie, &pni, &pcn,
763 &auxt->pvnr_va, auxt->pvnr_link);
765 if (buildpath) {
766 if (error) {
767 pu->pu_pathfree(pu, &pcn.pcn_po_full);
768 } else {
769 pn = PU_CMAP(pu, auxt->pvnr_newnode);
770 pn->pn_po = pcn.pcn_po_full;
774 if (pncookie && !error) {
775 if (pn == NULL)
776 pn = PU_CMAP(pu, auxt->pvnr_newnode);
777 pn->pn_nlookup++;
779 break;
782 case PUFFS_VN_READDIR:
784 struct puffs_vnmsg_readdir *auxt = auxbuf;
785 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
786 struct dirent *dent;
787 off_t *cookies;
788 size_t res, origcookies;
790 if (pops->puffs_node_readdir == NULL) {
791 error = 0;
792 break;
795 if (auxt->pvnr_ncookies) {
796 /* LINTED: pvnr_data is __aligned() */
797 cookies = (off_t *)auxt->pvnr_data;
798 origcookies = auxt->pvnr_ncookies;
799 } else {
800 cookies = NULL;
801 origcookies = 0;
803 /* LINTED: dentoff is aligned in the kernel */
804 dent = (struct dirent *)
805 (auxt->pvnr_data + auxt->pvnr_dentoff);
807 res = auxt->pvnr_resid;
808 error = pops->puffs_node_readdir(pu,
809 opcookie, dent, &auxt->pvnr_offset,
810 &auxt->pvnr_resid, pcr, &auxt->pvnr_eofflag,
811 cookies, &auxt->pvnr_ncookies);
813 /* much easier to track non-working NFS */
814 assert(auxt->pvnr_ncookies <= origcookies);
816 /* need to move a bit more */
817 preq->preq_buflen = sizeof(struct puffs_vnmsg_readdir)
818 + auxt->pvnr_dentoff + (res - auxt->pvnr_resid);
819 break;
822 case PUFFS_VN_READLINK:
824 struct puffs_vnmsg_readlink *auxt = auxbuf;
825 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
827 if (pops->puffs_node_readlink == NULL) {
828 error = EOPNOTSUPP;
829 break;
832 /*LINTED*/
833 error = pops->puffs_node_readlink(pu, opcookie, pcr,
834 auxt->pvnr_link, &auxt->pvnr_linklen);
835 break;
838 case PUFFS_VN_RECLAIM:
840 struct puffs_vnmsg_reclaim *auxt = auxbuf;
841 struct puffs_node *pn;
843 if (pops->puffs_node_reclaim2 != NULL) {
844 error = pops->puffs_node_reclaim2(pu, opcookie,
845 auxt->pvnr_nlookup);
846 break;
849 if (pops->puffs_node_reclaim == NULL) {
850 error = 0;
851 break;
855 * This fixes a race condition,
856 * where a node in reclaimed by kernel
857 * after a lookup request is sent,
858 * but before the reply, leaving the kernel
859 * with a invalid vnode/cookie reference.
861 if (pncookie) {
862 pn = PU_CMAP(pu, opcookie);
863 pn->pn_nlookup -= auxt->pvnr_nlookup;
864 if (pn->pn_nlookup >= 1) {
865 error = 0;
866 break;
870 error = pops->puffs_node_reclaim(pu, opcookie);
871 break;
874 case PUFFS_VN_INACTIVE:
877 if (pops->puffs_node_inactive == NULL) {
878 error = EOPNOTSUPP;
879 break;
882 error = pops->puffs_node_inactive(pu, opcookie);
883 break;
886 case PUFFS_VN_PATHCONF:
888 struct puffs_vnmsg_pathconf *auxt = auxbuf;
889 if (pops->puffs_node_pathconf == NULL) {
890 error = 0;
891 break;
894 error = pops->puffs_node_pathconf(pu,
895 opcookie, auxt->pvnr_name,
896 &auxt->pvnr_retval);
897 break;
900 case PUFFS_VN_ADVLOCK:
902 struct puffs_vnmsg_advlock *auxt = auxbuf;
903 if (pops->puffs_node_advlock == NULL) {
904 error = 0;
905 break;
908 error = pops->puffs_node_advlock(pu,
909 opcookie, auxt->pvnr_id, auxt->pvnr_op,
910 &auxt->pvnr_fl, auxt->pvnr_flags);
911 break;
914 case PUFFS_VN_PRINT:
916 if (pops->puffs_node_print == NULL) {
917 error = 0;
918 break;
921 error = pops->puffs_node_print(pu,
922 opcookie);
923 break;
926 case PUFFS_VN_ABORTOP:
928 struct puffs_vnmsg_abortop *auxt = auxbuf;
929 struct puffs_cn pcn;
931 if (pops->puffs_node_abortop == NULL) {
932 error = 0;
933 break;
936 pcn.pcn_pkcnp = &auxt->pvnr_cn;
937 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
939 error = pops->puffs_node_abortop(pu, opcookie, &pcn);
941 break;
944 case PUFFS_VN_READ:
946 struct puffs_vnmsg_read *auxt = auxbuf;
947 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
948 size_t res;
950 if (pops->puffs_node_read == NULL) {
951 error = EIO;
952 break;
955 res = auxt->pvnr_resid;
956 error = pops->puffs_node_read(pu,
957 opcookie, auxt->pvnr_data,
958 auxt->pvnr_offset, &auxt->pvnr_resid,
959 pcr, auxt->pvnr_ioflag);
961 /* need to move a bit more */
962 preq->preq_buflen = sizeof(struct puffs_vnmsg_read)
963 + (res - auxt->pvnr_resid);
964 break;
967 case PUFFS_VN_WRITE:
969 struct puffs_vnmsg_write *auxt = auxbuf;
970 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
972 if (pops->puffs_node_write2 != NULL) {
973 int xflag = 0;
975 if (!PUFFSOP_WANTREPLY(preq->preq_opclass))
976 xflag |= PUFFS_SETATTR_FAF;
978 error = pops->puffs_node_write2(pu,
979 opcookie, auxt->pvnr_data,
980 auxt->pvnr_offset, &auxt->pvnr_resid,
981 pcr, auxt->pvnr_ioflag, xflag);
983 } else if (pops->puffs_node_write != NULL) {
984 error = pops->puffs_node_write(pu,
985 opcookie, auxt->pvnr_data,
986 auxt->pvnr_offset, &auxt->pvnr_resid,
987 pcr, auxt->pvnr_ioflag);
988 } else {
989 error = EIO;
990 break;
994 /* don't need to move data back to the kernel */
995 preq->preq_buflen = sizeof(struct puffs_vnmsg_write);
996 break;
999 case PUFFS_VN_POLL:
1001 struct puffs_vnmsg_poll *auxt = auxbuf;
1003 if (pops->puffs_node_poll == NULL) {
1004 error = 0;
1006 /* emulate genfs_poll() */
1007 auxt->pvnr_events &= (POLLIN | POLLOUT
1008 | POLLRDNORM | POLLWRNORM);
1010 break;
1013 error = pops->puffs_node_poll(pu,
1014 opcookie, &auxt->pvnr_events);
1015 break;
1018 case PUFFS_VN_GETEXTATTR:
1020 struct puffs_vnmsg_getextattr *auxt = auxbuf;
1021 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
1022 size_t res, *resp, *sizep;
1023 uint8_t *data;
1025 if (pops->puffs_node_getextattr == NULL) {
1026 error = EOPNOTSUPP;
1027 break;
1030 if (auxt->pvnr_datasize)
1031 sizep = &auxt->pvnr_datasize;
1032 else
1033 sizep = NULL;
1035 res = auxt->pvnr_resid;
1036 if (res > 0) {
1037 data = auxt->pvnr_data;
1038 resp = &auxt->pvnr_resid;
1039 } else {
1040 data = NULL;
1041 resp = NULL;
1044 error = pops->puffs_node_getextattr(pu,
1045 opcookie, auxt->pvnr_attrnamespace,
1046 auxt->pvnr_attrname, sizep, data, resp, pcr);
1048 /* need to move a bit more? */
1049 preq->preq_buflen =
1050 sizeof(struct puffs_vnmsg_getextattr)
1051 + (res - auxt->pvnr_resid);
1052 break;
1055 case PUFFS_VN_SETEXTATTR:
1057 struct puffs_vnmsg_setextattr *auxt = auxbuf;
1058 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
1059 size_t *resp;
1060 uint8_t *data;
1062 if (pops->puffs_node_setextattr == NULL) {
1063 error = EOPNOTSUPP;
1064 break;
1067 if (auxt->pvnr_resid > 0) {
1068 data = auxt->pvnr_data;
1069 resp = &auxt->pvnr_resid;
1070 } else {
1071 data = NULL;
1072 resp = NULL;
1075 error = pops->puffs_node_setextattr(pu,
1076 opcookie, auxt->pvnr_attrnamespace,
1077 auxt->pvnr_attrname, data, resp, pcr);
1078 break;
1081 case PUFFS_VN_LISTEXTATTR:
1083 struct puffs_vnmsg_listextattr *auxt = auxbuf;
1084 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
1085 size_t res, *resp, *sizep;
1086 int flag;
1087 uint8_t *data;
1089 if (pops->puffs_node_listextattr == NULL) {
1090 error = EOPNOTSUPP;
1091 break;
1094 if (auxt->pvnr_datasize)
1095 sizep = &auxt->pvnr_datasize;
1096 else
1097 sizep = NULL;
1099 res = auxt->pvnr_resid;
1100 if (res > 0) {
1101 data = auxt->pvnr_data;
1102 resp = &auxt->pvnr_resid;
1103 } else {
1104 data = NULL;
1105 resp = NULL;
1108 res = auxt->pvnr_resid;
1109 flag = auxt->pvnr_flag;
1110 error = pops->puffs_node_listextattr(pu,
1111 opcookie, auxt->pvnr_attrnamespace,
1112 sizep, data, resp, flag, pcr);
1114 /* need to move a bit more? */
1115 preq->preq_buflen =
1116 sizeof(struct puffs_vnmsg_listextattr)
1117 + (res - auxt->pvnr_resid);
1118 break;
1121 case PUFFS_VN_DELETEEXTATTR:
1123 struct puffs_vnmsg_deleteextattr *auxt = auxbuf;
1124 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
1126 if (pops->puffs_node_deleteextattr == NULL) {
1127 error = EOPNOTSUPP;
1128 break;
1131 error = pops->puffs_node_deleteextattr(pu,
1132 opcookie, auxt->pvnr_attrnamespace,
1133 auxt->pvnr_attrname, pcr);
1134 break;
1137 default:
1138 printf("inval op %d\n", preq->preq_optype);
1139 error = EINVAL;
1140 break;
1143 #if 0
1144 /* not issued by kernel currently */
1145 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_CACHE) {
1146 struct puffs_cacheinfo *pci = (void *)preq;
1148 if (pu->pu_ops.puffs_cache_write) {
1149 pu->pu_ops.puffs_cache_write(pu, preq->preq_cookie,
1150 pci->pcache_nruns, pci->pcache_runs);
1152 error = 0;
1153 #endif
1155 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_ERROR) {
1156 struct puffs_error *perr = (void *)preq;
1158 pu->pu_errnotify(pu, preq->preq_optype,
1159 perr->perr_error, perr->perr_str, preq->preq_cookie);
1160 error = 0;
1161 } else {
1163 * I guess the kernel sees this one coming also
1165 error = EINVAL;
1168 out:
1169 preq->preq_rv = error;
1171 if (pu->pu_oppost)
1172 pu->pu_oppost(pu);
1174 pcc->pcc_flags |= PCC_DONE;