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