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