]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/fuse/fuse_vnops.c
MFHead @r350386
[FreeBSD/FreeBSD.git] / sys / fs / fuse / fuse_vnops.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 2007-2009 Google Inc. and Amit Singh
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are
9  * met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  *   copyright notice, this list of conditions and the following disclaimer
15  *   in the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of Google Inc. nor the names of its
18  *   contributors may be used to endorse or promote products derived from
19  *   this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Copyright (C) 2005 Csaba Henk.
34  * All rights reserved.
35  *
36  * Copyright (c) 2019 The FreeBSD Foundation
37  *
38  * Portions of this software were developed by BFF Storage Systems, LLC under
39  * sponsorship from the FreeBSD Foundation.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  *
50  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
51  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
54  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60  * SUCH DAMAGE.
61  */
62
63 #include <sys/cdefs.h>
64 __FBSDID("$FreeBSD$");
65
66 #include <sys/param.h>
67 #include <sys/module.h>
68 #include <sys/systm.h>
69 #include <sys/errno.h>
70 #include <sys/kernel.h>
71 #include <sys/conf.h>
72 #include <sys/uio.h>
73 #include <sys/malloc.h>
74 #include <sys/queue.h>
75 #include <sys/lock.h>
76 #include <sys/rwlock.h>
77 #include <sys/sx.h>
78 #include <sys/proc.h>
79 #include <sys/mount.h>
80 #include <sys/vnode.h>
81 #include <sys/namei.h>
82 #include <sys/extattr.h>
83 #include <sys/stat.h>
84 #include <sys/unistd.h>
85 #include <sys/filedesc.h>
86 #include <sys/file.h>
87 #include <sys/fcntl.h>
88 #include <sys/dirent.h>
89 #include <sys/bio.h>
90 #include <sys/buf.h>
91 #include <sys/sysctl.h>
92 #include <sys/vmmeter.h>
93
94 #include <vm/vm.h>
95 #include <vm/vm_extern.h>
96 #include <vm/pmap.h>
97 #include <vm/vm_map.h>
98 #include <vm/vm_page.h>
99 #include <vm/vm_param.h>
100 #include <vm/vm_object.h>
101 #include <vm/vm_pager.h>
102 #include <vm/vnode_pager.h>
103 #include <vm/vm_object.h>
104
105 #include "fuse.h"
106 #include "fuse_file.h"
107 #include "fuse_internal.h"
108 #include "fuse_ipc.h"
109 #include "fuse_node.h"
110 #include "fuse_io.h"
111
112 #include <sys/priv.h>
113
114 /* Maximum number of hardlinks to a single FUSE file */
115 #define FUSE_LINK_MAX                      UINT32_MAX
116
117 SDT_PROVIDER_DECLARE(fusefs);
118 /* 
119  * Fuse trace probe:
120  * arg0: verbosity.  Higher numbers give more verbose messages
121  * arg1: Textual message
122  */
123 SDT_PROBE_DEFINE2(fusefs, , vnops, trace, "int", "char*");
124
125 /* vnode ops */
126 static vop_access_t fuse_vnop_access;
127 static vop_advlock_t fuse_vnop_advlock;
128 static vop_bmap_t fuse_vnop_bmap;
129 static vop_close_t fuse_fifo_close;
130 static vop_close_t fuse_vnop_close;
131 static vop_create_t fuse_vnop_create;
132 static vop_deleteextattr_t fuse_vnop_deleteextattr;
133 static vop_fdatasync_t fuse_vnop_fdatasync;
134 static vop_fsync_t fuse_vnop_fsync;
135 static vop_getattr_t fuse_vnop_getattr;
136 static vop_getextattr_t fuse_vnop_getextattr;
137 static vop_inactive_t fuse_vnop_inactive;
138 static vop_link_t fuse_vnop_link;
139 static vop_listextattr_t fuse_vnop_listextattr;
140 static vop_lookup_t fuse_vnop_lookup;
141 static vop_mkdir_t fuse_vnop_mkdir;
142 static vop_mknod_t fuse_vnop_mknod;
143 static vop_open_t fuse_vnop_open;
144 static vop_pathconf_t fuse_vnop_pathconf;
145 static vop_read_t fuse_vnop_read;
146 static vop_readdir_t fuse_vnop_readdir;
147 static vop_readlink_t fuse_vnop_readlink;
148 static vop_reclaim_t fuse_vnop_reclaim;
149 static vop_remove_t fuse_vnop_remove;
150 static vop_rename_t fuse_vnop_rename;
151 static vop_rmdir_t fuse_vnop_rmdir;
152 static vop_setattr_t fuse_vnop_setattr;
153 static vop_setextattr_t fuse_vnop_setextattr;
154 static vop_strategy_t fuse_vnop_strategy;
155 static vop_symlink_t fuse_vnop_symlink;
156 static vop_write_t fuse_vnop_write;
157 static vop_getpages_t fuse_vnop_getpages;
158 static vop_print_t fuse_vnop_print;
159 static vop_vptofh_t fuse_vnop_vptofh;
160
161 struct vop_vector fuse_fifoops = {
162         .vop_default =          &fifo_specops,
163         .vop_access =           fuse_vnop_access,
164         .vop_close =            fuse_fifo_close,
165         .vop_fsync =            fuse_vnop_fsync,
166         .vop_getattr =          fuse_vnop_getattr,
167         .vop_inactive =         fuse_vnop_inactive,
168         .vop_pathconf =         fuse_vnop_pathconf,
169         .vop_print =            fuse_vnop_print,
170         .vop_read =             VOP_PANIC,
171         .vop_reclaim =          fuse_vnop_reclaim,
172         .vop_setattr =          fuse_vnop_setattr,
173         .vop_write =            VOP_PANIC,
174         .vop_vptofh =           fuse_vnop_vptofh,
175 };
176
177 struct vop_vector fuse_vnops = {
178         .vop_allocate = VOP_EINVAL,
179         .vop_default = &default_vnodeops,
180         .vop_access = fuse_vnop_access,
181         .vop_advlock = fuse_vnop_advlock,
182         .vop_bmap = fuse_vnop_bmap,
183         .vop_close = fuse_vnop_close,
184         .vop_create = fuse_vnop_create,
185         .vop_deleteextattr = fuse_vnop_deleteextattr,
186         .vop_fsync = fuse_vnop_fsync,
187         .vop_fdatasync = fuse_vnop_fdatasync,
188         .vop_getattr = fuse_vnop_getattr,
189         .vop_getextattr = fuse_vnop_getextattr,
190         .vop_inactive = fuse_vnop_inactive,
191         /*
192          * TODO: implement vop_ioctl after upgrading to protocol 7.16.
193          * FUSE_IOCTL was added in 7.11, but 32-bit compat is broken until
194          * 7.16.
195          */
196         .vop_link = fuse_vnop_link,
197         .vop_listextattr = fuse_vnop_listextattr,
198         .vop_lookup = fuse_vnop_lookup,
199         .vop_mkdir = fuse_vnop_mkdir,
200         .vop_mknod = fuse_vnop_mknod,
201         .vop_open = fuse_vnop_open,
202         .vop_pathconf = fuse_vnop_pathconf,
203         /*
204          * TODO: implement vop_poll after upgrading to protocol 7.21.
205          * FUSE_POLL was added in protocol 7.11, but it's kind of broken until
206          * 7.21, which adds the ability for the client to choose which poll
207          * events it wants, and for a client to deregister a file handle
208          */
209         .vop_read = fuse_vnop_read,
210         .vop_readdir = fuse_vnop_readdir,
211         .vop_readlink = fuse_vnop_readlink,
212         .vop_reclaim = fuse_vnop_reclaim,
213         .vop_remove = fuse_vnop_remove,
214         .vop_rename = fuse_vnop_rename,
215         .vop_rmdir = fuse_vnop_rmdir,
216         .vop_setattr = fuse_vnop_setattr,
217         .vop_setextattr = fuse_vnop_setextattr,
218         .vop_strategy = fuse_vnop_strategy,
219         .vop_symlink = fuse_vnop_symlink,
220         .vop_write = fuse_vnop_write,
221         .vop_getpages = fuse_vnop_getpages,
222         .vop_print = fuse_vnop_print,
223         .vop_vptofh = fuse_vnop_vptofh,
224 };
225
226 uma_zone_t fuse_pbuf_zone;
227
228 #define fuse_vm_page_lock(m)            vm_page_lock((m));
229 #define fuse_vm_page_unlock(m)          vm_page_unlock((m));
230 #define fuse_vm_page_lock_queues()      ((void)0)
231 #define fuse_vm_page_unlock_queues()    ((void)0)
232
233 /* Check permission for extattr operations, much like extattr_check_cred */
234 static int
235 fuse_extattr_check_cred(struct vnode *vp, int ns, struct ucred *cred,
236         struct thread *td, accmode_t accmode)
237 {
238         struct mount *mp = vnode_mount(vp);
239         struct fuse_data *data = fuse_get_mpdata(mp);
240
241         /*
242          * Kernel-invoked always succeeds.
243          */
244         if (cred == NOCRED)
245                 return (0);
246
247         /*
248          * Do not allow privileged processes in jail to directly manipulate
249          * system attributes.
250          */
251         switch (ns) {
252         case EXTATTR_NAMESPACE_SYSTEM:
253                 if (data->dataflags & FSESS_DEFAULT_PERMISSIONS) {
254                         return (priv_check_cred(cred, PRIV_VFS_EXTATTR_SYSTEM));
255                 }
256                 /* FALLTHROUGH */
257         case EXTATTR_NAMESPACE_USER:
258                 return (fuse_internal_access(vp, accmode, td, cred));
259         default:
260                 return (EPERM);
261         }
262 }
263
264 /* Get a filehandle for a directory */
265 static int
266 fuse_filehandle_get_dir(struct vnode *vp, struct fuse_filehandle **fufhp,
267         struct ucred *cred, pid_t pid)
268 {
269         if (fuse_filehandle_get(vp, FREAD, fufhp, cred, pid) == 0)
270                 return 0;
271         return fuse_filehandle_get(vp, FEXEC, fufhp, cred, pid);
272 }
273
274 /* Send FUSE_FLUSH for this vnode */
275 static int
276 fuse_flush(struct vnode *vp, struct ucred *cred, pid_t pid, int fflag)
277 {
278         struct fuse_flush_in *ffi;
279         struct fuse_filehandle *fufh;
280         struct fuse_dispatcher fdi;
281         struct thread *td = curthread;
282         struct mount *mp = vnode_mount(vp);
283         int err;
284
285         if (!fsess_isimpl(vnode_mount(vp), FUSE_FLUSH))
286                 return 0;
287
288         err = fuse_filehandle_getrw(vp, fflag, &fufh, cred, pid);
289         if (err)
290                 return err;
291
292         fdisp_init(&fdi, sizeof(*ffi));
293         fdisp_make_vp(&fdi, FUSE_FLUSH, vp, td, cred);
294         ffi = fdi.indata;
295         ffi->fh = fufh->fh_id;
296         /* 
297          * If the file has a POSIX lock then we're supposed to set lock_owner.
298          * If not, then lock_owner is undefined.  So we may as well always set
299          * it.
300          */
301         ffi->lock_owner = td->td_proc->p_pid;
302
303         err = fdisp_wait_answ(&fdi);
304         if (err == ENOSYS) {
305                 fsess_set_notimpl(mp, FUSE_FLUSH);
306                 err = 0;
307         }
308         fdisp_destroy(&fdi);
309         return err;
310 }
311
312 /* Close wrapper for fifos.  */
313 static int
314 fuse_fifo_close(struct vop_close_args *ap)
315 {
316         return (fifo_specops.vop_close(ap));
317 }
318
319 /*
320     struct vnop_access_args {
321         struct vnode *a_vp;
322 #if VOP_ACCESS_TAKES_ACCMODE_T
323         accmode_t a_accmode;
324 #else
325         int a_mode;
326 #endif
327         struct ucred *a_cred;
328         struct thread *a_td;
329     };
330 */
331 static int
332 fuse_vnop_access(struct vop_access_args *ap)
333 {
334         struct vnode *vp = ap->a_vp;
335         int accmode = ap->a_accmode;
336         struct ucred *cred = ap->a_cred;
337
338         struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp));
339
340         int err;
341
342         if (fuse_isdeadfs(vp)) {
343                 if (vnode_isvroot(vp)) {
344                         return 0;
345                 }
346                 return ENXIO;
347         }
348         if (!(data->dataflags & FSESS_INITED)) {
349                 if (vnode_isvroot(vp)) {
350                         if (priv_check_cred(cred, PRIV_VFS_ADMIN) ||
351                             (fuse_match_cred(data->daemoncred, cred) == 0)) {
352                                 return 0;
353                         }
354                 }
355                 return EBADF;
356         }
357         if (vnode_islnk(vp)) {
358                 return 0;
359         }
360
361         err = fuse_internal_access(vp, accmode, ap->a_td, ap->a_cred);
362         return err;
363 }
364
365 /*
366  * struct vop_advlock_args {
367  *      struct vop_generic_args a_gen;
368  *      struct vnode *a_vp;
369  *      void *a_id;
370  *      int a_op;
371  *      struct flock *a_fl;
372  *      int a_flags;
373  * }
374  */
375 static int
376 fuse_vnop_advlock(struct vop_advlock_args *ap)
377 {
378         struct vnode *vp = ap->a_vp;
379         struct flock *fl = ap->a_fl;
380         struct thread *td = curthread;
381         struct ucred *cred = td->td_ucred;
382         pid_t pid = td->td_proc->p_pid;
383         struct fuse_filehandle *fufh;
384         struct fuse_dispatcher fdi;
385         struct fuse_lk_in *fli;
386         struct fuse_lk_out *flo;
387         enum fuse_opcode op;
388         int dataflags, err;
389         int flags = ap->a_flags;
390
391         dataflags = fuse_get_mpdata(vnode_mount(vp))->dataflags;
392
393         if (fuse_isdeadfs(vp)) {
394                 return ENXIO;
395         }
396
397         if (!(dataflags & FSESS_POSIX_LOCKS))
398                 return vop_stdadvlock(ap);
399         /* FUSE doesn't properly support flock until protocol 7.17 */
400         if (flags & F_FLOCK)
401                 return vop_stdadvlock(ap);
402
403         err = fuse_filehandle_get_anyflags(vp, &fufh, cred, pid);
404         if (err)
405                 return err;
406
407         fdisp_init(&fdi, sizeof(*fli));
408
409         switch(ap->a_op) {
410         case F_GETLK:
411                 op = FUSE_GETLK;
412                 break;
413         case F_SETLK:
414                 op = FUSE_SETLK;
415                 break;
416         case F_SETLKW:
417                 op = FUSE_SETLKW;
418                 break;
419         default:
420                 return EINVAL;
421         }
422
423         fdisp_make_vp(&fdi, op, vp, td, cred);
424         fli = fdi.indata;
425         fli->fh = fufh->fh_id;
426         fli->owner = fl->l_pid;
427         fli->lk.start = fl->l_start;
428         if (fl->l_len != 0)
429                 fli->lk.end = fl->l_start + fl->l_len - 1;
430         else
431                 fli->lk.end = INT64_MAX;
432         fli->lk.type = fl->l_type;
433         fli->lk.pid = fl->l_pid;
434
435         err = fdisp_wait_answ(&fdi);
436         fdisp_destroy(&fdi);
437
438         if (err == 0 && op == FUSE_GETLK) {
439                 flo = fdi.answ;
440                 fl->l_type = flo->lk.type;
441                 fl->l_pid = flo->lk.pid;
442                 if (flo->lk.type != F_UNLCK) {
443                         fl->l_start = flo->lk.start;
444                         if (flo->lk.end == INT64_MAX)
445                                 fl->l_len = 0;
446                         else
447                                 fl->l_len = flo->lk.end - flo->lk.start + 1;
448                         fl->l_start = flo->lk.start;
449                 }
450         }
451
452         return err;
453 }
454
455 /* {
456         struct vnode *a_vp;
457         daddr_t a_bn;
458         struct bufobj **a_bop;
459         daddr_t *a_bnp;
460         int *a_runp;
461         int *a_runb;
462 } */
463 static int
464 fuse_vnop_bmap(struct vop_bmap_args *ap)
465 {
466         struct vnode *vp = ap->a_vp;
467         struct bufobj **bo = ap->a_bop;
468         struct thread *td = curthread;
469         struct mount *mp;
470         struct fuse_dispatcher fdi;
471         struct fuse_bmap_in *fbi;
472         struct fuse_bmap_out *fbo;
473         struct fuse_data *data;
474         uint64_t biosize;
475         off_t filesize;
476         daddr_t lbn = ap->a_bn;
477         daddr_t *pbn = ap->a_bnp;
478         int *runp = ap->a_runp;
479         int *runb = ap->a_runb;
480         int error = 0;
481         int maxrun;
482
483         if (fuse_isdeadfs(vp)) {
484                 return ENXIO;
485         }
486
487         mp = vnode_mount(vp);
488         data = fuse_get_mpdata(mp);
489         biosize = fuse_iosize(vp);
490         maxrun = MIN(vp->v_mount->mnt_iosize_max / biosize - 1,
491                 data->max_readahead_blocks);
492
493         if (bo != NULL)
494                 *bo = &vp->v_bufobj;
495
496         /*
497          * The FUSE_BMAP operation does not include the runp and runb
498          * variables, so we must guess.  Report nonzero contiguous runs so
499          * cluster_read will combine adjacent reads.  It's worthwhile to reduce
500          * upcalls even if we don't know the true physical layout of the file.
501          * 
502          * FUSE file systems may opt out of read clustering in two ways:
503          * * mounting with -onoclusterr
504          * * Setting max_readahead <= maxbcachebuf during FUSE_INIT
505          */
506         if (runb != NULL)
507                 *runb = MIN(lbn, maxrun);
508         if (runp != NULL) {
509                 error = fuse_vnode_size(vp, &filesize, td->td_ucred, td);
510                 if (error == 0)
511                         *runp = MIN(MAX(0, filesize / biosize - lbn - 1),
512                                     maxrun);
513                 else
514                         *runp = 0;
515         }
516
517         if (fsess_isimpl(mp, FUSE_BMAP)) {
518                 fdisp_init(&fdi, sizeof(*fbi));
519                 fdisp_make_vp(&fdi, FUSE_BMAP, vp, td, td->td_ucred);
520                 fbi = fdi.indata;
521                 fbi->block = lbn;
522                 fbi->blocksize = biosize;
523                 error = fdisp_wait_answ(&fdi);
524                 if (error == ENOSYS) {
525                         fdisp_destroy(&fdi);
526                         fsess_set_notimpl(mp, FUSE_BMAP);
527                         error = 0;
528                 } else {
529                         fbo = fdi.answ;
530                         if (error == 0 && pbn != NULL)
531                                 *pbn = fbo->block;
532                         fdisp_destroy(&fdi);
533                         return error;
534                 }
535         }
536
537         /* If the daemon doesn't support BMAP, make up a sensible default */
538         if (pbn != NULL)
539                 *pbn = lbn * btodb(biosize);
540         return (error);
541 }
542
543 /*
544     struct vop_close_args {
545         struct vnode *a_vp;
546         int  a_fflag;
547         struct ucred *a_cred;
548         struct thread *a_td;
549     };
550 */
551 static int
552 fuse_vnop_close(struct vop_close_args *ap)
553 {
554         struct vnode *vp = ap->a_vp;
555         struct ucred *cred = ap->a_cred;
556         int fflag = ap->a_fflag;
557         struct thread *td = ap->a_td;
558         pid_t pid = td->td_proc->p_pid;
559         int err = 0;
560
561         if (fuse_isdeadfs(vp))
562                 return 0;
563         if (vnode_isdir(vp))
564                 return 0;
565         if (fflag & IO_NDELAY)
566                 return 0;
567
568         err = fuse_flush(vp, cred, pid, fflag);
569         /* TODO: close the file handle, if we're sure it's no longer used */
570         if ((VTOFUD(vp)->flag & FN_SIZECHANGE) != 0) {
571                 fuse_vnode_savesize(vp, cred, td->td_proc->p_pid);
572         }
573         return err;
574 }
575
576 static void
577 fdisp_make_mknod_for_fallback(
578         struct fuse_dispatcher *fdip,
579         struct componentname *cnp,
580         struct vnode *dvp,
581         uint64_t parentnid,
582         struct thread *td,
583         struct ucred *cred,
584         mode_t mode,
585         enum fuse_opcode *op)
586 {
587         struct fuse_mknod_in *fmni;
588
589         fdisp_init(fdip, sizeof(*fmni) + cnp->cn_namelen + 1);
590         *op = FUSE_MKNOD;
591         fdisp_make(fdip, *op, vnode_mount(dvp), parentnid, td, cred);
592         fmni = fdip->indata;
593         fmni->mode = mode;
594         fmni->rdev = 0;
595         memcpy((char *)fdip->indata + sizeof(*fmni), cnp->cn_nameptr,
596             cnp->cn_namelen);
597         ((char *)fdip->indata)[sizeof(*fmni) + cnp->cn_namelen] = '\0';
598 }
599 /*
600     struct vnop_create_args {
601         struct vnode *a_dvp;
602         struct vnode **a_vpp;
603         struct componentname *a_cnp;
604         struct vattr *a_vap;
605     };
606 */
607 static int
608 fuse_vnop_create(struct vop_create_args *ap)
609 {
610         struct vnode *dvp = ap->a_dvp;
611         struct vnode **vpp = ap->a_vpp;
612         struct componentname *cnp = ap->a_cnp;
613         struct vattr *vap = ap->a_vap;
614         struct thread *td = cnp->cn_thread;
615         struct ucred *cred = cnp->cn_cred;
616
617         struct fuse_data *data;
618         struct fuse_create_in *fci;
619         struct fuse_entry_out *feo;
620         struct fuse_open_out *foo;
621         struct fuse_dispatcher fdi, fdi2;
622         struct fuse_dispatcher *fdip = &fdi;
623         struct fuse_dispatcher *fdip2 = NULL;
624
625         int err;
626
627         struct mount *mp = vnode_mount(dvp);
628         data = fuse_get_mpdata(mp);
629         uint64_t parentnid = VTOFUD(dvp)->nid;
630         mode_t mode = MAKEIMODE(vap->va_type, vap->va_mode);
631         enum fuse_opcode op;
632         int flags;
633
634         if (fuse_isdeadfs(dvp))
635                 return ENXIO;
636
637         /* FUSE expects sockets to be created with FUSE_MKNOD */
638         if (vap->va_type == VSOCK)
639                 return fuse_internal_mknod(dvp, vpp, cnp, vap);
640
641         /* 
642          * VOP_CREATE doesn't tell us the open(2) flags, so we guess.  Only a
643          * writable mode makes sense, and we might as well include readability
644          * too.
645          */
646         flags = O_RDWR;
647
648         bzero(&fdi, sizeof(fdi));
649
650         if (vap->va_type != VREG)
651                 return (EINVAL);
652
653         if (!fsess_isimpl(mp, FUSE_CREATE) || vap->va_type == VSOCK) {
654                 /* Fallback to FUSE_MKNOD/FUSE_OPEN */
655                 fdisp_make_mknod_for_fallback(fdip, cnp, dvp, parentnid, td,
656                         cred, mode, &op);
657         } else {
658                 /* Use FUSE_CREATE */
659                 size_t insize;
660
661                 op = FUSE_CREATE;
662                 fdisp_init(fdip, sizeof(*fci) + cnp->cn_namelen + 1);
663                 fdisp_make(fdip, op, vnode_mount(dvp), parentnid, td, cred);
664                 fci = fdip->indata;
665                 fci->mode = mode;
666                 fci->flags = O_CREAT | flags;
667                 if (fuse_libabi_geq(data, 7, 12)) {
668                         insize = sizeof(*fci);
669                         fci->umask = td->td_proc->p_fd->fd_cmask;
670                 } else {
671                         insize = sizeof(struct fuse_open_in);
672                 }
673
674                 memcpy((char *)fdip->indata + insize, cnp->cn_nameptr,
675                     cnp->cn_namelen);
676                 ((char *)fdip->indata)[insize + cnp->cn_namelen] = '\0';
677         }
678
679         err = fdisp_wait_answ(fdip);
680
681         if (err) {
682                 if (err == ENOSYS && op == FUSE_CREATE) {
683                         fsess_set_notimpl(mp, FUSE_CREATE);
684                         fdisp_destroy(fdip);
685                         fdisp_make_mknod_for_fallback(fdip, cnp, dvp,
686                                 parentnid, td, cred, mode, &op);
687                         err = fdisp_wait_answ(fdip);
688                 }
689                 if (err)
690                         goto out;
691         }
692
693         feo = fdip->answ;
694
695         if ((err = fuse_internal_checkentry(feo, vap->va_type))) {
696                 goto out;
697         }
698
699         if (op == FUSE_CREATE) {
700                 foo = (struct fuse_open_out*)(feo + 1);
701         } else {
702                 /* Issue a separate FUSE_OPEN */
703                 struct fuse_open_in *foi;
704
705                 fdip2 = &fdi2;
706                 fdisp_init(fdip2, sizeof(*foi));
707                 fdisp_make(fdip2, FUSE_OPEN, vnode_mount(dvp), feo->nodeid, td,
708                         cred);
709                 foi = fdip2->indata;
710                 foi->flags = flags;
711                 err = fdisp_wait_answ(fdip2);
712                 if (err)
713                         goto out;
714                 foo = fdip2->answ;
715         }
716         err = fuse_vnode_get(mp, feo, feo->nodeid, dvp, vpp, cnp, vap->va_type);
717         if (err) {
718                 struct fuse_release_in *fri;
719                 uint64_t nodeid = feo->nodeid;
720                 uint64_t fh_id = foo->fh;
721
722                 fdisp_init(fdip, sizeof(*fri));
723                 fdisp_make(fdip, FUSE_RELEASE, mp, nodeid, td, cred);
724                 fri = fdip->indata;
725                 fri->fh = fh_id;
726                 fri->flags = flags;
727                 fuse_insert_callback(fdip->tick, fuse_internal_forget_callback);
728                 fuse_insert_message(fdip->tick, false);
729                 goto out;
730         }
731         ASSERT_VOP_ELOCKED(*vpp, "fuse_vnop_create");
732         fuse_internal_cache_attrs(*vpp, &feo->attr, feo->attr_valid,
733                 feo->attr_valid_nsec, NULL);
734
735         fuse_filehandle_init(*vpp, FUFH_RDWR, NULL, td, cred, foo);
736         fuse_vnode_open(*vpp, foo->open_flags, td);
737         /* 
738          * Purge the parent's attribute cache because the daemon should've
739          * updated its mtime and ctime
740          */
741         fuse_vnode_clear_attr_cache(dvp);
742         cache_purge_negative(dvp);
743
744 out:
745         if (fdip2)
746                 fdisp_destroy(fdip2);
747         fdisp_destroy(fdip);
748         return err;
749 }
750
751 /*
752     struct vnop_fdatasync_args {
753         struct vop_generic_args a_gen;
754         struct vnode * a_vp;
755         struct thread * a_td;
756     };
757 */
758 static int
759 fuse_vnop_fdatasync(struct vop_fdatasync_args *ap)
760 {
761         struct vnode *vp = ap->a_vp;
762         struct thread *td = ap->a_td;
763         int waitfor = MNT_WAIT;
764
765         int err = 0;
766
767         if (fuse_isdeadfs(vp)) {
768                 return 0;
769         }
770         if ((err = vop_stdfdatasync_buf(ap)))
771                 return err;
772
773         return fuse_internal_fsync(vp, td, waitfor, true);
774 }
775
776 /*
777     struct vnop_fsync_args {
778         struct vop_generic_args a_gen;
779         struct vnode * a_vp;
780         int  a_waitfor;
781         struct thread * a_td;
782     };
783 */
784 static int
785 fuse_vnop_fsync(struct vop_fsync_args *ap)
786 {
787         struct vnode *vp = ap->a_vp;
788         struct thread *td = ap->a_td;
789         int waitfor = ap->a_waitfor;
790         int err = 0;
791
792         if (fuse_isdeadfs(vp)) {
793                 return 0;
794         }
795         if ((err = vop_stdfsync(ap)))
796                 return err;
797
798         return fuse_internal_fsync(vp, td, waitfor, false);
799 }
800
801 /*
802     struct vnop_getattr_args {
803         struct vnode *a_vp;
804         struct vattr *a_vap;
805         struct ucred *a_cred;
806         struct thread *a_td;
807     };
808 */
809 static int
810 fuse_vnop_getattr(struct vop_getattr_args *ap)
811 {
812         struct vnode *vp = ap->a_vp;
813         struct vattr *vap = ap->a_vap;
814         struct ucred *cred = ap->a_cred;
815         struct thread *td = curthread;
816
817         int err = 0;
818         int dataflags;
819
820         dataflags = fuse_get_mpdata(vnode_mount(vp))->dataflags;
821
822         /* Note that we are not bailing out on a dead file system just yet. */
823
824         if (!(dataflags & FSESS_INITED)) {
825                 if (!vnode_isvroot(vp)) {
826                         fdata_set_dead(fuse_get_mpdata(vnode_mount(vp)));
827                         err = ENOTCONN;
828                         return err;
829                 } else {
830                         goto fake;
831                 }
832         }
833         err = fuse_internal_getattr(vp, vap, cred, td);
834         if (err == ENOTCONN && vnode_isvroot(vp)) {
835                 /* see comment in fuse_vfsop_statfs() */
836                 goto fake;
837         } else {
838                 return err;
839         }
840
841 fake:
842         bzero(vap, sizeof(*vap));
843         vap->va_type = vnode_vtype(vp);
844
845         return 0;
846 }
847
848 /*
849     struct vnop_inactive_args {
850         struct vnode *a_vp;
851         struct thread *a_td;
852     };
853 */
854 static int
855 fuse_vnop_inactive(struct vop_inactive_args *ap)
856 {
857         struct vnode *vp = ap->a_vp;
858         struct thread *td = ap->a_td;
859
860         struct fuse_vnode_data *fvdat = VTOFUD(vp);
861         struct fuse_filehandle *fufh, *fufh_tmp;
862
863         int need_flush = 1;
864
865         LIST_FOREACH_SAFE(fufh, &fvdat->handles, next, fufh_tmp) {
866                 if (need_flush && vp->v_type == VREG) {
867                         if ((VTOFUD(vp)->flag & FN_SIZECHANGE) != 0) {
868                                 fuse_vnode_savesize(vp, NULL, 0);
869                         }
870                         if ((fvdat->flag & FN_REVOKED) != 0)
871                                 fuse_io_invalbuf(vp, td);
872                         else
873                                 fuse_io_flushbuf(vp, MNT_WAIT, td);
874                         need_flush = 0;
875                 }
876                 fuse_filehandle_close(vp, fufh, td, NULL);
877         }
878
879         if ((fvdat->flag & FN_REVOKED) != 0)
880                 vrecycle(vp);
881
882         return 0;
883 }
884
885 /*
886     struct vnop_link_args {
887         struct vnode *a_tdvp;
888         struct vnode *a_vp;
889         struct componentname *a_cnp;
890     };
891 */
892 static int
893 fuse_vnop_link(struct vop_link_args *ap)
894 {
895         struct vnode *vp = ap->a_vp;
896         struct vnode *tdvp = ap->a_tdvp;
897         struct componentname *cnp = ap->a_cnp;
898
899         struct vattr *vap = VTOVA(vp);
900
901         struct fuse_dispatcher fdi;
902         struct fuse_entry_out *feo;
903         struct fuse_link_in fli;
904
905         int err;
906
907         if (fuse_isdeadfs(vp)) {
908                 return ENXIO;
909         }
910         if (vnode_mount(tdvp) != vnode_mount(vp)) {
911                 return EXDEV;
912         }
913
914         /*
915          * This is a seatbelt check to protect naive userspace filesystems from
916          * themselves and the limitations of the FUSE IPC protocol.  If a
917          * filesystem does not allow attribute caching, assume it is capable of
918          * validating that nlink does not overflow.
919          */
920         if (vap != NULL && vap->va_nlink >= FUSE_LINK_MAX)
921                 return EMLINK;
922         fli.oldnodeid = VTOI(vp);
923
924         fdisp_init(&fdi, 0);
925         fuse_internal_newentry_makerequest(vnode_mount(tdvp), VTOI(tdvp), cnp,
926             FUSE_LINK, &fli, sizeof(fli), &fdi);
927         if ((err = fdisp_wait_answ(&fdi))) {
928                 goto out;
929         }
930         feo = fdi.answ;
931
932         err = fuse_internal_checkentry(feo, vnode_vtype(vp));
933         if (!err) {
934                 /* 
935                  * Purge the parent's attribute cache because the daemon
936                  * should've updated its mtime and ctime
937                  */
938                 fuse_vnode_clear_attr_cache(tdvp);
939                 fuse_internal_cache_attrs(vp, &feo->attr, feo->attr_valid,
940                         feo->attr_valid_nsec, NULL);
941         }
942 out:
943         fdisp_destroy(&fdi);
944         return err;
945 }
946
947 struct fuse_lookup_alloc_arg {
948         struct fuse_entry_out *feo;
949         struct componentname *cnp;
950         uint64_t nid;
951         enum vtype vtyp;
952 };
953
954 /* Callback for vn_get_ino */
955 static int
956 fuse_lookup_alloc(struct mount *mp, void *arg, int lkflags, struct vnode **vpp)
957 {
958         struct fuse_lookup_alloc_arg *flaa = arg;
959
960         return fuse_vnode_get(mp, flaa->feo, flaa->nid, NULL, vpp, flaa->cnp,
961                 flaa->vtyp);
962 }
963
964 SDT_PROBE_DEFINE3(fusefs, , vnops, cache_lookup,
965         "int", "struct timespec*", "struct timespec*");
966 /*
967     struct vnop_lookup_args {
968         struct vnodeop_desc *a_desc;
969         struct vnode *a_dvp;
970         struct vnode **a_vpp;
971         struct componentname *a_cnp;
972     };
973 */
974 int
975 fuse_vnop_lookup(struct vop_lookup_args *ap)
976 {
977         struct vnode *dvp = ap->a_dvp;
978         struct vnode **vpp = ap->a_vpp;
979         struct componentname *cnp = ap->a_cnp;
980         struct thread *td = cnp->cn_thread;
981         struct ucred *cred = cnp->cn_cred;
982
983         int nameiop = cnp->cn_nameiop;
984         int flags = cnp->cn_flags;
985         int wantparent = flags & (LOCKPARENT | WANTPARENT);
986         int islastcn = flags & ISLASTCN;
987         struct mount *mp = vnode_mount(dvp);
988
989         int err = 0;
990         int lookup_err = 0;
991         struct vnode *vp = NULL;
992
993         struct fuse_dispatcher fdi;
994         bool did_lookup = false;
995         struct fuse_entry_out *feo = NULL;
996         enum vtype vtyp;        /* vnode type of target */
997         off_t filesize;         /* filesize of target */
998
999         uint64_t nid;
1000
1001         if (fuse_isdeadfs(dvp)) {
1002                 *vpp = NULL;
1003                 return ENXIO;
1004         }
1005         if (!vnode_isdir(dvp))
1006                 return ENOTDIR;
1007
1008         if (islastcn && vfs_isrdonly(mp) && (nameiop != LOOKUP))
1009                 return EROFS;
1010
1011         if ((err = fuse_internal_access(dvp, VEXEC, td, cred)))
1012                 return err;
1013
1014         if (flags & ISDOTDOT) {
1015                 KASSERT(VTOFUD(dvp)->flag & FN_PARENT_NID,
1016                         ("Looking up .. is TODO"));
1017                 nid = VTOFUD(dvp)->parent_nid;
1018                 if (nid == 0)
1019                         return ENOENT;
1020                 /* .. is obviously a directory */
1021                 vtyp = VDIR;
1022                 filesize = 0;
1023         } else if (cnp->cn_namelen == 1 && *(cnp->cn_nameptr) == '.') {
1024                 nid = VTOI(dvp);
1025                 /* . is obviously a directory */
1026                 vtyp = VDIR;
1027                 filesize = 0;
1028         } else {
1029                 struct timespec now, timeout;
1030
1031                 err = cache_lookup(dvp, vpp, cnp, &timeout, NULL);
1032                 getnanouptime(&now);
1033                 SDT_PROBE3(fusefs, , vnops, cache_lookup, err, &timeout, &now);
1034                 switch (err) {
1035                 case -1:                /* positive match */
1036                         if (timespeccmp(&timeout, &now, >)) {
1037                                 counter_u64_add(fuse_lookup_cache_hits, 1);
1038                         } else {
1039                                 /* Cache timeout */
1040                                 counter_u64_add(fuse_lookup_cache_misses, 1);
1041                                 bintime_clear(
1042                                         &VTOFUD(*vpp)->entry_cache_timeout);
1043                                 cache_purge(*vpp);
1044                                 if (dvp != *vpp)
1045                                         vput(*vpp);
1046                                 else 
1047                                         vrele(*vpp);
1048                                 *vpp = NULL;
1049                                 break;
1050                         }
1051                         return 0;
1052
1053                 case 0:         /* no match in cache */
1054                         counter_u64_add(fuse_lookup_cache_misses, 1);
1055                         break;
1056
1057                 case ENOENT:            /* negative match */
1058                         getnanouptime(&now);
1059                         if (timespeccmp(&timeout, &now, <=)) {
1060                                 /* Cache timeout */
1061                                 cache_purge_negative(dvp);
1062                                 break;
1063                         }
1064                         /* fall through */
1065                 default:
1066                         return err;
1067                 }
1068
1069                 nid = VTOI(dvp);
1070                 fdisp_init(&fdi, cnp->cn_namelen + 1);
1071                 fdisp_make(&fdi, FUSE_LOOKUP, mp, nid, td, cred);
1072
1073                 memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
1074                 ((char *)fdi.indata)[cnp->cn_namelen] = '\0';
1075                 lookup_err = fdisp_wait_answ(&fdi);
1076                 did_lookup = true;
1077
1078                 if (!lookup_err) {
1079                         /* lookup call succeeded */
1080                         feo = (struct fuse_entry_out *)fdi.answ;
1081                         nid = feo->nodeid;
1082                         if (nid == 0) {
1083                                 /* zero nodeid means ENOENT and cache it */
1084                                 struct timespec timeout;
1085
1086                                 fdi.answ_stat = ENOENT;
1087                                 lookup_err = ENOENT;
1088                                 if (cnp->cn_flags & MAKEENTRY) {
1089                                         fuse_validity_2_timespec(feo, &timeout);
1090                                         cache_enter_time(dvp, *vpp, cnp,
1091                                                 &timeout, NULL);
1092                                 }
1093                         } else if (nid == FUSE_ROOT_ID) {
1094                                 lookup_err = EINVAL;
1095                         }
1096                         vtyp = IFTOVT(feo->attr.mode);
1097                         filesize = feo->attr.size;
1098                 }
1099                 if (lookup_err && (!fdi.answ_stat || lookup_err != ENOENT)) {
1100                         fdisp_destroy(&fdi);
1101                         return lookup_err;
1102                 }
1103         }
1104         /* lookup_err, if non-zero, must be ENOENT at this point */
1105
1106         if (lookup_err) {
1107                 /* Entry not found */
1108                 if ((nameiop == CREATE || nameiop == RENAME) && islastcn) {
1109                         err = fuse_internal_access(dvp, VWRITE, td, cred);
1110                         if (!err) {
1111                                 /*
1112                                  * Set the SAVENAME flag to hold onto the
1113                                  * pathname for use later in VOP_CREATE or
1114                                  * VOP_RENAME.
1115                                  */
1116                                 cnp->cn_flags |= SAVENAME;
1117
1118                                 err = EJUSTRETURN;
1119                         }
1120                 } else {
1121                         err = ENOENT;
1122                 }
1123         } else {
1124                 /* Entry was found */
1125                 if (flags & ISDOTDOT) {
1126                         struct fuse_lookup_alloc_arg flaa;
1127
1128                         flaa.nid = nid;
1129                         flaa.feo = feo;
1130                         flaa.cnp = cnp;
1131                         flaa.vtyp = vtyp;
1132                         err = vn_vget_ino_gen(dvp, fuse_lookup_alloc, &flaa, 0,
1133                                 &vp);
1134                         *vpp = vp;
1135                 } else if (nid == VTOI(dvp)) {
1136                         vref(dvp);
1137                         *vpp = dvp;
1138                 } else {
1139                         struct fuse_vnode_data *fvdat;
1140
1141                         err = fuse_vnode_get(vnode_mount(dvp), feo, nid, dvp,
1142                             &vp, cnp, vtyp);
1143                         if (err)
1144                                 goto out;
1145                         *vpp = vp;
1146
1147                         /*
1148                          * In the case where we are looking up a FUSE node
1149                          * represented by an existing cached vnode, and the
1150                          * true size reported by FUSE_LOOKUP doesn't match
1151                          * the vnode's cached size, then any cached writes
1152                          * beyond the file's current size are lost.
1153                          *
1154                          * We can get here:
1155                          * * following attribute cache expiration, or
1156                          * * due a bug in the daemon, or
1157                          */
1158                         fvdat = VTOFUD(vp);
1159                         if (vnode_isreg(vp) &&
1160                             filesize != fvdat->cached_attrs.va_size &&
1161                             fvdat->flag & FN_SIZECHANGE) {
1162                                 /*
1163                                  * The FN_SIZECHANGE flag reflects a dirty
1164                                  * append.  If userspace lets us know our cache
1165                                  * is invalid, that write was lost.  (Dirty
1166                                  * writes that do not cause append are also
1167                                  * lost, but we don't detect them here.)
1168                                  *
1169                                  * XXX: Maybe disable WB caching on this mount.
1170                                  */
1171                                 printf("%s: WB cache incoherent on %s!\n",
1172                                     __func__,
1173                                     vnode_mount(vp)->mnt_stat.f_mntonname);
1174
1175                                 fvdat->flag &= ~FN_SIZECHANGE;
1176                         }
1177
1178                         MPASS(feo != NULL);
1179                         fuse_internal_cache_attrs(*vpp, &feo->attr,
1180                                 feo->attr_valid, feo->attr_valid_nsec, NULL);
1181                         fuse_validity_2_bintime(feo->entry_valid,
1182                                 feo->entry_valid_nsec,
1183                                 &fvdat->entry_cache_timeout);
1184
1185                         if ((nameiop == DELETE || nameiop == RENAME) &&
1186                                 islastcn)
1187                         {
1188                                 struct vattr dvattr;
1189
1190                                 err = fuse_internal_access(dvp, VWRITE, td,
1191                                         cred);
1192                                 if (err != 0)
1193                                         goto out;
1194                                 /* 
1195                                  * if the parent's sticky bit is set, check
1196                                  * whether we're allowed to remove the file.
1197                                  * Need to figure out the vnode locking to make
1198                                  * this work.
1199                                  */
1200                                 fuse_internal_getattr(dvp, &dvattr, cred, td);
1201                                 if ((dvattr.va_mode & S_ISTXT) &&
1202                                         fuse_internal_access(dvp, VADMIN, td,
1203                                                 cred) &&
1204                                         fuse_internal_access(*vpp, VADMIN, td,
1205                                                 cred)) {
1206                                         err = EPERM;
1207                                         goto out;
1208                                 }
1209                         }
1210
1211                         if (islastcn && (
1212                                 (nameiop == DELETE) ||
1213                                 (nameiop == RENAME && wantparent))) {
1214                                 cnp->cn_flags |= SAVENAME;
1215                         }
1216
1217                 }
1218         }
1219 out:
1220         if (err) {
1221                 if (vp != NULL && dvp != vp)
1222                         vput(vp);
1223                 else if (vp != NULL)
1224                         vrele(vp);
1225                 *vpp = NULL;
1226         }
1227         if (did_lookup)
1228                 fdisp_destroy(&fdi);
1229
1230         return err;
1231 }
1232
1233 /*
1234     struct vnop_mkdir_args {
1235         struct vnode *a_dvp;
1236         struct vnode **a_vpp;
1237         struct componentname *a_cnp;
1238         struct vattr *a_vap;
1239     };
1240 */
1241 static int
1242 fuse_vnop_mkdir(struct vop_mkdir_args *ap)
1243 {
1244         struct vnode *dvp = ap->a_dvp;
1245         struct vnode **vpp = ap->a_vpp;
1246         struct componentname *cnp = ap->a_cnp;
1247         struct vattr *vap = ap->a_vap;
1248
1249         struct fuse_mkdir_in fmdi;
1250
1251         if (fuse_isdeadfs(dvp)) {
1252                 return ENXIO;
1253         }
1254         fmdi.mode = MAKEIMODE(vap->va_type, vap->va_mode);
1255         fmdi.umask = curthread->td_proc->p_fd->fd_cmask;
1256
1257         return (fuse_internal_newentry(dvp, vpp, cnp, FUSE_MKDIR, &fmdi,
1258             sizeof(fmdi), VDIR));
1259 }
1260
1261 /*
1262     struct vnop_mknod_args {
1263         struct vnode *a_dvp;
1264         struct vnode **a_vpp;
1265         struct componentname *a_cnp;
1266         struct vattr *a_vap;
1267     };
1268 */
1269 static int
1270 fuse_vnop_mknod(struct vop_mknod_args *ap)
1271 {
1272
1273         struct vnode *dvp = ap->a_dvp;
1274         struct vnode **vpp = ap->a_vpp;
1275         struct componentname *cnp = ap->a_cnp;
1276         struct vattr *vap = ap->a_vap;
1277
1278         if (fuse_isdeadfs(dvp))
1279                 return ENXIO;
1280
1281         return fuse_internal_mknod(dvp, vpp, cnp, vap);
1282 }
1283
1284 /*
1285     struct vop_open_args {
1286         struct vnode *a_vp;
1287         int  a_mode;
1288         struct ucred *a_cred;
1289         struct thread *a_td;
1290         int a_fdidx; / struct file *a_fp;
1291     };
1292 */
1293 static int
1294 fuse_vnop_open(struct vop_open_args *ap)
1295 {
1296         struct vnode *vp = ap->a_vp;
1297         int a_mode = ap->a_mode;
1298         struct thread *td = ap->a_td;
1299         struct ucred *cred = ap->a_cred;
1300         pid_t pid = td->td_proc->p_pid;
1301         struct fuse_vnode_data *fvdat;
1302
1303         if (fuse_isdeadfs(vp))
1304                 return ENXIO;
1305         if (vp->v_type == VCHR || vp->v_type == VBLK || vp->v_type == VFIFO)
1306                 return (EOPNOTSUPP);
1307         if ((a_mode & (FREAD | FWRITE | FEXEC)) == 0)
1308                 return EINVAL;
1309
1310         fvdat = VTOFUD(vp);
1311
1312         if (fuse_filehandle_validrw(vp, a_mode, cred, pid)) {
1313                 fuse_vnode_open(vp, 0, td);
1314                 return 0;
1315         }
1316
1317         return fuse_filehandle_open(vp, a_mode, NULL, td, cred);
1318 }
1319
1320 static int
1321 fuse_vnop_pathconf(struct vop_pathconf_args *ap)
1322 {
1323
1324         switch (ap->a_name) {
1325         case _PC_FILESIZEBITS:
1326                 *ap->a_retval = 64;
1327                 return (0);
1328         case _PC_NAME_MAX:
1329                 *ap->a_retval = NAME_MAX;
1330                 return (0);
1331         case _PC_LINK_MAX:
1332                 *ap->a_retval = MIN(LONG_MAX, FUSE_LINK_MAX);
1333                 return (0);
1334         case _PC_SYMLINK_MAX:
1335                 *ap->a_retval = MAXPATHLEN;
1336                 return (0);
1337         case _PC_NO_TRUNC:
1338                 *ap->a_retval = 1;
1339                 return (0);
1340         default:
1341                 return (vop_stdpathconf(ap));
1342         }
1343 }
1344
1345 /*
1346     struct vnop_read_args {
1347         struct vnode *a_vp;
1348         struct uio *a_uio;
1349         int  a_ioflag;
1350         struct ucred *a_cred;
1351     };
1352 */
1353 static int
1354 fuse_vnop_read(struct vop_read_args *ap)
1355 {
1356         struct vnode *vp = ap->a_vp;
1357         struct uio *uio = ap->a_uio;
1358         int ioflag = ap->a_ioflag;
1359         struct ucred *cred = ap->a_cred;
1360         pid_t pid = curthread->td_proc->p_pid;
1361
1362         if (fuse_isdeadfs(vp)) {
1363                 return ENXIO;
1364         }
1365
1366         if (VTOFUD(vp)->flag & FN_DIRECTIO) {
1367                 ioflag |= IO_DIRECT;
1368         }
1369
1370         return fuse_io_dispatch(vp, uio, ioflag, cred, pid);
1371 }
1372
1373 /*
1374     struct vnop_readdir_args {
1375         struct vnode *a_vp;
1376         struct uio *a_uio;
1377         struct ucred *a_cred;
1378         int *a_eofflag;
1379         int *a_ncookies;
1380         u_long **a_cookies;
1381     };
1382 */
1383 static int
1384 fuse_vnop_readdir(struct vop_readdir_args *ap)
1385 {
1386         struct vnode *vp = ap->a_vp;
1387         struct uio *uio = ap->a_uio;
1388         struct ucred *cred = ap->a_cred;
1389         struct fuse_filehandle *fufh = NULL;
1390         struct fuse_iov cookediov;
1391         int err = 0;
1392         u_long *cookies;
1393         off_t startoff;
1394         ssize_t tresid;
1395         int ncookies;
1396         bool closefufh = false;
1397         pid_t pid = curthread->td_proc->p_pid;
1398
1399         if (ap->a_eofflag)
1400                 *ap->a_eofflag = 0;
1401         if (fuse_isdeadfs(vp)) {
1402                 return ENXIO;
1403         }
1404         if (                            /* XXXIP ((uio_iovcnt(uio) > 1)) || */
1405             (uio_resid(uio) < sizeof(struct dirent))) {
1406                 return EINVAL;
1407         }
1408
1409         tresid = uio->uio_resid;
1410         startoff = uio->uio_offset;
1411         err = fuse_filehandle_get_dir(vp, &fufh, cred, pid);
1412         if (err == EBADF && vnode_mount(vp)->mnt_flag & MNT_EXPORTED) {
1413                 /* 
1414                  * nfsd will do VOP_READDIR without first doing VOP_OPEN.  We
1415                  * must implicitly open the directory here
1416                  */
1417                 err = fuse_filehandle_open(vp, FREAD, &fufh, curthread, cred);
1418                 if (err == 0) {
1419                         /*
1420                          * When a directory is opened, it must be read from
1421                          * the beginning.  Hopefully, the "startoff" still
1422                          * exists as an offset cookie for the directory.
1423                          * If not, it will read the entire directory without
1424                          * returning any entries and just return eof.
1425                          */
1426                         uio->uio_offset = 0;
1427                 }
1428                 closefufh = true;
1429         }
1430         if (err)
1431                 return (err);
1432         if (ap->a_ncookies != NULL) {
1433                 ncookies = uio->uio_resid /
1434                         (offsetof(struct dirent, d_name) + 4) + 1;
1435                 cookies = malloc(ncookies * sizeof(*cookies), M_TEMP, M_WAITOK);
1436                 *ap->a_ncookies = ncookies;
1437                 *ap->a_cookies = cookies;
1438         } else {
1439                 ncookies = 0;
1440                 cookies = NULL;
1441         }
1442 #define DIRCOOKEDSIZE FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + MAXNAMLEN + 1)
1443         fiov_init(&cookediov, DIRCOOKEDSIZE);
1444
1445         err = fuse_internal_readdir(vp, uio, startoff, fufh, &cookediov,
1446                 &ncookies, cookies);
1447
1448         fiov_teardown(&cookediov);
1449         if (closefufh)
1450                 fuse_filehandle_close(vp, fufh, curthread, cred);
1451
1452         if (ap->a_ncookies != NULL) {
1453                 if (err == 0) {
1454                         *ap->a_ncookies -= ncookies;
1455                 } else {
1456                         free(*ap->a_cookies, M_TEMP);
1457                         *ap->a_ncookies = 0;
1458                         *ap->a_cookies = NULL;
1459                 }
1460         }
1461         if (err == 0 && tresid == uio->uio_resid)
1462                 *ap->a_eofflag = 1;
1463
1464         return err;
1465 }
1466
1467 /*
1468     struct vnop_readlink_args {
1469         struct vnode *a_vp;
1470         struct uio *a_uio;
1471         struct ucred *a_cred;
1472     };
1473 */
1474 static int
1475 fuse_vnop_readlink(struct vop_readlink_args *ap)
1476 {
1477         struct vnode *vp = ap->a_vp;
1478         struct uio *uio = ap->a_uio;
1479         struct ucred *cred = ap->a_cred;
1480
1481         struct fuse_dispatcher fdi;
1482         int err;
1483
1484         if (fuse_isdeadfs(vp)) {
1485                 return ENXIO;
1486         }
1487         if (!vnode_islnk(vp)) {
1488                 return EINVAL;
1489         }
1490         fdisp_init(&fdi, 0);
1491         err = fdisp_simple_putget_vp(&fdi, FUSE_READLINK, vp, curthread, cred);
1492         if (err) {
1493                 goto out;
1494         }
1495         if (((char *)fdi.answ)[0] == '/' &&
1496             fuse_get_mpdata(vnode_mount(vp))->dataflags & FSESS_PUSH_SYMLINKS_IN) {
1497                 char *mpth = vnode_mount(vp)->mnt_stat.f_mntonname;
1498
1499                 err = uiomove(mpth, strlen(mpth), uio);
1500         }
1501         if (!err) {
1502                 err = uiomove(fdi.answ, fdi.iosize, uio);
1503         }
1504 out:
1505         fdisp_destroy(&fdi);
1506         return err;
1507 }
1508
1509 /*
1510     struct vnop_reclaim_args {
1511         struct vnode *a_vp;
1512         struct thread *a_td;
1513     };
1514 */
1515 static int
1516 fuse_vnop_reclaim(struct vop_reclaim_args *ap)
1517 {
1518         struct vnode *vp = ap->a_vp;
1519         struct thread *td = ap->a_td;
1520         struct fuse_vnode_data *fvdat = VTOFUD(vp);
1521         struct fuse_filehandle *fufh, *fufh_tmp;
1522
1523         if (!fvdat) {
1524                 panic("FUSE: no vnode data during recycling");
1525         }
1526         LIST_FOREACH_SAFE(fufh, &fvdat->handles, next, fufh_tmp) {
1527                 printf("FUSE: vnode being reclaimed with open fufh "
1528                         "(type=%#x)", fufh->fufh_type);
1529                 fuse_filehandle_close(vp, fufh, td, NULL);
1530         }
1531
1532         if ((!fuse_isdeadfs(vp)) && (fvdat->nlookup)) {
1533                 fuse_internal_forget_send(vnode_mount(vp), td, NULL, VTOI(vp),
1534                     fvdat->nlookup);
1535         }
1536         fuse_vnode_setparent(vp, NULL);
1537         cache_purge(vp);
1538         vfs_hash_remove(vp);
1539         vnode_destroy_vobject(vp);
1540         fuse_vnode_destroy(vp);
1541
1542         return 0;
1543 }
1544
1545 /*
1546     struct vnop_remove_args {
1547         struct vnode *a_dvp;
1548         struct vnode *a_vp;
1549         struct componentname *a_cnp;
1550     };
1551 */
1552 static int
1553 fuse_vnop_remove(struct vop_remove_args *ap)
1554 {
1555         struct vnode *dvp = ap->a_dvp;
1556         struct vnode *vp = ap->a_vp;
1557         struct componentname *cnp = ap->a_cnp;
1558
1559         int err;
1560
1561         if (fuse_isdeadfs(vp)) {
1562                 return ENXIO;
1563         }
1564         if (vnode_isdir(vp)) {
1565                 return EPERM;
1566         }
1567
1568         err = fuse_internal_remove(dvp, vp, cnp, FUSE_UNLINK);
1569
1570         return err;
1571 }
1572
1573 /*
1574     struct vnop_rename_args {
1575         struct vnode *a_fdvp;
1576         struct vnode *a_fvp;
1577         struct componentname *a_fcnp;
1578         struct vnode *a_tdvp;
1579         struct vnode *a_tvp;
1580         struct componentname *a_tcnp;
1581     };
1582 */
1583 static int
1584 fuse_vnop_rename(struct vop_rename_args *ap)
1585 {
1586         struct vnode *fdvp = ap->a_fdvp;
1587         struct vnode *fvp = ap->a_fvp;
1588         struct componentname *fcnp = ap->a_fcnp;
1589         struct vnode *tdvp = ap->a_tdvp;
1590         struct vnode *tvp = ap->a_tvp;
1591         struct componentname *tcnp = ap->a_tcnp;
1592         struct fuse_data *data;
1593         bool newparent = fdvp != tdvp;
1594         bool isdir = fvp->v_type == VDIR;
1595         int err = 0;
1596
1597         if (fuse_isdeadfs(fdvp)) {
1598                 return ENXIO;
1599         }
1600         if (fvp->v_mount != tdvp->v_mount ||
1601             (tvp && fvp->v_mount != tvp->v_mount)) {
1602                 SDT_PROBE2(fusefs, , vnops, trace, 1, "cross-device rename");
1603                 err = EXDEV;
1604                 goto out;
1605         }
1606         cache_purge(fvp);
1607
1608         /*
1609          * FUSE library is expected to check if target directory is not
1610          * under the source directory in the file system tree.
1611          * Linux performs this check at VFS level.
1612          */
1613         /* 
1614          * If source is a directory, and it will get a new parent, user must
1615          * have write permission to it, so ".." can be modified.
1616          */
1617         data = fuse_get_mpdata(vnode_mount(tdvp));
1618         if (data->dataflags & FSESS_DEFAULT_PERMISSIONS && isdir && newparent) {
1619                 err = fuse_internal_access(fvp, VWRITE,
1620                         tcnp->cn_thread, tcnp->cn_cred);
1621                 if (err)
1622                         goto out;
1623         }
1624         sx_xlock(&data->rename_lock);
1625         err = fuse_internal_rename(fdvp, fcnp, tdvp, tcnp);
1626         if (err == 0) {
1627                 if (tdvp != fdvp)
1628                         fuse_vnode_setparent(fvp, tdvp);
1629                 if (tvp != NULL)
1630                         fuse_vnode_setparent(tvp, NULL);
1631         }
1632         sx_unlock(&data->rename_lock);
1633
1634         if (tvp != NULL && tvp != fvp) {
1635                 cache_purge(tvp);
1636         }
1637         if (vnode_isdir(fvp)) {
1638                 if ((tvp != NULL) && vnode_isdir(tvp)) {
1639                         cache_purge(tdvp);
1640                 }
1641                 cache_purge(fdvp);
1642         }
1643 out:
1644         if (tdvp == tvp) {
1645                 vrele(tdvp);
1646         } else {
1647                 vput(tdvp);
1648         }
1649         if (tvp != NULL) {
1650                 vput(tvp);
1651         }
1652         vrele(fdvp);
1653         vrele(fvp);
1654
1655         return err;
1656 }
1657
1658 /*
1659     struct vnop_rmdir_args {
1660             struct vnode *a_dvp;
1661             struct vnode *a_vp;
1662             struct componentname *a_cnp;
1663     } *ap;
1664 */
1665 static int
1666 fuse_vnop_rmdir(struct vop_rmdir_args *ap)
1667 {
1668         struct vnode *dvp = ap->a_dvp;
1669         struct vnode *vp = ap->a_vp;
1670
1671         int err;
1672
1673         if (fuse_isdeadfs(vp)) {
1674                 return ENXIO;
1675         }
1676         if (VTOFUD(vp) == VTOFUD(dvp)) {
1677                 return EINVAL;
1678         }
1679         err = fuse_internal_remove(dvp, vp, ap->a_cnp, FUSE_RMDIR);
1680
1681         return err;
1682 }
1683
1684 /*
1685     struct vnop_setattr_args {
1686         struct vnode *a_vp;
1687         struct vattr *a_vap;
1688         struct ucred *a_cred;
1689         struct thread *a_td;
1690     };
1691 */
1692 static int
1693 fuse_vnop_setattr(struct vop_setattr_args *ap)
1694 {
1695         struct vnode *vp = ap->a_vp;
1696         struct vattr *vap = ap->a_vap;
1697         struct ucred *cred = ap->a_cred;
1698         struct thread *td = curthread;
1699         struct mount *mp;
1700         struct fuse_data *data;
1701         struct vattr old_va;
1702         int dataflags;
1703         int err = 0, err2;
1704         accmode_t accmode = 0;
1705         bool checkperm;
1706         bool drop_suid = false;
1707         gid_t cr_gid;
1708
1709         mp = vnode_mount(vp);
1710         data = fuse_get_mpdata(mp);
1711         dataflags = data->dataflags;
1712         checkperm = dataflags & FSESS_DEFAULT_PERMISSIONS;
1713         if (cred->cr_ngroups > 0)
1714                 cr_gid = cred->cr_groups[0];
1715         else
1716                 cr_gid = 0;
1717
1718         if (fuse_isdeadfs(vp)) {
1719                 return ENXIO;
1720         }
1721
1722         if (vap->va_uid != (uid_t)VNOVAL) {
1723                 if (checkperm) {
1724                         /* Only root may change a file's owner */
1725                         err = priv_check_cred(cred, PRIV_VFS_CHOWN);
1726                         if (err) {
1727                                 /* As a special case, allow the null chown */
1728                                 err2 = fuse_internal_getattr(vp, &old_va, cred,
1729                                         td);
1730                                 if (err2)
1731                                         return (err2);
1732                                 if (vap->va_uid != old_va.va_uid)
1733                                         return err;
1734                                 else
1735                                         accmode |= VADMIN;
1736                                 drop_suid = true;
1737                         } else
1738                                 accmode |= VADMIN;
1739                 } else
1740                         accmode |= VADMIN;
1741         }
1742         if (vap->va_gid != (gid_t)VNOVAL) {
1743                 if (checkperm && priv_check_cred(cred, PRIV_VFS_CHOWN))
1744                         drop_suid = true;
1745                 if (checkperm && !groupmember(vap->va_gid, cred))
1746                 {
1747                         /*
1748                          * Non-root users may only chgrp to one of their own
1749                          * groups 
1750                          */
1751                         err = priv_check_cred(cred, PRIV_VFS_CHOWN);
1752                         if (err) {
1753                                 /* As a special case, allow the null chgrp */
1754                                 err2 = fuse_internal_getattr(vp, &old_va, cred,
1755                                         td);
1756                                 if (err2)
1757                                         return (err2);
1758                                 if (vap->va_gid != old_va.va_gid)
1759                                         return err;
1760                                 accmode |= VADMIN;
1761                         } else
1762                                 accmode |= VADMIN;
1763                 } else
1764                         accmode |= VADMIN;
1765         }
1766         if (vap->va_size != VNOVAL) {
1767                 switch (vp->v_type) {
1768                 case VDIR:
1769                         return (EISDIR);
1770                 case VLNK:
1771                 case VREG:
1772                         if (vfs_isrdonly(mp))
1773                                 return (EROFS);
1774                         break;
1775                 default:
1776                         /*
1777                          * According to POSIX, the result is unspecified
1778                          * for file types other than regular files,
1779                          * directories and shared memory objects.  We
1780                          * don't support shared memory objects in the file
1781                          * system, and have dubious support for truncating
1782                          * symlinks.  Just ignore the request in other cases.
1783                          */
1784                         return (0);
1785                 }
1786                 /* Don't set accmode.  Permission to trunc is checked upstack */
1787         }
1788         if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
1789                 if (vap->va_vaflags & VA_UTIMES_NULL)
1790                         accmode |= VWRITE;
1791                 else
1792                         accmode |= VADMIN;
1793         }
1794         if (drop_suid) {
1795                 if (vap->va_mode != (mode_t)VNOVAL)
1796                         vap->va_mode &= ~(S_ISUID | S_ISGID);
1797                 else {
1798                         err = fuse_internal_getattr(vp, &old_va, cred, td);
1799                         if (err)
1800                                 return (err);
1801                         vap->va_mode = old_va.va_mode & ~(S_ISUID | S_ISGID);
1802                 }
1803         }
1804         if (vap->va_mode != (mode_t)VNOVAL) {
1805                 /* Only root may set the sticky bit on non-directories */
1806                 if (checkperm && vp->v_type != VDIR && (vap->va_mode & S_ISTXT)
1807                     && priv_check_cred(cred, PRIV_VFS_STICKYFILE))
1808                         return EFTYPE;
1809                 if (checkperm && (vap->va_mode & S_ISGID)) {
1810                         err = fuse_internal_getattr(vp, &old_va, cred, td);
1811                         if (err)
1812                                 return (err);
1813                         if (!groupmember(old_va.va_gid, cred)) {
1814                                 err = priv_check_cred(cred, PRIV_VFS_SETGID);
1815                                 if (err)
1816                                         return (err);
1817                         }
1818                 }
1819                 accmode |= VADMIN;
1820         }
1821
1822         if (vfs_isrdonly(mp))
1823                 return EROFS;
1824
1825         err = fuse_internal_access(vp, accmode, td, cred);
1826         if (err)
1827                 return err;
1828         else
1829                 return fuse_internal_setattr(vp, vap, td, cred);
1830 }
1831
1832 /*
1833     struct vnop_strategy_args {
1834         struct vnode *a_vp;
1835         struct buf *a_bp;
1836     };
1837 */
1838 static int
1839 fuse_vnop_strategy(struct vop_strategy_args *ap)
1840 {
1841         struct vnode *vp = ap->a_vp;
1842         struct buf *bp = ap->a_bp;
1843
1844         if (!vp || fuse_isdeadfs(vp)) {
1845                 bp->b_ioflags |= BIO_ERROR;
1846                 bp->b_error = ENXIO;
1847                 bufdone(bp);
1848                 return 0;
1849         }
1850
1851         /*
1852          * VOP_STRATEGY always returns zero and signals error via bp->b_ioflags.
1853          * fuse_io_strategy sets bp's error fields
1854          */
1855         (void)fuse_io_strategy(vp, bp);
1856
1857         return 0;
1858 }
1859
1860
1861 /*
1862     struct vnop_symlink_args {
1863         struct vnode *a_dvp;
1864         struct vnode **a_vpp;
1865         struct componentname *a_cnp;
1866         struct vattr *a_vap;
1867         char *a_target;
1868     };
1869 */
1870 static int
1871 fuse_vnop_symlink(struct vop_symlink_args *ap)
1872 {
1873         struct vnode *dvp = ap->a_dvp;
1874         struct vnode **vpp = ap->a_vpp;
1875         struct componentname *cnp = ap->a_cnp;
1876         const char *target = ap->a_target;
1877
1878         struct fuse_dispatcher fdi;
1879
1880         int err;
1881         size_t len;
1882
1883         if (fuse_isdeadfs(dvp)) {
1884                 return ENXIO;
1885         }
1886         /*
1887          * Unlike the other creator type calls, here we have to create a message
1888          * where the name of the new entry comes first, and the data describing
1889          * the entry comes second.
1890          * Hence we can't rely on our handy fuse_internal_newentry() routine,
1891          * but put together the message manually and just call the core part.
1892          */
1893
1894         len = strlen(target) + 1;
1895         fdisp_init(&fdi, len + cnp->cn_namelen + 1);
1896         fdisp_make_vp(&fdi, FUSE_SYMLINK, dvp, curthread, NULL);
1897
1898         memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
1899         ((char *)fdi.indata)[cnp->cn_namelen] = '\0';
1900         memcpy((char *)fdi.indata + cnp->cn_namelen + 1, target, len);
1901
1902         err = fuse_internal_newentry_core(dvp, vpp, cnp, VLNK, &fdi);
1903         fdisp_destroy(&fdi);
1904         return err;
1905 }
1906
1907 /*
1908     struct vnop_write_args {
1909         struct vnode *a_vp;
1910         struct uio *a_uio;
1911         int  a_ioflag;
1912         struct ucred *a_cred;
1913     };
1914 */
1915 static int
1916 fuse_vnop_write(struct vop_write_args *ap)
1917 {
1918         struct vnode *vp = ap->a_vp;
1919         struct uio *uio = ap->a_uio;
1920         int ioflag = ap->a_ioflag;
1921         struct ucred *cred = ap->a_cred;
1922         pid_t pid = curthread->td_proc->p_pid;
1923
1924         if (fuse_isdeadfs(vp)) {
1925                 return ENXIO;
1926         }
1927
1928         if (VTOFUD(vp)->flag & FN_DIRECTIO) {
1929                 ioflag |= IO_DIRECT;
1930         }
1931
1932         return fuse_io_dispatch(vp, uio, ioflag, cred, pid);
1933 }
1934
1935 static daddr_t
1936 fuse_gbp_getblkno(struct vnode *vp, vm_ooffset_t off)
1937 {
1938         const int biosize = fuse_iosize(vp);
1939
1940         return (off / biosize);
1941 }
1942
1943 static int
1944 fuse_gbp_getblksz(struct vnode *vp, daddr_t lbn)
1945 {
1946         off_t filesize;
1947         int blksz, err;
1948         const int biosize = fuse_iosize(vp);
1949
1950         err = fuse_vnode_size(vp, &filesize, NULL, NULL);
1951         KASSERT(err == 0, ("vfs_bio_getpages can't handle errors here"));
1952         if (err)
1953                 return biosize;
1954
1955         if ((off_t)lbn * biosize >= filesize) {
1956                 blksz = 0;
1957         } else if ((off_t)(lbn + 1) * biosize > filesize) {
1958                 blksz = filesize - (off_t)lbn *biosize;
1959         } else {
1960                 blksz = biosize;
1961         }
1962         return (blksz);
1963 }
1964
1965 /*
1966     struct vnop_getpages_args {
1967         struct vnode *a_vp;
1968         vm_page_t *a_m;
1969         int a_count;
1970         int a_reqpage;
1971     };
1972 */
1973 static int
1974 fuse_vnop_getpages(struct vop_getpages_args *ap)
1975 {
1976         struct vnode *vp = ap->a_vp;
1977
1978         if (!fsess_opt_mmap(vnode_mount(vp))) {
1979                 SDT_PROBE2(fusefs, , vnops, trace, 1,
1980                         "called on non-cacheable vnode??\n");
1981                 return (VM_PAGER_ERROR);
1982         }
1983
1984         return (vfs_bio_getpages(vp, ap->a_m, ap->a_count, ap->a_rbehind,
1985             ap->a_rahead, fuse_gbp_getblkno, fuse_gbp_getblksz));
1986 }
1987
1988 static const char extattr_namespace_separator = '.';
1989
1990 /*
1991     struct vop_getextattr_args {
1992         struct vop_generic_args a_gen;
1993         struct vnode *a_vp;
1994         int a_attrnamespace;
1995         const char *a_name;
1996         struct uio *a_uio;
1997         size_t *a_size;
1998         struct ucred *a_cred;
1999         struct thread *a_td;
2000     };
2001 */
2002 static int
2003 fuse_vnop_getextattr(struct vop_getextattr_args *ap)
2004 {
2005         struct vnode *vp = ap->a_vp;
2006         struct uio *uio = ap->a_uio;
2007         struct fuse_dispatcher fdi;
2008         struct fuse_getxattr_in *get_xattr_in;
2009         struct fuse_getxattr_out *get_xattr_out;
2010         struct mount *mp = vnode_mount(vp);
2011         struct thread *td = ap->a_td;
2012         struct ucred *cred = ap->a_cred;
2013         char *prefix;
2014         char *attr_str;
2015         size_t len;
2016         int err;
2017
2018         if (fuse_isdeadfs(vp))
2019                 return (ENXIO);
2020
2021         if (!fsess_isimpl(mp, FUSE_GETXATTR))
2022                 return EOPNOTSUPP;
2023
2024         err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td, VREAD);
2025         if (err)
2026                 return err;
2027
2028         /* Default to looking for user attributes. */
2029         if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
2030                 prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
2031         else
2032                 prefix = EXTATTR_NAMESPACE_USER_STRING;
2033
2034         len = strlen(prefix) + sizeof(extattr_namespace_separator) +
2035             strlen(ap->a_name) + 1;
2036
2037         fdisp_init(&fdi, len + sizeof(*get_xattr_in));
2038         fdisp_make_vp(&fdi, FUSE_GETXATTR, vp, td, cred);
2039
2040         get_xattr_in = fdi.indata;
2041         /*
2042          * Check to see whether we're querying the available size or
2043          * issuing the actual request.  If we pass in 0, we get back struct
2044          * fuse_getxattr_out.  If we pass in a non-zero size, we get back
2045          * that much data, without the struct fuse_getxattr_out header.
2046          */
2047         if (uio == NULL)
2048                 get_xattr_in->size = 0;
2049         else
2050                 get_xattr_in->size = uio->uio_resid;
2051
2052         attr_str = (char *)fdi.indata + sizeof(*get_xattr_in);
2053         snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator,
2054             ap->a_name);
2055
2056         err = fdisp_wait_answ(&fdi);
2057         if (err != 0) {
2058                 if (err == ENOSYS) {
2059                         fsess_set_notimpl(mp, FUSE_GETXATTR);
2060                         err = EOPNOTSUPP;
2061                 }
2062                 goto out;
2063         }
2064
2065         get_xattr_out = fdi.answ;
2066
2067         if (ap->a_size != NULL)
2068                 *ap->a_size = get_xattr_out->size;
2069
2070         if (uio != NULL)
2071                 err = uiomove(fdi.answ, fdi.iosize, uio);
2072
2073 out:
2074         fdisp_destroy(&fdi);
2075         return (err);
2076 }
2077
2078 /*
2079     struct vop_setextattr_args {
2080         struct vop_generic_args a_gen;
2081         struct vnode *a_vp;
2082         int a_attrnamespace;
2083         const char *a_name;
2084         struct uio *a_uio;
2085         struct ucred *a_cred;
2086         struct thread *a_td;
2087     };
2088 */
2089 static int
2090 fuse_vnop_setextattr(struct vop_setextattr_args *ap)
2091 {
2092         struct vnode *vp = ap->a_vp;
2093         struct uio *uio = ap->a_uio;
2094         struct fuse_dispatcher fdi;
2095         struct fuse_setxattr_in *set_xattr_in;
2096         struct mount *mp = vnode_mount(vp);
2097         struct thread *td = ap->a_td;
2098         struct ucred *cred = ap->a_cred;
2099         char *prefix;
2100         size_t len;
2101         char *attr_str;
2102         int err;
2103         
2104         if (fuse_isdeadfs(vp))
2105                 return (ENXIO);
2106
2107         if (!fsess_isimpl(mp, FUSE_SETXATTR))
2108                 return EOPNOTSUPP;
2109
2110         if (vfs_isrdonly(mp))
2111                 return EROFS;
2112
2113         /* Deleting xattrs must use VOP_DELETEEXTATTR instead */
2114         if (ap->a_uio == NULL) {
2115                 /*
2116                  * If we got here as fallback from VOP_DELETEEXTATTR, then
2117                  * return EOPNOTSUPP.
2118                  */
2119                 if (!fsess_isimpl(mp, FUSE_REMOVEXATTR))
2120                         return (EOPNOTSUPP);
2121                 else
2122                         return (EINVAL);
2123         }
2124
2125         err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td,
2126                 VWRITE);
2127         if (err)
2128                 return err;
2129
2130         /* Default to looking for user attributes. */
2131         if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
2132                 prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
2133         else
2134                 prefix = EXTATTR_NAMESPACE_USER_STRING;
2135
2136         len = strlen(prefix) + sizeof(extattr_namespace_separator) +
2137             strlen(ap->a_name) + 1;
2138
2139         fdisp_init(&fdi, len + sizeof(*set_xattr_in) + uio->uio_resid);
2140         fdisp_make_vp(&fdi, FUSE_SETXATTR, vp, td, cred);
2141
2142         set_xattr_in = fdi.indata;
2143         set_xattr_in->size = uio->uio_resid;
2144
2145         attr_str = (char *)fdi.indata + sizeof(*set_xattr_in);
2146         snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator,
2147             ap->a_name);
2148
2149         err = uiomove((char *)fdi.indata + sizeof(*set_xattr_in) + len,
2150             uio->uio_resid, uio);
2151         if (err != 0) {
2152                 goto out;
2153         }
2154
2155         err = fdisp_wait_answ(&fdi);
2156
2157         if (err == ENOSYS) {
2158                 fsess_set_notimpl(mp, FUSE_SETXATTR);
2159                 err = EOPNOTSUPP;
2160         }
2161         if (err == ERESTART) {
2162                 /* Can't restart after calling uiomove */
2163                 err = EINTR;
2164         }
2165
2166 out:
2167         fdisp_destroy(&fdi);
2168         return (err);
2169 }
2170
2171 /*
2172  * The Linux / FUSE extended attribute list is simply a collection of
2173  * NUL-terminated strings.  The FreeBSD extended attribute list is a single
2174  * byte length followed by a non-NUL terminated string.  So, this allows
2175  * conversion of the Linux / FUSE format to the FreeBSD format in place.
2176  * Linux attribute names are reported with the namespace as a prefix (e.g.
2177  * "user.attribute_name"), but in FreeBSD they are reported without the
2178  * namespace prefix (e.g. "attribute_name").  So, we're going from:
2179  *
2180  * user.attr_name1\0user.attr_name2\0
2181  *
2182  * to:
2183  *
2184  * <num>attr_name1<num>attr_name2
2185  *
2186  * Where "<num>" is a single byte number of characters in the attribute name.
2187  * 
2188  * Args:
2189  * prefix - exattr namespace prefix string
2190  * list, list_len - input list with namespace prefixes
2191  * bsd_list, bsd_list_len - output list compatible with bsd vfs
2192  */
2193 static int
2194 fuse_xattrlist_convert(char *prefix, const char *list, int list_len,
2195     char *bsd_list, int *bsd_list_len)
2196 {
2197         int len, pos, dist_to_next, prefix_len;
2198
2199         pos = 0;
2200         *bsd_list_len = 0;
2201         prefix_len = strlen(prefix);
2202
2203         while (pos < list_len && list[pos] != '\0') {
2204                 dist_to_next = strlen(&list[pos]) + 1;
2205                 if (bcmp(&list[pos], prefix, prefix_len) == 0 &&
2206                     list[pos + prefix_len] == extattr_namespace_separator) {
2207                         len = dist_to_next -
2208                             (prefix_len + sizeof(extattr_namespace_separator)) - 1;
2209                         if (len >= EXTATTR_MAXNAMELEN)
2210                                 return (ENAMETOOLONG);
2211
2212                         bsd_list[*bsd_list_len] = len;
2213                         memcpy(&bsd_list[*bsd_list_len + 1],
2214                             &list[pos + prefix_len +
2215                             sizeof(extattr_namespace_separator)], len);
2216
2217                         *bsd_list_len += len + 1;
2218                 }
2219
2220                 pos += dist_to_next;
2221         }
2222
2223         return (0);
2224 }
2225
2226 /*
2227     struct vop_listextattr_args {
2228         struct vop_generic_args a_gen;
2229         struct vnode *a_vp;
2230         int a_attrnamespace;
2231         struct uio *a_uio;
2232         size_t *a_size;
2233         struct ucred *a_cred;
2234         struct thread *a_td;
2235     };
2236 */
2237 static int
2238 fuse_vnop_listextattr(struct vop_listextattr_args *ap)
2239 {
2240         struct vnode *vp = ap->a_vp;
2241         struct uio *uio = ap->a_uio;
2242         struct fuse_dispatcher fdi;
2243         struct fuse_listxattr_in *list_xattr_in;
2244         struct fuse_listxattr_out *list_xattr_out;
2245         struct mount *mp = vnode_mount(vp);
2246         struct thread *td = ap->a_td;
2247         struct ucred *cred = ap->a_cred;
2248         size_t len;
2249         char *prefix;
2250         char *attr_str;
2251         char *bsd_list = NULL;
2252         char *linux_list;
2253         int bsd_list_len;
2254         int linux_list_len;
2255         int err;
2256
2257         if (fuse_isdeadfs(vp))
2258                 return (ENXIO);
2259
2260         if (!fsess_isimpl(mp, FUSE_LISTXATTR))
2261                 return EOPNOTSUPP;
2262
2263         err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td, VREAD);
2264         if (err)
2265                 return err;
2266
2267         /*
2268          * Add space for a NUL and the period separator if enabled.
2269          * Default to looking for user attributes.
2270          */
2271         if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
2272                 prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
2273         else
2274                 prefix = EXTATTR_NAMESPACE_USER_STRING;
2275
2276         len = strlen(prefix) + sizeof(extattr_namespace_separator) + 1;
2277
2278         fdisp_init(&fdi, sizeof(*list_xattr_in) + len);
2279         fdisp_make_vp(&fdi, FUSE_LISTXATTR, vp, td, cred);
2280
2281         /*
2282          * Retrieve Linux / FUSE compatible list size.
2283          */
2284         list_xattr_in = fdi.indata;
2285         list_xattr_in->size = 0;
2286         attr_str = (char *)fdi.indata + sizeof(*list_xattr_in);
2287         snprintf(attr_str, len, "%s%c", prefix, extattr_namespace_separator);
2288
2289         err = fdisp_wait_answ(&fdi);
2290         if (err != 0) {
2291                 if (err == ENOSYS) {
2292                         fsess_set_notimpl(mp, FUSE_LISTXATTR);
2293                         err = EOPNOTSUPP;
2294                 }
2295                 goto out;
2296         }
2297
2298         list_xattr_out = fdi.answ;
2299         linux_list_len = list_xattr_out->size;
2300         if (linux_list_len == 0) {
2301                 if (ap->a_size != NULL)
2302                         *ap->a_size = linux_list_len;
2303                 goto out;
2304         }
2305
2306         /*
2307          * Retrieve Linux / FUSE compatible list values.
2308          */
2309         fdisp_refresh_vp(&fdi, FUSE_LISTXATTR, vp, td, cred);
2310         list_xattr_in = fdi.indata;
2311         list_xattr_in->size = linux_list_len + sizeof(*list_xattr_out);
2312         attr_str = (char *)fdi.indata + sizeof(*list_xattr_in);
2313         snprintf(attr_str, len, "%s%c", prefix, extattr_namespace_separator);
2314
2315         err = fdisp_wait_answ(&fdi);
2316         if (err != 0)
2317                 goto out;
2318
2319         linux_list = fdi.answ;
2320         linux_list_len = fdi.iosize;
2321
2322         /*
2323          * Retrieve the BSD compatible list values.
2324          * The Linux / FUSE attribute list format isn't the same
2325          * as FreeBSD's format. So we need to transform it into
2326          * FreeBSD's format before giving it to the user.
2327          */
2328         bsd_list = malloc(linux_list_len, M_TEMP, M_WAITOK);
2329         err = fuse_xattrlist_convert(prefix, linux_list, linux_list_len,
2330             bsd_list, &bsd_list_len);
2331         if (err != 0)
2332                 goto out;
2333
2334         if (ap->a_size != NULL)
2335                 *ap->a_size = bsd_list_len;
2336
2337         if (uio != NULL)
2338                 err = uiomove(bsd_list, bsd_list_len, uio);
2339
2340 out:
2341         free(bsd_list, M_TEMP);
2342         fdisp_destroy(&fdi);
2343         return (err);
2344 }
2345
2346 /*
2347     struct vop_deleteextattr_args {
2348         struct vop_generic_args a_gen;
2349         struct vnode *a_vp;
2350         int a_attrnamespace;
2351         const char *a_name;
2352         struct ucred *a_cred;
2353         struct thread *a_td;
2354     };
2355 */
2356 static int
2357 fuse_vnop_deleteextattr(struct vop_deleteextattr_args *ap)
2358 {
2359         struct vnode *vp = ap->a_vp;
2360         struct fuse_dispatcher fdi;
2361         struct mount *mp = vnode_mount(vp);
2362         struct thread *td = ap->a_td;
2363         struct ucred *cred = ap->a_cred;
2364         char *prefix;
2365         size_t len;
2366         char *attr_str;
2367         int err;
2368
2369         if (fuse_isdeadfs(vp))
2370                 return (ENXIO);
2371
2372         if (!fsess_isimpl(mp, FUSE_REMOVEXATTR))
2373                 return EOPNOTSUPP;
2374
2375         if (vfs_isrdonly(mp))
2376                 return EROFS;
2377
2378         err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td,
2379                 VWRITE);
2380         if (err)
2381                 return err;
2382
2383         /* Default to looking for user attributes. */
2384         if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
2385                 prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
2386         else
2387                 prefix = EXTATTR_NAMESPACE_USER_STRING;
2388
2389         len = strlen(prefix) + sizeof(extattr_namespace_separator) +
2390             strlen(ap->a_name) + 1;
2391
2392         fdisp_init(&fdi, len);
2393         fdisp_make_vp(&fdi, FUSE_REMOVEXATTR, vp, td, cred);
2394
2395         attr_str = fdi.indata;
2396         snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator,
2397             ap->a_name);
2398
2399         err = fdisp_wait_answ(&fdi);
2400         if (err == ENOSYS) {
2401                 fsess_set_notimpl(mp, FUSE_REMOVEXATTR);
2402                 err = EOPNOTSUPP;
2403         }
2404
2405         fdisp_destroy(&fdi);
2406         return (err);
2407 }
2408
2409 /*
2410     struct vnop_print_args {
2411         struct vnode *a_vp;
2412     };
2413 */
2414 static int
2415 fuse_vnop_print(struct vop_print_args *ap)
2416 {
2417         struct fuse_vnode_data *fvdat = VTOFUD(ap->a_vp);
2418
2419         printf("nodeid: %ju, parent nodeid: %ju, nlookup: %ju, flag: %#x\n",
2420             (uintmax_t)VTOILLU(ap->a_vp), (uintmax_t)fvdat->parent_nid,
2421             (uintmax_t)fvdat->nlookup,
2422             fvdat->flag);
2423
2424         return 0;
2425 }
2426         
2427 /*
2428  * Get an NFS filehandle for a FUSE file.
2429  *
2430  * This will only work for FUSE file systems that guarantee the uniqueness of
2431  * nodeid:generation, which most don't.
2432  */
2433 /*
2434 vop_vptofh {
2435         IN struct vnode *a_vp;
2436         IN struct fid *a_fhp;
2437 };
2438 */
2439 static int
2440 fuse_vnop_vptofh(struct vop_vptofh_args *ap)
2441 {
2442         struct vnode *vp = ap->a_vp;
2443         struct fuse_vnode_data *fvdat = VTOFUD(vp);
2444         struct fuse_fid *fhp = (struct fuse_fid *)(ap->a_fhp);
2445         _Static_assert(sizeof(struct fuse_fid) <= sizeof(struct fid),
2446                 "FUSE fid type is too big");
2447         struct mount *mp = vnode_mount(vp);
2448         struct fuse_data *data = fuse_get_mpdata(mp);
2449         struct vattr va;
2450         int err;
2451
2452         if (!(data->dataflags & FSESS_EXPORT_SUPPORT))
2453                 return EOPNOTSUPP;
2454
2455         err = fuse_internal_getattr(vp, &va, curthread->td_ucred, curthread);
2456         if (err)
2457                 return err;
2458
2459         /*ip = VTOI(ap->a_vp);*/
2460         /*ufhp = (struct ufid *)ap->a_fhp;*/
2461         fhp->len = sizeof(struct fuse_fid);
2462         fhp->nid = fvdat->nid;
2463         if (fvdat->generation <= UINT32_MAX)
2464                 fhp->gen = fvdat->generation;
2465         else
2466                 return EOVERFLOW;
2467         return (0);
2468 }
2469
2470