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