]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/fuse/fuse_vnops.c
fusefs: use vn_vget_ino_gen in fuse_vnop_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 struct fuse_lookup_alloc_arg {
708         struct fuse_entry_out *feo;
709         struct componentname *cnp;
710         uint64_t nid;
711         enum vtype vtyp;
712 };
713
714 /* Callback for vn_get_ino */
715 static int
716 fuse_lookup_alloc(struct mount *mp, void *arg, int lkflags, struct vnode **vpp)
717 {
718         struct fuse_lookup_alloc_arg *flaa = arg;
719
720         return fuse_vnode_get(mp, flaa->feo, flaa->nid, NULL, vpp, flaa->cnp,
721                 flaa->vtyp);
722 }
723
724 SDT_PROBE_DEFINE3(fuse, , vnops, cache_lookup,
725         "int", "struct timespec*", "struct timespec*");
726 /*
727     struct vnop_lookup_args {
728         struct vnodeop_desc *a_desc;
729         struct vnode *a_dvp;
730         struct vnode **a_vpp;
731         struct componentname *a_cnp;
732     };
733 */
734 int
735 fuse_vnop_lookup(struct vop_lookup_args *ap)
736 {
737         struct vnode *dvp = ap->a_dvp;
738         struct vnode **vpp = ap->a_vpp;
739         struct componentname *cnp = ap->a_cnp;
740         struct thread *td = cnp->cn_thread;
741         struct ucred *cred = cnp->cn_cred;
742
743         int nameiop = cnp->cn_nameiop;
744         int flags = cnp->cn_flags;
745         int wantparent = flags & (LOCKPARENT | WANTPARENT);
746         int islastcn = flags & ISLASTCN;
747         struct mount *mp = vnode_mount(dvp);
748
749         int err = 0;
750         int lookup_err = 0;
751         struct vnode *vp = NULL;
752
753         struct fuse_dispatcher fdi;
754         bool did_lookup = false;
755         struct fuse_entry_out *feo = NULL;
756         enum vtype vtyp;        /* vnode type of target */
757         off_t filesize;         /* filesize of target */
758
759         uint64_t nid;
760
761         if (fuse_isdeadfs(dvp)) {
762                 *vpp = NULL;
763                 return ENXIO;
764         }
765         if (!vnode_isdir(dvp))
766                 return ENOTDIR;
767
768         if (islastcn && vfs_isrdonly(mp) && (nameiop != LOOKUP))
769                 return EROFS;
770
771         if ((err = fuse_internal_access(dvp, VEXEC, td, cred)))
772                 return err;
773
774         if (flags & ISDOTDOT) {
775                 nid = VTOFUD(dvp)->parent_nid;
776                 if (nid == 0)
777                         return ENOENT;
778                 /* .. is obviously a directory */
779                 vtyp = VDIR;
780                 filesize = 0;
781         } else if (cnp->cn_namelen == 1 && *(cnp->cn_nameptr) == '.') {
782                 nid = VTOI(dvp);
783                 /* . is obviously a directory */
784                 vtyp = VDIR;
785                 filesize = 0;
786         } else {
787                 struct timespec now, timeout;
788
789                 err = cache_lookup(dvp, vpp, cnp, &timeout, NULL);
790                 getnanouptime(&now);
791                 SDT_PROBE3(fuse, , vnops, cache_lookup, err, &timeout, &now);
792                 switch (err) {
793                 case -1:                /* positive match */
794                         if (timespeccmp(&timeout, &now, >)) {
795                                 atomic_add_acq_long(&fuse_lookup_cache_hits, 1);
796                         } else {
797                                 /* Cache timeout */
798                                 atomic_add_acq_long(&fuse_lookup_cache_misses,
799                                         1);
800                                 fuse_internal_vnode_disappear(*vpp);
801                                 if (dvp != *vpp)
802                                         vput(*vpp);
803                                 else 
804                                         vrele(*vpp);
805                                 *vpp = NULL;
806                                 break;
807                         }
808                         return 0;
809
810                 case 0:         /* no match in cache */
811                         atomic_add_acq_long(&fuse_lookup_cache_misses, 1);
812                         break;
813
814                 case ENOENT:            /* negative match */
815                         getnanouptime(&now);
816                         if (timespeccmp(&timeout, &now, <=)) {
817                                 /* Cache timeout */
818                                 cache_purge_negative(dvp);
819                                 break;
820                         }
821                         /* fall through */
822                 default:
823                         return err;
824                 }
825
826                 nid = VTOI(dvp);
827                 fdisp_init(&fdi, cnp->cn_namelen + 1);
828                 fdisp_make(&fdi, FUSE_LOOKUP, mp, nid, td, cred);
829
830                 memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
831                 ((char *)fdi.indata)[cnp->cn_namelen] = '\0';
832                 lookup_err = fdisp_wait_answ(&fdi);
833                 did_lookup = true;
834
835                 if (!lookup_err) {
836                         /* lookup call succeeded */
837                         nid = ((struct fuse_entry_out *)fdi.answ)->nodeid;
838                         feo = (struct fuse_entry_out *)fdi.answ;
839                         if (nid == 0) {
840                                 /* zero nodeid means ENOENT and cache it */
841                                 struct timespec timeout;
842
843                                 fdi.answ_stat = ENOENT;
844                                 lookup_err = ENOENT;
845                                 if (cnp->cn_flags & MAKEENTRY) {
846                                         fuse_validity_2_timespec(feo, &timeout);
847                                         cache_enter_time(dvp, *vpp, cnp,
848                                                 &timeout, NULL);
849                                 }
850                         } else if (nid == FUSE_ROOT_ID) {
851                                 lookup_err = EINVAL;
852                         }
853                         vtyp = IFTOVT(feo->attr.mode);
854                         filesize = feo->attr.size;
855                 }
856                 if (lookup_err && (!fdi.answ_stat || lookup_err != ENOENT)) {
857                         fdisp_destroy(&fdi);
858                         return lookup_err;
859                 }
860         }
861         /* lookup_err, if non-zero, must be ENOENT at this point */
862
863         if (lookup_err) {
864                 /* Entry not found */
865                 if ((nameiop == CREATE || nameiop == RENAME) && islastcn) {
866                         err = fuse_internal_access(dvp, VWRITE, td, cred);
867                         if (err)
868                                 goto out;
869
870                         /*
871                          * Set the SAVENAME flag to hold onto the
872                          * pathname for use later in VOP_CREATE or VOP_RENAME.
873                          */
874                         cnp->cn_flags |= SAVENAME;
875
876                         err = EJUSTRETURN;
877                         goto out;
878                 }
879
880                 err = ENOENT;
881                 goto out;
882
883         } else {
884                 /* Entry was found */
885                 if ((nameiop == DELETE || nameiop == RENAME) && islastcn) {
886                         err = fuse_internal_access(dvp, VWRITE, td, cred);
887                         if (err != 0)
888                                 goto out;
889                         /* 
890                          * TODO: if the parent's sticky bit is set, check
891                          * whether we're allowed to remove the file.
892                          * Need to figure out the vnode locking to make this
893                          * work.
894                          */
895 #if defined(NOT_YET)
896                         struct vattr dvattr;
897                         fuse_internal_getattr(dvp, &dvattr, cred, td);
898                         if ((dvattr.va_mode & S_ISTXT) &&
899                                 fuse_internal_access(dvp, VADMIN, td, cred) &&
900                                 fuse_internal_access(*vpp, VADMIN, td, cred)) {
901                                 err = EPERM;
902                                 goto out;
903                         }
904 #endif
905                 }
906
907                 /*
908                  * If deleting, and at end of pathname, return parameters
909                  * which can be used to remove file.  If the wantparent flag
910                  * isn't set, we return only the directory, otherwise we go on
911                  * and lock the inode, being careful with ".".
912                  */
913                 if (nameiop == DELETE && islastcn) {
914                         if (nid == VTOI(dvp)) {
915                                 vref(dvp);
916                                 *vpp = dvp;
917                         } else {
918                                 err = fuse_vnode_get(dvp->v_mount, feo, nid,
919                                     dvp, &vp, cnp, vtyp);
920                                 if (err)
921                                         goto out;
922                                 *vpp = vp;
923                         }
924
925                         /*
926                          * Save the name for use in VOP_RMDIR and VOP_REMOVE
927                          * later.
928                          */
929                         cnp->cn_flags |= SAVENAME;
930                         goto out;
931
932                 }
933                 /*
934                  * If rewriting (RENAME), return the inode and the
935                  * information required to rewrite the present directory
936                  * Must get inode of directory entry to verify it's a
937                  * regular file, or empty directory.
938                  */
939                 if (nameiop == RENAME && wantparent && islastcn) {
940                         /*
941                          * Check for "."
942                          */
943                         if (nid == VTOI(dvp)) {
944                                 err = EISDIR;
945                                 goto out;
946                         }
947                         err = fuse_vnode_get(vnode_mount(dvp), feo, nid, dvp,
948                             &vp, cnp, vtyp);
949                         if (err) {
950                                 goto out;
951                         }
952                         *vpp = vp;
953                         /*
954                          * Save the name for use in VOP_RENAME later.
955                          */
956                         cnp->cn_flags |= SAVENAME;
957
958                         goto out;
959                 }
960                 if (flags & ISDOTDOT) {
961                         struct fuse_lookup_alloc_arg flaa;
962
963                         flaa.nid = nid;
964                         flaa.feo = feo;
965                         flaa.cnp = cnp;
966                         flaa.vtyp = vtyp;
967                         err = vn_vget_ino_gen(dvp, fuse_lookup_alloc, &flaa, 0,
968                                 &vp);
969                         if (err)
970                                 goto out;
971                         *vpp = vp;
972                 } else if (nid == VTOI(dvp)) {
973                         vref(dvp);
974                         *vpp = dvp;
975                 } else {
976                         struct fuse_vnode_data *fvdat;
977
978                         err = fuse_vnode_get(vnode_mount(dvp), feo, nid, dvp,
979                             &vp, cnp, vtyp);
980                         if (err) {
981                                 goto out;
982                         }
983                         fuse_vnode_setparent(vp, dvp);
984
985                         /*
986                          * In the case where we are looking up a FUSE node
987                          * represented by an existing cached vnode, and the
988                          * true size reported by FUSE_LOOKUP doesn't match
989                          * the vnode's cached size, fix the vnode cache to
990                          * match the real object size.
991                          *
992                          * This can occur via FUSE distributed filesystems,
993                          * irregular files, etc.
994                          */
995                         fvdat = VTOFUD(vp);
996                         if (vnode_isreg(vp) &&
997                             filesize != fvdat->filesize) {
998                                 /*
999                                  * The FN_SIZECHANGE flag reflects a dirty
1000                                  * append.  If userspace lets us know our cache
1001                                  * is invalid, that write was lost.  (Dirty
1002                                  * writes that do not cause append are also
1003                                  * lost, but we don't detect them here.)
1004                                  *
1005                                  * XXX: Maybe disable WB caching on this mount.
1006                                  */
1007                                 if (fvdat->flag & FN_SIZECHANGE)
1008                                         printf("%s: WB cache incoherent on "
1009                                             "%s!\n", __func__,
1010                                             vnode_mount(vp)->mnt_stat.f_mntonname);
1011
1012                                 (void)fuse_vnode_setsize(vp, cred, filesize);
1013                                 fvdat->flag &= ~FN_SIZECHANGE;
1014                         }
1015                         *vpp = vp;
1016                 }
1017
1018                 if (feo != NULL) {
1019                         fuse_internal_cache_attrs(*vpp, &feo->attr,
1020                                 feo->attr_valid, feo->attr_valid_nsec, NULL);
1021                 }
1022         }
1023 out:
1024         if (!lookup_err) {
1025
1026                 /* No lookup error; need to clean up. */
1027
1028                 if (err) {              /* Found inode; exit with no vnode. */
1029                         if (feo != NULL) {
1030                                 fuse_internal_forget_send(vnode_mount(dvp), td,
1031                                         cred, nid, 1);
1032                         }
1033                         if (did_lookup)
1034                                 fdisp_destroy(&fdi);
1035                         return err;
1036                 }
1037         }
1038         if (did_lookup)
1039                 fdisp_destroy(&fdi);
1040
1041         return err;
1042 }
1043
1044 /*
1045     struct vnop_mkdir_args {
1046         struct vnode *a_dvp;
1047         struct vnode **a_vpp;
1048         struct componentname *a_cnp;
1049         struct vattr *a_vap;
1050     };
1051 */
1052 static int
1053 fuse_vnop_mkdir(struct vop_mkdir_args *ap)
1054 {
1055         struct vnode *dvp = ap->a_dvp;
1056         struct vnode **vpp = ap->a_vpp;
1057         struct componentname *cnp = ap->a_cnp;
1058         struct vattr *vap = ap->a_vap;
1059
1060         struct fuse_mkdir_in fmdi;
1061
1062         if (fuse_isdeadfs(dvp)) {
1063                 return ENXIO;
1064         }
1065         fmdi.mode = MAKEIMODE(vap->va_type, vap->va_mode);
1066
1067         return (fuse_internal_newentry(dvp, vpp, cnp, FUSE_MKDIR, &fmdi,
1068             sizeof(fmdi), VDIR));
1069 }
1070
1071 /*
1072     struct vnop_mknod_args {
1073         struct vnode *a_dvp;
1074         struct vnode **a_vpp;
1075         struct componentname *a_cnp;
1076         struct vattr *a_vap;
1077     };
1078 */
1079 static int
1080 fuse_vnop_mknod(struct vop_mknod_args *ap)
1081 {
1082
1083         struct vnode *dvp = ap->a_dvp;
1084         struct vnode **vpp = ap->a_vpp;
1085         struct componentname *cnp = ap->a_cnp;
1086         struct vattr *vap = ap->a_vap;
1087         struct fuse_mknod_in fmni;
1088
1089         if (fuse_isdeadfs(dvp))
1090                 return ENXIO;
1091
1092         fmni.mode = MAKEIMODE(vap->va_type, vap->va_mode);
1093         fmni.rdev = vap->va_rdev;
1094         return (fuse_internal_newentry(dvp, vpp, cnp, FUSE_MKNOD, &fmni,
1095             sizeof(fmni), vap->va_type));
1096 }
1097
1098 /*
1099     struct vnop_open_args {
1100         struct vnode *a_vp;
1101         int  a_mode;
1102         struct ucred *a_cred;
1103         struct thread *a_td;
1104         int a_fdidx; / struct file *a_fp;
1105     };
1106 */
1107 static int
1108 fuse_vnop_open(struct vop_open_args *ap)
1109 {
1110         struct vnode *vp = ap->a_vp;
1111         int a_mode = ap->a_mode;
1112         struct thread *td = ap->a_td;
1113         struct ucred *cred = ap->a_cred;
1114         pid_t pid = td->td_proc->p_pid;
1115         struct fuse_vnode_data *fvdat;
1116
1117         if (fuse_isdeadfs(vp))
1118                 return ENXIO;
1119         if (vp->v_type == VCHR || vp->v_type == VBLK || vp->v_type == VFIFO)
1120                 return (EOPNOTSUPP);
1121         if ((a_mode & (FREAD | FWRITE | FEXEC)) == 0)
1122                 return EINVAL;
1123
1124         fvdat = VTOFUD(vp);
1125
1126         if (fuse_filehandle_validrw(vp, a_mode, cred, pid)) {
1127                 fuse_vnode_open(vp, 0, td);
1128                 return 0;
1129         }
1130
1131         return fuse_filehandle_open(vp, a_mode, NULL, td, cred);
1132 }
1133
1134 static int
1135 fuse_vnop_pathconf(struct vop_pathconf_args *ap)
1136 {
1137
1138         switch (ap->a_name) {
1139         case _PC_FILESIZEBITS:
1140                 *ap->a_retval = 64;
1141                 return (0);
1142         case _PC_NAME_MAX:
1143                 *ap->a_retval = NAME_MAX;
1144                 return (0);
1145         case _PC_LINK_MAX:
1146                 *ap->a_retval = MIN(LONG_MAX, FUSE_LINK_MAX);
1147                 return (0);
1148         case _PC_SYMLINK_MAX:
1149                 *ap->a_retval = MAXPATHLEN;
1150                 return (0);
1151         case _PC_NO_TRUNC:
1152                 *ap->a_retval = 1;
1153                 return (0);
1154         default:
1155                 return (vop_stdpathconf(ap));
1156         }
1157 }
1158
1159 /*
1160     struct vnop_read_args {
1161         struct vnode *a_vp;
1162         struct uio *a_uio;
1163         int  a_ioflag;
1164         struct ucred *a_cred;
1165     };
1166 */
1167 static int
1168 fuse_vnop_read(struct vop_read_args *ap)
1169 {
1170         struct vnode *vp = ap->a_vp;
1171         struct uio *uio = ap->a_uio;
1172         int ioflag = ap->a_ioflag;
1173         struct ucred *cred = ap->a_cred;
1174         pid_t pid = curthread->td_proc->p_pid;
1175
1176         if (fuse_isdeadfs(vp)) {
1177                 return ENXIO;
1178         }
1179
1180         if (VTOFUD(vp)->flag & FN_DIRECTIO) {
1181                 ioflag |= IO_DIRECT;
1182         }
1183
1184         return fuse_io_dispatch(vp, uio, ioflag, cred, pid);
1185 }
1186
1187 /*
1188     struct vnop_readdir_args {
1189         struct vnode *a_vp;
1190         struct uio *a_uio;
1191         struct ucred *a_cred;
1192         int *a_eofflag;
1193         int *ncookies;
1194         u_long **a_cookies;
1195     };
1196 */
1197 static int
1198 fuse_vnop_readdir(struct vop_readdir_args *ap)
1199 {
1200         struct vnode *vp = ap->a_vp;
1201         struct uio *uio = ap->a_uio;
1202         struct ucred *cred = ap->a_cred;
1203         struct fuse_filehandle *fufh = NULL;
1204         struct fuse_iov cookediov;
1205         int err = 0;
1206         pid_t pid = curthread->td_proc->p_pid;
1207
1208         if (fuse_isdeadfs(vp)) {
1209                 return ENXIO;
1210         }
1211         if (                            /* XXXIP ((uio_iovcnt(uio) > 1)) || */
1212             (uio_resid(uio) < sizeof(struct dirent))) {
1213                 return EINVAL;
1214         }
1215
1216         err = fuse_filehandle_get_dir(vp, &fufh, cred, pid);
1217         if (err)
1218                 return (err);
1219 #define DIRCOOKEDSIZE FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + MAXNAMLEN + 1)
1220         fiov_init(&cookediov, DIRCOOKEDSIZE);
1221
1222         err = fuse_internal_readdir(vp, uio, fufh, &cookediov);
1223
1224         fiov_teardown(&cookediov);
1225
1226         return err;
1227 }
1228
1229 /*
1230     struct vnop_readlink_args {
1231         struct vnode *a_vp;
1232         struct uio *a_uio;
1233         struct ucred *a_cred;
1234     };
1235 */
1236 static int
1237 fuse_vnop_readlink(struct vop_readlink_args *ap)
1238 {
1239         struct vnode *vp = ap->a_vp;
1240         struct uio *uio = ap->a_uio;
1241         struct ucred *cred = ap->a_cred;
1242
1243         struct fuse_dispatcher fdi;
1244         int err;
1245
1246         if (fuse_isdeadfs(vp)) {
1247                 return ENXIO;
1248         }
1249         if (!vnode_islnk(vp)) {
1250                 return EINVAL;
1251         }
1252         fdisp_init(&fdi, 0);
1253         err = fdisp_simple_putget_vp(&fdi, FUSE_READLINK, vp, curthread, cred);
1254         if (err) {
1255                 goto out;
1256         }
1257         if (((char *)fdi.answ)[0] == '/' &&
1258             fuse_get_mpdata(vnode_mount(vp))->dataflags & FSESS_PUSH_SYMLINKS_IN) {
1259                 char *mpth = vnode_mount(vp)->mnt_stat.f_mntonname;
1260
1261                 err = uiomove(mpth, strlen(mpth), uio);
1262         }
1263         if (!err) {
1264                 err = uiomove(fdi.answ, fdi.iosize, uio);
1265         }
1266 out:
1267         fdisp_destroy(&fdi);
1268         return err;
1269 }
1270
1271 /*
1272     struct vnop_reclaim_args {
1273         struct vnode *a_vp;
1274         struct thread *a_td;
1275     };
1276 */
1277 static int
1278 fuse_vnop_reclaim(struct vop_reclaim_args *ap)
1279 {
1280         struct vnode *vp = ap->a_vp;
1281         struct thread *td = ap->a_td;
1282         struct fuse_vnode_data *fvdat = VTOFUD(vp);
1283         struct fuse_filehandle *fufh, *fufh_tmp;
1284
1285         if (!fvdat) {
1286                 panic("FUSE: no vnode data during recycling");
1287         }
1288         LIST_FOREACH_SAFE(fufh, &fvdat->handles, next, fufh_tmp) {
1289                 printf("FUSE: vnode being reclaimed with open fufh "
1290                         "(type=%#x)", fufh->fufh_type);
1291                 fuse_filehandle_close(vp, fufh, td, NULL);
1292         }
1293
1294         if ((!fuse_isdeadfs(vp)) && (fvdat->nlookup)) {
1295                 fuse_internal_forget_send(vnode_mount(vp), td, NULL, VTOI(vp),
1296                     fvdat->nlookup);
1297         }
1298         fuse_vnode_setparent(vp, NULL);
1299         cache_purge(vp);
1300         vfs_hash_remove(vp);
1301         vnode_destroy_vobject(vp);
1302         fuse_vnode_destroy(vp);
1303
1304         return 0;
1305 }
1306
1307 /*
1308     struct vnop_remove_args {
1309         struct vnode *a_dvp;
1310         struct vnode *a_vp;
1311         struct componentname *a_cnp;
1312     };
1313 */
1314 static int
1315 fuse_vnop_remove(struct vop_remove_args *ap)
1316 {
1317         struct vnode *dvp = ap->a_dvp;
1318         struct vnode *vp = ap->a_vp;
1319         struct componentname *cnp = ap->a_cnp;
1320
1321         int err;
1322
1323         if (fuse_isdeadfs(vp)) {
1324                 return ENXIO;
1325         }
1326         if (vnode_isdir(vp)) {
1327                 return EPERM;
1328         }
1329         cache_purge(vp);
1330
1331         err = fuse_internal_remove(dvp, vp, cnp, FUSE_UNLINK);
1332
1333         if (err == 0)
1334                 fuse_internal_vnode_disappear(vp);
1335         return err;
1336 }
1337
1338 /*
1339     struct vnop_rename_args {
1340         struct vnode *a_fdvp;
1341         struct vnode *a_fvp;
1342         struct componentname *a_fcnp;
1343         struct vnode *a_tdvp;
1344         struct vnode *a_tvp;
1345         struct componentname *a_tcnp;
1346     };
1347 */
1348 static int
1349 fuse_vnop_rename(struct vop_rename_args *ap)
1350 {
1351         struct vnode *fdvp = ap->a_fdvp;
1352         struct vnode *fvp = ap->a_fvp;
1353         struct componentname *fcnp = ap->a_fcnp;
1354         struct vnode *tdvp = ap->a_tdvp;
1355         struct vnode *tvp = ap->a_tvp;
1356         struct componentname *tcnp = ap->a_tcnp;
1357         struct fuse_data *data;
1358
1359         int err = 0;
1360
1361         if (fuse_isdeadfs(fdvp)) {
1362                 return ENXIO;
1363         }
1364         if (fvp->v_mount != tdvp->v_mount ||
1365             (tvp && fvp->v_mount != tvp->v_mount)) {
1366                 SDT_PROBE2(fuse, , vnops, trace, 1, "cross-device rename");
1367                 err = EXDEV;
1368                 goto out;
1369         }
1370         cache_purge(fvp);
1371
1372         /*
1373          * FUSE library is expected to check if target directory is not
1374          * under the source directory in the file system tree.
1375          * Linux performs this check at VFS level.
1376          */
1377         data = fuse_get_mpdata(vnode_mount(tdvp));
1378         sx_xlock(&data->rename_lock);
1379         err = fuse_internal_rename(fdvp, fcnp, tdvp, tcnp);
1380         if (err == 0) {
1381                 if (tdvp != fdvp)
1382                         fuse_vnode_setparent(fvp, tdvp);
1383                 if (tvp != NULL)
1384                         fuse_vnode_setparent(tvp, NULL);
1385         }
1386         sx_unlock(&data->rename_lock);
1387
1388         if (tvp != NULL && tvp != fvp) {
1389                 cache_purge(tvp);
1390         }
1391         if (vnode_isdir(fvp)) {
1392                 if ((tvp != NULL) && vnode_isdir(tvp)) {
1393                         cache_purge(tdvp);
1394                 }
1395                 cache_purge(fdvp);
1396         }
1397 out:
1398         if (tdvp == tvp) {
1399                 vrele(tdvp);
1400         } else {
1401                 vput(tdvp);
1402         }
1403         if (tvp != NULL) {
1404                 vput(tvp);
1405         }
1406         vrele(fdvp);
1407         vrele(fvp);
1408
1409         return err;
1410 }
1411
1412 /*
1413     struct vnop_rmdir_args {
1414             struct vnode *a_dvp;
1415             struct vnode *a_vp;
1416             struct componentname *a_cnp;
1417     } *ap;
1418 */
1419 static int
1420 fuse_vnop_rmdir(struct vop_rmdir_args *ap)
1421 {
1422         struct vnode *dvp = ap->a_dvp;
1423         struct vnode *vp = ap->a_vp;
1424
1425         int err;
1426
1427         if (fuse_isdeadfs(vp)) {
1428                 return ENXIO;
1429         }
1430         if (VTOFUD(vp) == VTOFUD(dvp)) {
1431                 return EINVAL;
1432         }
1433         err = fuse_internal_remove(dvp, vp, ap->a_cnp, FUSE_RMDIR);
1434
1435         if (err == 0)
1436                 fuse_internal_vnode_disappear(vp);
1437         return err;
1438 }
1439
1440 /*
1441     struct vnop_setattr_args {
1442         struct vnode *a_vp;
1443         struct vattr *a_vap;
1444         struct ucred *a_cred;
1445         struct thread *a_td;
1446     };
1447 */
1448 static int
1449 fuse_vnop_setattr(struct vop_setattr_args *ap)
1450 {
1451         struct vnode *vp = ap->a_vp;
1452         struct vattr *vap = ap->a_vap;
1453         struct ucred *cred = ap->a_cred;
1454         struct thread *td = curthread;
1455         struct fuse_dispatcher fdi;
1456         struct fuse_setattr_in *fsai;
1457         pid_t pid = td->td_proc->p_pid;
1458
1459         int err = 0;
1460         enum vtype vtyp;
1461         int sizechanged = 0;
1462         uint64_t newsize = 0;
1463         accmode_t accmode = 0;
1464
1465         if (fuse_isdeadfs(vp)) {
1466                 return ENXIO;
1467         }
1468         fdisp_init(&fdi, sizeof(*fsai));
1469         fdisp_make_vp(&fdi, FUSE_SETATTR, vp, td, cred);
1470         fsai = fdi.indata;
1471         fsai->valid = 0;
1472
1473         if (vap->va_uid != (uid_t)VNOVAL) {
1474                 fsai->uid = vap->va_uid;
1475                 fsai->valid |= FATTR_UID;
1476                 accmode |= VADMIN;
1477         }
1478         if (vap->va_gid != (gid_t)VNOVAL) {
1479                 fsai->gid = vap->va_gid;
1480                 fsai->valid |= FATTR_GID;
1481                 accmode |= VADMIN;
1482         }
1483         if (vap->va_size != VNOVAL) {
1484
1485                 struct fuse_filehandle *fufh = NULL;
1486
1487                 /*Truncate to a new value. */
1488                 fsai->size = vap->va_size;
1489                 sizechanged = 1;
1490                 newsize = vap->va_size;
1491                 fsai->valid |= FATTR_SIZE;
1492                 accmode |= VWRITE;
1493
1494                 fuse_filehandle_getrw(vp, FWRITE, &fufh, cred, pid);
1495                 if (fufh) {
1496                         fsai->fh = fufh->fh_id;
1497                         fsai->valid |= FATTR_FH;
1498                 }
1499         }
1500         if (vap->va_atime.tv_sec != VNOVAL) {
1501                 fsai->atime = vap->va_atime.tv_sec;
1502                 fsai->atimensec = vap->va_atime.tv_nsec;
1503                 fsai->valid |= FATTR_ATIME;
1504                 accmode |= VADMIN;
1505                 /*
1506                  * TODO: only require VWRITE if UTIMENS_NULL is set. PR 237181
1507                  */
1508         }
1509         if (vap->va_mtime.tv_sec != VNOVAL) {
1510                 fsai->mtime = vap->va_mtime.tv_sec;
1511                 fsai->mtimensec = vap->va_mtime.tv_nsec;
1512                 fsai->valid |= FATTR_MTIME;
1513                 accmode |= VADMIN;
1514                 /*
1515                  * TODO: only require VWRITE if UTIMENS_NULL is set. PR 237181
1516                  */
1517         }
1518         if (vap->va_mode != (mode_t)VNOVAL) {
1519                 fsai->mode = vap->va_mode & ALLPERMS;
1520                 fsai->valid |= FATTR_MODE;
1521                 accmode |= VADMIN;
1522         }
1523         if (!fsai->valid) {
1524                 goto out;
1525         }
1526         vtyp = vnode_vtype(vp);
1527
1528         if (fsai->valid & FATTR_SIZE && vtyp == VDIR) {
1529                 err = EISDIR;
1530                 goto out;
1531         }
1532         if (vfs_isrdonly(vnode_mount(vp)) && (fsai->valid & ~FATTR_SIZE || vtyp == VREG)) {
1533                 err = EROFS;
1534                 goto out;
1535         }
1536         err = fuse_internal_access(vp, accmode, td, cred);
1537         if (err)
1538                 goto out;
1539
1540         if ((err = fdisp_wait_answ(&fdi)))
1541                 goto out;
1542         vtyp = IFTOVT(((struct fuse_attr_out *)fdi.answ)->attr.mode);
1543
1544         if (vnode_vtype(vp) != vtyp) {
1545                 if (vnode_vtype(vp) == VNON && vtyp != VNON) {
1546                         SDT_PROBE2(fuse, , vnops, trace, 1, "FUSE: Dang! "
1547                                 "vnode_vtype is VNON and vtype isn't.");
1548                 } else {
1549                         /*
1550                          * STALE vnode, ditch
1551                          *
1552                          * The vnode has changed its type "behind our back".
1553                          * There's nothing really we can do, so let us just
1554                          * force an internal revocation and tell the caller to
1555                          * try again, if interested.
1556                          */
1557                         fuse_internal_vnode_disappear(vp);
1558                         err = EAGAIN;
1559                 }
1560         }
1561         if (err == 0) {
1562                 struct fuse_attr_out *fao = (struct fuse_attr_out*)fdi.answ;
1563                 fuse_internal_cache_attrs(vp, &fao->attr, fao->attr_valid,
1564                         fao->attr_valid_nsec, NULL);
1565         }
1566
1567 out:
1568         fdisp_destroy(&fdi);
1569         if (!err && sizechanged) {
1570                 fuse_vnode_setsize(vp, cred, newsize);
1571                 VTOFUD(vp)->flag &= ~FN_SIZECHANGE;
1572         }
1573         return err;
1574 }
1575
1576 /*
1577     struct vnop_strategy_args {
1578         struct vnode *a_vp;
1579         struct buf *a_bp;
1580     };
1581 */
1582 static int
1583 fuse_vnop_strategy(struct vop_strategy_args *ap)
1584 {
1585         struct vnode *vp = ap->a_vp;
1586         struct buf *bp = ap->a_bp;
1587
1588         if (!vp || fuse_isdeadfs(vp)) {
1589                 bp->b_ioflags |= BIO_ERROR;
1590                 bp->b_error = ENXIO;
1591                 bufdone(bp);
1592                 return 0;
1593         }
1594         if (bp->b_iocmd == BIO_WRITE) {
1595                 int err;
1596
1597                 err = fuse_vnode_refreshsize(vp, NOCRED);
1598                 if (err) {
1599                         bp->b_ioflags |= BIO_ERROR;
1600                         bp->b_error = err;
1601                         bufdone(bp);
1602                         return 0;
1603                 }
1604         }
1605
1606         /*
1607          * VOP_STRATEGY always returns zero and signals error via bp->b_ioflags.
1608          * fuse_io_strategy sets bp's error fields
1609          */
1610         (void)fuse_io_strategy(vp, bp);
1611
1612         return 0;
1613 }
1614
1615
1616 /*
1617     struct vnop_symlink_args {
1618         struct vnode *a_dvp;
1619         struct vnode **a_vpp;
1620         struct componentname *a_cnp;
1621         struct vattr *a_vap;
1622         char *a_target;
1623     };
1624 */
1625 static int
1626 fuse_vnop_symlink(struct vop_symlink_args *ap)
1627 {
1628         struct vnode *dvp = ap->a_dvp;
1629         struct vnode **vpp = ap->a_vpp;
1630         struct componentname *cnp = ap->a_cnp;
1631         const char *target = ap->a_target;
1632
1633         struct fuse_dispatcher fdi;
1634
1635         int err;
1636         size_t len;
1637
1638         if (fuse_isdeadfs(dvp)) {
1639                 return ENXIO;
1640         }
1641         /*
1642          * Unlike the other creator type calls, here we have to create a message
1643          * where the name of the new entry comes first, and the data describing
1644          * the entry comes second.
1645          * Hence we can't rely on our handy fuse_internal_newentry() routine,
1646          * but put together the message manually and just call the core part.
1647          */
1648
1649         len = strlen(target) + 1;
1650         fdisp_init(&fdi, len + cnp->cn_namelen + 1);
1651         fdisp_make_vp(&fdi, FUSE_SYMLINK, dvp, curthread, NULL);
1652
1653         memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
1654         ((char *)fdi.indata)[cnp->cn_namelen] = '\0';
1655         memcpy((char *)fdi.indata + cnp->cn_namelen + 1, target, len);
1656
1657         err = fuse_internal_newentry_core(dvp, vpp, cnp, VLNK, &fdi);
1658         fdisp_destroy(&fdi);
1659         return err;
1660 }
1661
1662 /*
1663     struct vnop_write_args {
1664         struct vnode *a_vp;
1665         struct uio *a_uio;
1666         int  a_ioflag;
1667         struct ucred *a_cred;
1668     };
1669 */
1670 static int
1671 fuse_vnop_write(struct vop_write_args *ap)
1672 {
1673         struct vnode *vp = ap->a_vp;
1674         struct uio *uio = ap->a_uio;
1675         int ioflag = ap->a_ioflag;
1676         struct ucred *cred = ap->a_cred;
1677         pid_t pid = curthread->td_proc->p_pid;
1678         int err;
1679
1680         if (fuse_isdeadfs(vp)) {
1681                 return ENXIO;
1682         }
1683         err = fuse_vnode_refreshsize(vp, cred);
1684         if (err)
1685                 return err;
1686
1687         if (VTOFUD(vp)->flag & FN_DIRECTIO) {
1688                 ioflag |= IO_DIRECT;
1689         }
1690
1691         return fuse_io_dispatch(vp, uio, ioflag, cred, pid);
1692 }
1693
1694 SDT_PROBE_DEFINE1(fuse, , vnops, vnop_getpages_error, "int");
1695 /*
1696     struct vnop_getpages_args {
1697         struct vnode *a_vp;
1698         vm_page_t *a_m;
1699         int a_count;
1700         int a_reqpage;
1701     };
1702 */
1703 static int
1704 fuse_vnop_getpages(struct vop_getpages_args *ap)
1705 {
1706         int i, error, nextoff, size, toff, count, npages;
1707         struct uio uio;
1708         struct iovec iov;
1709         vm_offset_t kva;
1710         struct buf *bp;
1711         struct vnode *vp;
1712         struct thread *td;
1713         struct ucred *cred;
1714         vm_page_t *pages;
1715         pid_t pid = curthread->td_proc->p_pid;
1716
1717         vp = ap->a_vp;
1718         KASSERT(vp->v_object, ("objectless vp passed to getpages"));
1719         td = curthread;                 /* XXX */
1720         cred = curthread->td_ucred;     /* XXX */
1721         pages = ap->a_m;
1722         npages = ap->a_count;
1723
1724         if (!fsess_opt_mmap(vnode_mount(vp))) {
1725                 SDT_PROBE2(fuse, , vnops, trace, 1,
1726                         "called on non-cacheable vnode??\n");
1727                 return (VM_PAGER_ERROR);
1728         }
1729
1730         /*
1731          * If the last page is partially valid, just return it and allow
1732          * the pager to zero-out the blanks.  Partially valid pages can
1733          * only occur at the file EOF.
1734          *
1735          * XXXGL: is that true for FUSE, which is a local filesystem,
1736          * but still somewhat disconnected from the kernel?
1737          */
1738         VM_OBJECT_WLOCK(vp->v_object);
1739         if (pages[npages - 1]->valid != 0 && --npages == 0)
1740                 goto out;
1741         VM_OBJECT_WUNLOCK(vp->v_object);
1742
1743         /*
1744          * We use only the kva address for the buffer, but this is extremely
1745          * convenient and fast.
1746          */
1747         bp = uma_zalloc(fuse_pbuf_zone, M_WAITOK);
1748
1749         kva = (vm_offset_t)bp->b_data;
1750         pmap_qenter(kva, pages, npages);
1751         VM_CNT_INC(v_vnodein);
1752         VM_CNT_ADD(v_vnodepgsin, npages);
1753
1754         count = npages << PAGE_SHIFT;
1755         iov.iov_base = (caddr_t)kva;
1756         iov.iov_len = count;
1757         uio.uio_iov = &iov;
1758         uio.uio_iovcnt = 1;
1759         uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
1760         uio.uio_resid = count;
1761         uio.uio_segflg = UIO_SYSSPACE;
1762         uio.uio_rw = UIO_READ;
1763         uio.uio_td = td;
1764
1765         error = fuse_io_dispatch(vp, &uio, IO_DIRECT, cred, pid);
1766         pmap_qremove(kva, npages);
1767
1768         uma_zfree(fuse_pbuf_zone, bp);
1769
1770         if (error && (uio.uio_resid == count)) {
1771                 SDT_PROBE1(fuse, , vnops, vnop_getpages_error, error);
1772                 return VM_PAGER_ERROR;
1773         }
1774         /*
1775          * Calculate the number of bytes read and validate only that number
1776          * of bytes.  Note that due to pending writes, size may be 0.  This
1777          * does not mean that the remaining data is invalid!
1778          */
1779
1780         size = count - uio.uio_resid;
1781         VM_OBJECT_WLOCK(vp->v_object);
1782         fuse_vm_page_lock_queues();
1783         for (i = 0, toff = 0; i < npages; i++, toff = nextoff) {
1784                 vm_page_t m;
1785
1786                 nextoff = toff + PAGE_SIZE;
1787                 m = pages[i];
1788
1789                 if (nextoff <= size) {
1790                         /*
1791                          * Read operation filled an entire page
1792                          */
1793                         m->valid = VM_PAGE_BITS_ALL;
1794                         KASSERT(m->dirty == 0,
1795                             ("fuse_getpages: page %p is dirty", m));
1796                 } else if (size > toff) {
1797                         /*
1798                          * Read operation filled a partial page.
1799                          */
1800                         m->valid = 0;
1801                         vm_page_set_valid_range(m, 0, size - toff);
1802                         KASSERT(m->dirty == 0,
1803                             ("fuse_getpages: page %p is dirty", m));
1804                 } else {
1805                         /*
1806                          * Read operation was short.  If no error occurred
1807                          * we may have hit a zero-fill section.   We simply
1808                          * leave valid set to 0.
1809                          */
1810                         ;
1811                 }
1812         }
1813         fuse_vm_page_unlock_queues();
1814 out:
1815         VM_OBJECT_WUNLOCK(vp->v_object);
1816         if (ap->a_rbehind)
1817                 *ap->a_rbehind = 0;
1818         if (ap->a_rahead)
1819                 *ap->a_rahead = 0;
1820         return (VM_PAGER_OK);
1821 }
1822
1823 /*
1824     struct vnop_putpages_args {
1825         struct vnode *a_vp;
1826         vm_page_t *a_m;
1827         int a_count;
1828         int a_sync;
1829         int *a_rtvals;
1830         vm_ooffset_t a_offset;
1831     };
1832 */
1833 static int
1834 fuse_vnop_putpages(struct vop_putpages_args *ap)
1835 {
1836         struct uio uio;
1837         struct iovec iov;
1838         vm_offset_t kva;
1839         struct buf *bp;
1840         int i, error, npages, count;
1841         off_t offset;
1842         int *rtvals;
1843         struct vnode *vp;
1844         struct thread *td;
1845         struct ucred *cred;
1846         vm_page_t *pages;
1847         vm_ooffset_t fsize;
1848         pid_t pid = curthread->td_proc->p_pid;
1849
1850         vp = ap->a_vp;
1851         KASSERT(vp->v_object, ("objectless vp passed to putpages"));
1852         fsize = vp->v_object->un_pager.vnp.vnp_size;
1853         td = curthread;                 /* XXX */
1854         cred = curthread->td_ucred;     /* XXX */
1855         pages = ap->a_m;
1856         count = ap->a_count;
1857         rtvals = ap->a_rtvals;
1858         npages = btoc(count);
1859         offset = IDX_TO_OFF(pages[0]->pindex);
1860
1861         if (!fsess_opt_mmap(vnode_mount(vp))) {
1862                 SDT_PROBE2(fuse, , vnops, trace, 1,
1863                         "called on non-cacheable vnode??\n");
1864         }
1865         for (i = 0; i < npages; i++)
1866                 rtvals[i] = VM_PAGER_AGAIN;
1867
1868         /*
1869          * When putting pages, do not extend file past EOF.
1870          */
1871
1872         if (offset + count > fsize) {
1873                 count = fsize - offset;
1874                 if (count < 0)
1875                         count = 0;
1876         }
1877         /*
1878          * We use only the kva address for the buffer, but this is extremely
1879          * convenient and fast.
1880          */
1881         bp = uma_zalloc(fuse_pbuf_zone, M_WAITOK);
1882
1883         kva = (vm_offset_t)bp->b_data;
1884         pmap_qenter(kva, pages, npages);
1885         VM_CNT_INC(v_vnodeout);
1886         VM_CNT_ADD(v_vnodepgsout, count);
1887
1888         iov.iov_base = (caddr_t)kva;
1889         iov.iov_len = count;
1890         uio.uio_iov = &iov;
1891         uio.uio_iovcnt = 1;
1892         uio.uio_offset = offset;
1893         uio.uio_resid = count;
1894         uio.uio_segflg = UIO_SYSSPACE;
1895         uio.uio_rw = UIO_WRITE;
1896         uio.uio_td = td;
1897
1898         error = fuse_io_dispatch(vp, &uio, IO_DIRECT, cred, pid);
1899
1900         pmap_qremove(kva, npages);
1901         uma_zfree(fuse_pbuf_zone, bp);
1902
1903         if (!error) {
1904                 int nwritten = round_page(count - uio.uio_resid) / PAGE_SIZE;
1905
1906                 for (i = 0; i < nwritten; i++) {
1907                         rtvals[i] = VM_PAGER_OK;
1908                         VM_OBJECT_WLOCK(pages[i]->object);
1909                         vm_page_undirty(pages[i]);
1910                         VM_OBJECT_WUNLOCK(pages[i]->object);
1911                 }
1912         }
1913         return rtvals[0];
1914 }
1915
1916 static const char extattr_namespace_separator = '.';
1917
1918 /*
1919     struct vop_getextattr_args {
1920         struct vop_generic_args a_gen;
1921         struct vnode *a_vp;
1922         int a_attrnamespace;
1923         const char *a_name;
1924         struct uio *a_uio;
1925         size_t *a_size;
1926         struct ucred *a_cred;
1927         struct thread *a_td;
1928     };
1929 */
1930 static int
1931 fuse_vnop_getextattr(struct vop_getextattr_args *ap)
1932 {
1933         struct vnode *vp = ap->a_vp;
1934         struct uio *uio = ap->a_uio;
1935         struct fuse_dispatcher fdi;
1936         struct fuse_getxattr_in *get_xattr_in;
1937         struct fuse_getxattr_out *get_xattr_out;
1938         struct mount *mp = vnode_mount(vp);
1939         struct thread *td = ap->a_td;
1940         struct ucred *cred = ap->a_cred;
1941         char *prefix;
1942         char *attr_str;
1943         size_t len;
1944         int err;
1945
1946         if (fuse_isdeadfs(vp))
1947                 return (ENXIO);
1948
1949         err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td, VREAD);
1950         if (err)
1951                 return err;
1952
1953         /* Default to looking for user attributes. */
1954         if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
1955                 prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
1956         else
1957                 prefix = EXTATTR_NAMESPACE_USER_STRING;
1958
1959         len = strlen(prefix) + sizeof(extattr_namespace_separator) +
1960             strlen(ap->a_name) + 1;
1961
1962         fdisp_init(&fdi, len + sizeof(*get_xattr_in));
1963         fdisp_make_vp(&fdi, FUSE_GETXATTR, vp, td, cred);
1964
1965         get_xattr_in = fdi.indata;
1966         /*
1967          * Check to see whether we're querying the available size or
1968          * issuing the actual request.  If we pass in 0, we get back struct
1969          * fuse_getxattr_out.  If we pass in a non-zero size, we get back
1970          * that much data, without the struct fuse_getxattr_out header.
1971          */
1972         if (uio == NULL)
1973                 get_xattr_in->size = 0;
1974         else
1975                 get_xattr_in->size = uio->uio_resid;
1976
1977         attr_str = (char *)fdi.indata + sizeof(*get_xattr_in);
1978         snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator,
1979             ap->a_name);
1980
1981         err = fdisp_wait_answ(&fdi);
1982         if (err != 0) {
1983                 if (err == ENOSYS)
1984                         fsess_set_notimpl(mp, FUSE_GETXATTR);
1985                 goto out;
1986         }
1987
1988         get_xattr_out = fdi.answ;
1989
1990         if (ap->a_size != NULL)
1991                 *ap->a_size = get_xattr_out->size;
1992
1993         if (uio != NULL)
1994                 err = uiomove(fdi.answ, fdi.iosize, uio);
1995
1996 out:
1997         fdisp_destroy(&fdi);
1998         return (err);
1999 }
2000
2001 /*
2002     struct vop_setextattr_args {
2003         struct vop_generic_args a_gen;
2004         struct vnode *a_vp;
2005         int a_attrnamespace;
2006         const char *a_name;
2007         struct uio *a_uio;
2008         struct ucred *a_cred;
2009         struct thread *a_td;
2010     };
2011 */
2012 static int
2013 fuse_vnop_setextattr(struct vop_setextattr_args *ap)
2014 {
2015         struct vnode *vp = ap->a_vp;
2016         struct uio *uio = ap->a_uio;
2017         struct fuse_dispatcher fdi;
2018         struct fuse_setxattr_in *set_xattr_in;
2019         struct mount *mp = vnode_mount(vp);
2020         struct thread *td = ap->a_td;
2021         struct ucred *cred = ap->a_cred;
2022         char *prefix;
2023         size_t len;
2024         char *attr_str;
2025         int err;
2026         
2027         if (fuse_isdeadfs(vp))
2028                 return (ENXIO);
2029
2030         if (vfs_isrdonly(mp))
2031                 return EROFS;
2032
2033         /* Deleting xattrs must use VOP_DELETEEXTATTR instead */
2034         if (ap->a_uio == NULL)
2035                 return (EINVAL);
2036
2037         err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td,
2038                 VWRITE);
2039         if (err)
2040                 return err;
2041
2042         /* Default to looking for user attributes. */
2043         if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
2044                 prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
2045         else
2046                 prefix = EXTATTR_NAMESPACE_USER_STRING;
2047
2048         len = strlen(prefix) + sizeof(extattr_namespace_separator) +
2049             strlen(ap->a_name) + 1;
2050
2051         fdisp_init(&fdi, len + sizeof(*set_xattr_in) + uio->uio_resid);
2052         fdisp_make_vp(&fdi, FUSE_SETXATTR, vp, td, cred);
2053
2054         set_xattr_in = fdi.indata;
2055         set_xattr_in->size = uio->uio_resid;
2056
2057         attr_str = (char *)fdi.indata + sizeof(*set_xattr_in);
2058         snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator,
2059             ap->a_name);
2060
2061         err = uiomove((char *)fdi.indata + sizeof(*set_xattr_in) + len,
2062             uio->uio_resid, uio);
2063         if (err != 0) {
2064                 goto out;
2065         }
2066
2067         err = fdisp_wait_answ(&fdi);
2068
2069         if (err != 0) {
2070                 if (err == ENOSYS)
2071                         fsess_set_notimpl(mp, FUSE_SETXATTR);
2072                 goto out;
2073         }
2074
2075 out:
2076         fdisp_destroy(&fdi);
2077         return (err);
2078 }
2079
2080 /*
2081  * The Linux / FUSE extended attribute list is simply a collection of
2082  * NUL-terminated strings.  The FreeBSD extended attribute list is a single
2083  * byte length followed by a non-NUL terminated string.  So, this allows
2084  * conversion of the Linux / FUSE format to the FreeBSD format in place.
2085  * Linux attribute names are reported with the namespace as a prefix (e.g.
2086  * "user.attribute_name"), but in FreeBSD they are reported without the
2087  * namespace prefix (e.g. "attribute_name").  So, we're going from:
2088  *
2089  * user.attr_name1\0user.attr_name2\0
2090  *
2091  * to:
2092  *
2093  * <num>attr_name1<num>attr_name2
2094  *
2095  * Where "<num>" is a single byte number of characters in the attribute name.
2096  * 
2097  * Args:
2098  * prefix - exattr namespace prefix string
2099  * list, list_len - input list with namespace prefixes
2100  * bsd_list, bsd_list_len - output list compatible with bsd vfs
2101  */
2102 static int
2103 fuse_xattrlist_convert(char *prefix, const char *list, int list_len,
2104     char *bsd_list, int *bsd_list_len)
2105 {
2106         int len, pos, dist_to_next, prefix_len;
2107
2108         pos = 0;
2109         *bsd_list_len = 0;
2110         prefix_len = strlen(prefix);
2111
2112         while (pos < list_len && list[pos] != '\0') {
2113                 dist_to_next = strlen(&list[pos]) + 1;
2114                 if (bcmp(&list[pos], prefix, prefix_len) == 0 &&
2115                     list[pos + prefix_len] == extattr_namespace_separator) {
2116                         len = dist_to_next -
2117                             (prefix_len + sizeof(extattr_namespace_separator)) - 1;
2118                         if (len >= EXTATTR_MAXNAMELEN)
2119                                 return (ENAMETOOLONG);
2120
2121                         bsd_list[*bsd_list_len] = len;
2122                         memcpy(&bsd_list[*bsd_list_len + 1],
2123                             &list[pos + prefix_len +
2124                             sizeof(extattr_namespace_separator)], len);
2125
2126                         *bsd_list_len += len + 1;
2127                 }
2128
2129                 pos += dist_to_next;
2130         }
2131
2132         return (0);
2133 }
2134
2135 /*
2136     struct vop_listextattr_args {
2137         struct vop_generic_args a_gen;
2138         struct vnode *a_vp;
2139         int a_attrnamespace;
2140         struct uio *a_uio;
2141         size_t *a_size;
2142         struct ucred *a_cred;
2143         struct thread *a_td;
2144     };
2145 */
2146 static int
2147 fuse_vnop_listextattr(struct vop_listextattr_args *ap)
2148 {
2149         struct vnode *vp = ap->a_vp;
2150         struct uio *uio = ap->a_uio;
2151         struct fuse_dispatcher fdi;
2152         struct fuse_listxattr_in *list_xattr_in;
2153         struct fuse_listxattr_out *list_xattr_out;
2154         struct mount *mp = vnode_mount(vp);
2155         struct thread *td = ap->a_td;
2156         struct ucred *cred = ap->a_cred;
2157         size_t len;
2158         char *prefix;
2159         char *attr_str;
2160         char *bsd_list = NULL;
2161         char *linux_list;
2162         int bsd_list_len;
2163         int linux_list_len;
2164         int err;
2165
2166         if (fuse_isdeadfs(vp))
2167                 return (ENXIO);
2168
2169         err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td, VREAD);
2170         if (err)
2171                 return err;
2172
2173         /*
2174          * Add space for a NUL and the period separator if enabled.
2175          * Default to looking for user attributes.
2176          */
2177         if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
2178                 prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
2179         else
2180                 prefix = EXTATTR_NAMESPACE_USER_STRING;
2181
2182         len = strlen(prefix) + sizeof(extattr_namespace_separator) + 1;
2183
2184         fdisp_init(&fdi, sizeof(*list_xattr_in) + len);
2185         fdisp_make_vp(&fdi, FUSE_LISTXATTR, vp, td, cred);
2186
2187         /*
2188          * Retrieve Linux / FUSE compatible list size.
2189          */
2190         list_xattr_in = fdi.indata;
2191         list_xattr_in->size = 0;
2192         attr_str = (char *)fdi.indata + sizeof(*list_xattr_in);
2193         snprintf(attr_str, len, "%s%c", prefix, extattr_namespace_separator);
2194
2195         err = fdisp_wait_answ(&fdi);
2196         if (err != 0) {
2197                 if (err == ENOSYS)
2198                         fsess_set_notimpl(mp, FUSE_LISTXATTR);
2199                 goto out;
2200         }
2201
2202         list_xattr_out = fdi.answ;
2203         linux_list_len = list_xattr_out->size;
2204         if (linux_list_len == 0) {
2205                 if (ap->a_size != NULL)
2206                         *ap->a_size = linux_list_len;
2207                 goto out;
2208         }
2209
2210         /*
2211          * Retrieve Linux / FUSE compatible list values.
2212          */
2213         fdisp_refresh_vp(&fdi, FUSE_LISTXATTR, vp, td, cred);
2214         list_xattr_in = fdi.indata;
2215         list_xattr_in->size = linux_list_len + sizeof(*list_xattr_out);
2216         list_xattr_in->flags = 0;
2217         attr_str = (char *)fdi.indata + sizeof(*list_xattr_in);
2218         snprintf(attr_str, len, "%s%c", prefix, extattr_namespace_separator);
2219
2220         err = fdisp_wait_answ(&fdi);
2221         if (err != 0)
2222                 goto out;
2223
2224         linux_list = fdi.answ;
2225         linux_list_len = fdi.iosize;
2226
2227         /*
2228          * Retrieve the BSD compatible list values.
2229          * The Linux / FUSE attribute list format isn't the same
2230          * as FreeBSD's format. So we need to transform it into
2231          * FreeBSD's format before giving it to the user.
2232          */
2233         bsd_list = malloc(linux_list_len, M_TEMP, M_WAITOK);
2234         err = fuse_xattrlist_convert(prefix, linux_list, linux_list_len,
2235             bsd_list, &bsd_list_len);
2236         if (err != 0)
2237                 goto out;
2238
2239         if (ap->a_size != NULL)
2240                 *ap->a_size = bsd_list_len;
2241
2242         if (uio != NULL)
2243                 err = uiomove(bsd_list, bsd_list_len, uio);
2244
2245 out:
2246         free(bsd_list, M_TEMP);
2247         fdisp_destroy(&fdi);
2248         return (err);
2249 }
2250
2251 /*
2252     struct vop_deleteextattr_args {
2253         struct vop_generic_args a_gen;
2254         struct vnode *a_vp;
2255         int a_attrnamespace;
2256         const char *a_name;
2257         struct ucred *a_cred;
2258         struct thread *a_td;
2259     };
2260 */
2261 static int
2262 fuse_vnop_deleteextattr(struct vop_deleteextattr_args *ap)
2263 {
2264         struct vnode *vp = ap->a_vp;
2265         struct fuse_dispatcher fdi;
2266         struct mount *mp = vnode_mount(vp);
2267         struct thread *td = ap->a_td;
2268         struct ucred *cred = ap->a_cred;
2269         char *prefix;
2270         size_t len;
2271         char *attr_str;
2272         int err;
2273
2274         if (fuse_isdeadfs(vp))
2275                 return (ENXIO);
2276
2277         if (vfs_isrdonly(mp))
2278                 return EROFS;
2279
2280         err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td,
2281                 VWRITE);
2282         if (err)
2283                 return err;
2284
2285         /* Default to looking for user attributes. */
2286         if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
2287                 prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
2288         else
2289                 prefix = EXTATTR_NAMESPACE_USER_STRING;
2290
2291         len = strlen(prefix) + sizeof(extattr_namespace_separator) +
2292             strlen(ap->a_name) + 1;
2293
2294         fdisp_init(&fdi, len);
2295         fdisp_make_vp(&fdi, FUSE_REMOVEXATTR, vp, td, cred);
2296
2297         attr_str = fdi.indata;
2298         snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator,
2299             ap->a_name);
2300
2301         err = fdisp_wait_answ(&fdi);
2302         if (err != 0) {
2303                 if (err == ENOSYS)
2304                         fsess_set_notimpl(mp, FUSE_REMOVEXATTR);
2305         }
2306
2307         fdisp_destroy(&fdi);
2308         return (err);
2309 }
2310
2311 /*
2312     struct vnop_print_args {
2313         struct vnode *a_vp;
2314     };
2315 */
2316 static int
2317 fuse_vnop_print(struct vop_print_args *ap)
2318 {
2319         struct fuse_vnode_data *fvdat = VTOFUD(ap->a_vp);
2320
2321         printf("nodeid: %ju, parent nodeid: %ju, nlookup: %ju, flag: %#x\n",
2322             (uintmax_t)VTOILLU(ap->a_vp), (uintmax_t)fvdat->parent_nid,
2323             (uintmax_t)fvdat->nlookup,
2324             fvdat->flag);
2325
2326         return 0;
2327 }