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