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