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