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