The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/fuse/fuse_vnops.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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  * Copyright (c) 2019 The FreeBSD Foundation
   37  *
   38  * Portions of this software were developed by BFF Storage Systems, LLC under
   39  * sponsorship from the FreeBSD Foundation.
   40  *
   41  * Redistribution and use in source and binary forms, with or without
   42  * modification, are permitted provided that the following conditions
   43  * are met:
   44  * 1. Redistributions of source code must retain the above copyright
   45  *    notice, this list of conditions and the following disclaimer.
   46  * 2. Redistributions in binary form must reproduce the above copyright
   47  *    notice, this list of conditions and the following disclaimer in the
   48  *    documentation and/or other materials provided with the distribution.
   49  *
   50  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   51  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   52  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   53  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
   54  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   55  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   56  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   57  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   58  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   59  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   60  * SUCH DAMAGE.
   61  */
   62 
   63 #include <sys/cdefs.h>
   64 __FBSDID("$FreeBSD$");
   65 
   66 #include <sys/param.h>
   67 #include <sys/module.h>
   68 #include <sys/systm.h>
   69 #include <sys/errno.h>
   70 #include <sys/kernel.h>
   71 #include <sys/conf.h>
   72 #include <sys/filio.h>
   73 #include <sys/uio.h>
   74 #include <sys/malloc.h>
   75 #include <sys/queue.h>
   76 #include <sys/limits.h>
   77 #include <sys/lock.h>
   78 #include <sys/rwlock.h>
   79 #include <sys/sx.h>
   80 #include <sys/proc.h>
   81 #include <sys/mount.h>
   82 #include <sys/vnode.h>
   83 #include <sys/namei.h>
   84 #include <sys/extattr.h>
   85 #include <sys/stat.h>
   86 #include <sys/unistd.h>
   87 #include <sys/filedesc.h>
   88 #include <sys/file.h>
   89 #include <sys/fcntl.h>
   90 #include <sys/dirent.h>
   91 #include <sys/bio.h>
   92 #include <sys/buf.h>
   93 #include <sys/sysctl.h>
   94 #include <sys/vmmeter.h>
   95 
   96 #include <vm/vm.h>
   97 #include <vm/vm_extern.h>
   98 #include <vm/pmap.h>
   99 #include <vm/vm_map.h>
  100 #include <vm/vm_page.h>
  101 #include <vm/vm_param.h>
  102 #include <vm/vm_object.h>
  103 #include <vm/vm_pager.h>
  104 #include <vm/vnode_pager.h>
  105 #include <vm/vm_object.h>
  106 
  107 #include "fuse.h"
  108 #include "fuse_file.h"
  109 #include "fuse_internal.h"
  110 #include "fuse_ipc.h"
  111 #include "fuse_node.h"
  112 #include "fuse_io.h"
  113 
  114 #include <sys/priv.h>
  115 
  116 /* Maximum number of hardlinks to a single FUSE file */
  117 #define FUSE_LINK_MAX                      UINT32_MAX
  118 
  119 SDT_PROVIDER_DECLARE(fusefs);
  120 /* 
  121  * Fuse trace probe:
  122  * arg0: verbosity.  Higher numbers give more verbose messages
  123  * arg1: Textual message
  124  */
  125 SDT_PROBE_DEFINE2(fusefs, , vnops, trace, "int", "char*");
  126 
  127 /* vnode ops */
  128 static vop_access_t fuse_vnop_access;
  129 static vop_advlock_t fuse_vnop_advlock;
  130 static vop_allocate_t fuse_vnop_allocate;
  131 static vop_bmap_t fuse_vnop_bmap;
  132 static vop_close_t fuse_fifo_close;
  133 static vop_close_t fuse_vnop_close;
  134 static vop_copy_file_range_t fuse_vnop_copy_file_range;
  135 static vop_create_t fuse_vnop_create;
  136 static vop_deallocate_t fuse_vnop_deallocate;
  137 static vop_deleteextattr_t fuse_vnop_deleteextattr;
  138 static vop_fdatasync_t fuse_vnop_fdatasync;
  139 static vop_fsync_t fuse_vnop_fsync;
  140 static vop_getattr_t fuse_vnop_getattr;
  141 static vop_getextattr_t fuse_vnop_getextattr;
  142 static vop_inactive_t fuse_vnop_inactive;
  143 static vop_ioctl_t fuse_vnop_ioctl;
  144 static vop_link_t fuse_vnop_link;
  145 static vop_listextattr_t fuse_vnop_listextattr;
  146 static vop_lookup_t fuse_vnop_lookup;
  147 static vop_mkdir_t fuse_vnop_mkdir;
  148 static vop_mknod_t fuse_vnop_mknod;
  149 static vop_open_t fuse_vnop_open;
  150 static vop_pathconf_t fuse_vnop_pathconf;
  151 static vop_read_t fuse_vnop_read;
  152 static vop_readdir_t fuse_vnop_readdir;
  153 static vop_readlink_t fuse_vnop_readlink;
  154 static vop_reclaim_t fuse_vnop_reclaim;
  155 static vop_remove_t fuse_vnop_remove;
  156 static vop_rename_t fuse_vnop_rename;
  157 static vop_rmdir_t fuse_vnop_rmdir;
  158 static vop_setattr_t fuse_vnop_setattr;
  159 static vop_setextattr_t fuse_vnop_setextattr;
  160 static vop_strategy_t fuse_vnop_strategy;
  161 static vop_symlink_t fuse_vnop_symlink;
  162 static vop_write_t fuse_vnop_write;
  163 static vop_getpages_t fuse_vnop_getpages;
  164 static vop_print_t fuse_vnop_print;
  165 static vop_vptofh_t fuse_vnop_vptofh;
  166 
  167 struct vop_vector fuse_fifoops = {
  168         .vop_default =          &fifo_specops,
  169         .vop_access =           fuse_vnop_access,
  170         .vop_close =            fuse_fifo_close,
  171         .vop_fsync =            fuse_vnop_fsync,
  172         .vop_getattr =          fuse_vnop_getattr,
  173         .vop_inactive =         fuse_vnop_inactive,
  174         .vop_pathconf =         fuse_vnop_pathconf,
  175         .vop_print =            fuse_vnop_print,
  176         .vop_read =             VOP_PANIC,
  177         .vop_reclaim =          fuse_vnop_reclaim,
  178         .vop_setattr =          fuse_vnop_setattr,
  179         .vop_write =            VOP_PANIC,
  180         .vop_vptofh =           fuse_vnop_vptofh,
  181 };
  182 VFS_VOP_VECTOR_REGISTER(fuse_fifoops);
  183 
  184 struct vop_vector fuse_vnops = {
  185         .vop_allocate = fuse_vnop_allocate,
  186         .vop_default = &default_vnodeops,
  187         .vop_access = fuse_vnop_access,
  188         .vop_advlock = fuse_vnop_advlock,
  189         .vop_bmap = fuse_vnop_bmap,
  190         .vop_close = fuse_vnop_close,
  191         .vop_copy_file_range = fuse_vnop_copy_file_range,
  192         .vop_create = fuse_vnop_create,
  193         .vop_deallocate = fuse_vnop_deallocate,
  194         .vop_deleteextattr = fuse_vnop_deleteextattr,
  195         .vop_fsync = fuse_vnop_fsync,
  196         .vop_fdatasync = fuse_vnop_fdatasync,
  197         .vop_getattr = fuse_vnop_getattr,
  198         .vop_getextattr = fuse_vnop_getextattr,
  199         .vop_inactive = fuse_vnop_inactive,
  200         .vop_ioctl = fuse_vnop_ioctl,
  201         .vop_link = fuse_vnop_link,
  202         .vop_listextattr = fuse_vnop_listextattr,
  203         .vop_lookup = fuse_vnop_lookup,
  204         .vop_mkdir = fuse_vnop_mkdir,
  205         .vop_mknod = fuse_vnop_mknod,
  206         .vop_open = fuse_vnop_open,
  207         .vop_pathconf = fuse_vnop_pathconf,
  208         /*
  209          * TODO: implement vop_poll after upgrading to protocol 7.21.
  210          * FUSE_POLL was added in protocol 7.11, but it's kind of broken until
  211          * 7.21, which adds the ability for the client to choose which poll
  212          * events it wants, and for a client to deregister a file handle
  213          */
  214         .vop_read = fuse_vnop_read,
  215         .vop_readdir = fuse_vnop_readdir,
  216         .vop_readlink = fuse_vnop_readlink,
  217         .vop_reclaim = fuse_vnop_reclaim,
  218         .vop_remove = fuse_vnop_remove,
  219         .vop_rename = fuse_vnop_rename,
  220         .vop_rmdir = fuse_vnop_rmdir,
  221         .vop_setattr = fuse_vnop_setattr,
  222         .vop_setextattr = fuse_vnop_setextattr,
  223         .vop_strategy = fuse_vnop_strategy,
  224         .vop_symlink = fuse_vnop_symlink,
  225         .vop_write = fuse_vnop_write,
  226         .vop_getpages = fuse_vnop_getpages,
  227         .vop_print = fuse_vnop_print,
  228         .vop_vptofh = fuse_vnop_vptofh,
  229 };
  230 VFS_VOP_VECTOR_REGISTER(fuse_vnops);
  231 
  232 uma_zone_t fuse_pbuf_zone;
  233 
  234 /* Check permission for extattr operations, much like extattr_check_cred */
  235 static int
  236 fuse_extattr_check_cred(struct vnode *vp, int ns, struct ucred *cred,
  237         struct thread *td, accmode_t accmode)
  238 {
  239         struct mount *mp = vnode_mount(vp);
  240         struct fuse_data *data = fuse_get_mpdata(mp);
  241         int default_permissions = data->dataflags & FSESS_DEFAULT_PERMISSIONS;
  242 
  243         /*
  244          * Kernel-invoked always succeeds.
  245          */
  246         if (cred == NOCRED)
  247                 return (0);
  248 
  249         /*
  250          * Do not allow privileged processes in jail to directly manipulate
  251          * system attributes.
  252          */
  253         switch (ns) {
  254         case EXTATTR_NAMESPACE_SYSTEM:
  255                 if (default_permissions) {
  256                         return (priv_check_cred(cred, PRIV_VFS_EXTATTR_SYSTEM));
  257                 }
  258                 return (0);
  259         case EXTATTR_NAMESPACE_USER:
  260                 if (default_permissions) {
  261                         return (fuse_internal_access(vp, accmode, td, cred));
  262                 }
  263                 return (0);
  264         default:
  265                 return (EPERM);
  266         }
  267 }
  268 
  269 /* Get a filehandle for a directory */
  270 static int
  271 fuse_filehandle_get_dir(struct vnode *vp, struct fuse_filehandle **fufhp,
  272         struct ucred *cred, pid_t pid)
  273 {
  274         if (fuse_filehandle_get(vp, FREAD, fufhp, cred, pid) == 0)
  275                 return 0;
  276         return fuse_filehandle_get(vp, FEXEC, fufhp, cred, pid);
  277 }
  278 
  279 /* Send FUSE_FLUSH for this vnode */
  280 static int
  281 fuse_flush(struct vnode *vp, struct ucred *cred, pid_t pid, int fflag)
  282 {
  283         struct fuse_flush_in *ffi;
  284         struct fuse_filehandle *fufh;
  285         struct fuse_dispatcher fdi;
  286         struct thread *td = curthread;
  287         struct mount *mp = vnode_mount(vp);
  288         int err;
  289 
  290         if (fsess_not_impl(vnode_mount(vp), FUSE_FLUSH))
  291                 return 0;
  292 
  293         err = fuse_filehandle_getrw(vp, fflag, &fufh, cred, pid);
  294         if (err)
  295                 return err;
  296 
  297         fdisp_init(&fdi, sizeof(*ffi));
  298         fdisp_make_vp(&fdi, FUSE_FLUSH, vp, td, cred);
  299         ffi = fdi.indata;
  300         ffi->fh = fufh->fh_id;
  301         /* 
  302          * If the file has a POSIX lock then we're supposed to set lock_owner.
  303          * If not, then lock_owner is undefined.  So we may as well always set
  304          * it.
  305          */
  306         ffi->lock_owner = td->td_proc->p_pid;
  307 
  308         err = fdisp_wait_answ(&fdi);
  309         if (err == ENOSYS) {
  310                 fsess_set_notimpl(mp, FUSE_FLUSH);
  311                 err = 0;
  312         }
  313         fdisp_destroy(&fdi);
  314         return err;
  315 }
  316 
  317 /* Close wrapper for fifos.  */
  318 static int
  319 fuse_fifo_close(struct vop_close_args *ap)
  320 {
  321         return (fifo_specops.vop_close(ap));
  322 }
  323 
  324 /* Invalidate a range of cached data, whether dirty of not */
  325 static int
  326 fuse_inval_buf_range(struct vnode *vp, off_t filesize, off_t start, off_t end)
  327 {
  328         struct buf *bp;
  329         daddr_t left_lbn, end_lbn, right_lbn;
  330         off_t new_filesize;
  331         int iosize, left_on, right_on, right_blksize;
  332 
  333         iosize = fuse_iosize(vp);
  334         left_lbn = start / iosize;
  335         end_lbn = howmany(end, iosize);
  336         left_on = start & (iosize - 1);
  337         if (left_on != 0) {
  338                 bp = getblk(vp, left_lbn, iosize, PCATCH, 0, 0);
  339                 if ((bp->b_flags & B_CACHE) != 0 && bp->b_dirtyend >= left_on) {
  340                         /*
  341                          * Flush the dirty buffer, because we don't have a
  342                          * byte-granular way to record which parts of the
  343                          * buffer are valid.
  344                          */
  345                         bwrite(bp);
  346                         if (bp->b_error)
  347                                 return (bp->b_error);
  348                 } else {
  349                         brelse(bp);
  350                 }
  351         }
  352         right_on = end & (iosize - 1);
  353         if (right_on != 0) {
  354                 right_lbn = end / iosize;
  355                 new_filesize = MAX(filesize, end);
  356                 right_blksize = MIN(iosize, new_filesize - iosize * right_lbn);
  357                 bp = getblk(vp, right_lbn, right_blksize, PCATCH, 0, 0);
  358                 if ((bp->b_flags & B_CACHE) != 0 && bp->b_dirtyoff < right_on) {
  359                         /*
  360                          * Flush the dirty buffer, because we don't have a
  361                          * byte-granular way to record which parts of the
  362                          * buffer are valid.
  363                          */
  364                         bwrite(bp);
  365                         if (bp->b_error)
  366                                 return (bp->b_error);
  367                 } else {
  368                         brelse(bp);
  369                 }
  370         }
  371 
  372         v_inval_buf_range(vp, left_lbn, end_lbn, iosize);
  373         return (0);
  374 }
  375 
  376 
  377 /* Send FUSE_LSEEK for this node */
  378 static int
  379 fuse_vnop_do_lseek(struct vnode *vp, struct thread *td, struct ucred *cred,
  380         pid_t pid, off_t *offp, int whence)
  381 {
  382         struct fuse_dispatcher fdi;
  383         struct fuse_filehandle *fufh;
  384         struct fuse_lseek_in *flsi;
  385         struct fuse_lseek_out *flso;
  386         struct mount *mp = vnode_mount(vp);
  387         int err;
  388 
  389         ASSERT_VOP_LOCKED(vp, __func__);
  390 
  391         err = fuse_filehandle_getrw(vp, FREAD, &fufh, cred, pid);
  392         if (err)
  393                 return (err);
  394         fdisp_init(&fdi, sizeof(*flsi));
  395         fdisp_make_vp(&fdi, FUSE_LSEEK, vp, td, cred);
  396         flsi = fdi.indata;
  397         flsi->fh = fufh->fh_id;
  398         flsi->offset = *offp;
  399         flsi->whence = whence;
  400         err = fdisp_wait_answ(&fdi);
  401         if (err == ENOSYS) {
  402                 fsess_set_notimpl(mp, FUSE_LSEEK);
  403         } else if (err == 0) {
  404                 fsess_set_impl(mp, FUSE_LSEEK);
  405                 flso = fdi.answ;
  406                 *offp = flso->offset;
  407         }
  408         fdisp_destroy(&fdi);
  409 
  410         return (err);
  411 }
  412 
  413 /*
  414     struct vnop_access_args {
  415         struct vnode *a_vp;
  416 #if VOP_ACCESS_TAKES_ACCMODE_T
  417         accmode_t a_accmode;
  418 #else
  419         int a_mode;
  420 #endif
  421         struct ucred *a_cred;
  422         struct thread *a_td;
  423     };
  424 */
  425 static int
  426 fuse_vnop_access(struct vop_access_args *ap)
  427 {
  428         struct vnode *vp = ap->a_vp;
  429         int accmode = ap->a_accmode;
  430         struct ucred *cred = ap->a_cred;
  431 
  432         struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp));
  433 
  434         int err;
  435 
  436         if (fuse_isdeadfs(vp)) {
  437                 if (vnode_isvroot(vp)) {
  438                         return 0;
  439                 }
  440                 return ENXIO;
  441         }
  442         if (!(data->dataflags & FSESS_INITED)) {
  443                 if (vnode_isvroot(vp)) {
  444                         if (priv_check_cred(cred, PRIV_VFS_ADMIN) ||
  445                             (fuse_match_cred(data->daemoncred, cred) == 0)) {
  446                                 return 0;
  447                         }
  448                 }
  449                 return EBADF;
  450         }
  451         if (vnode_islnk(vp)) {
  452                 return 0;
  453         }
  454 
  455         err = fuse_internal_access(vp, accmode, ap->a_td, ap->a_cred);
  456         return err;
  457 }
  458 
  459 /*
  460  * struct vop_advlock_args {
  461  *      struct vop_generic_args a_gen;
  462  *      struct vnode *a_vp;
  463  *      void *a_id;
  464  *      int a_op;
  465  *      struct flock *a_fl;
  466  *      int a_flags;
  467  * }
  468  */
  469 static int
  470 fuse_vnop_advlock(struct vop_advlock_args *ap)
  471 {
  472         struct vnode *vp = ap->a_vp;
  473         struct flock *fl = ap->a_fl;
  474         struct thread *td = curthread;
  475         struct ucred *cred = td->td_ucred;
  476         pid_t pid = td->td_proc->p_pid;
  477         struct fuse_filehandle *fufh;
  478         struct fuse_dispatcher fdi;
  479         struct fuse_lk_in *fli;
  480         struct fuse_lk_out *flo;
  481         struct vattr vattr;
  482         enum fuse_opcode op;
  483         off_t size, start;
  484         int dataflags, err;
  485         int flags = ap->a_flags;
  486 
  487         dataflags = fuse_get_mpdata(vnode_mount(vp))->dataflags;
  488 
  489         if (fuse_isdeadfs(vp)) {
  490                 return ENXIO;
  491         }
  492 
  493         switch(ap->a_op) {
  494         case F_GETLK:
  495                 op = FUSE_GETLK;
  496                 break;
  497         case F_SETLK:
  498                 if (flags & F_WAIT)
  499                         op = FUSE_SETLKW;
  500                 else
  501                         op = FUSE_SETLK;
  502                 break;
  503         case F_UNLCK:
  504                 op = FUSE_SETLK;
  505                 break;
  506         default:
  507                 return EINVAL;
  508         }
  509 
  510         if (!(dataflags & FSESS_POSIX_LOCKS))
  511                 return vop_stdadvlock(ap);
  512         /* FUSE doesn't properly support flock until protocol 7.17 */
  513         if (flags & F_FLOCK)
  514                 return vop_stdadvlock(ap);
  515 
  516         vn_lock(vp, LK_SHARED | LK_RETRY);
  517 
  518         switch (fl->l_whence) {
  519         case SEEK_SET:
  520         case SEEK_CUR:
  521                 /*
  522                  * Caller is responsible for adding any necessary offset
  523                  * when SEEK_CUR is used.
  524                  */
  525                 start = fl->l_start;
  526                 break;
  527 
  528         case SEEK_END:
  529                 err = fuse_internal_getattr(vp, &vattr, cred, td);
  530                 if (err)
  531                         goto out;
  532                 size = vattr.va_size;
  533                 if (size > OFF_MAX ||
  534                     (fl->l_start > 0 && size > OFF_MAX - fl->l_start)) {
  535                         err = EOVERFLOW;
  536                         goto out;
  537                 }
  538                 start = size + fl->l_start;
  539                 break;
  540 
  541         default:
  542                 return (EINVAL);
  543         }
  544 
  545         err = fuse_filehandle_get_anyflags(vp, &fufh, cred, pid);
  546         if (err)
  547                 goto out;
  548 
  549         fdisp_init(&fdi, sizeof(*fli));
  550 
  551         fdisp_make_vp(&fdi, op, vp, td, cred);
  552         fli = fdi.indata;
  553         fli->fh = fufh->fh_id;
  554         fli->owner = td->td_proc->p_pid;
  555         fli->lk.start = start;
  556         if (fl->l_len != 0)
  557                 fli->lk.end = start + fl->l_len - 1;
  558         else
  559                 fli->lk.end = INT64_MAX;
  560         fli->lk.type = fl->l_type;
  561         fli->lk.pid = td->td_proc->p_pid;
  562 
  563         err = fdisp_wait_answ(&fdi);
  564         fdisp_destroy(&fdi);
  565 
  566         if (err == 0 && op == FUSE_GETLK) {
  567                 flo = fdi.answ;
  568                 fl->l_type = flo->lk.type;
  569                 fl->l_whence = SEEK_SET;
  570                 if (flo->lk.type != F_UNLCK) {
  571                         fl->l_pid = flo->lk.pid;
  572                         fl->l_start = flo->lk.start;
  573                         if (flo->lk.end == INT64_MAX)
  574                                 fl->l_len = 0;
  575                         else
  576                                 fl->l_len = flo->lk.end - flo->lk.start + 1;
  577                         fl->l_start = flo->lk.start;
  578                 }
  579         }
  580 
  581 out:
  582         VOP_UNLOCK(vp);
  583         return err;
  584 }
  585 
  586 static int
  587 fuse_vnop_allocate(struct vop_allocate_args *ap)
  588 {
  589         struct vnode *vp = ap->a_vp;
  590         off_t *len = ap->a_len;
  591         off_t *offset = ap->a_offset;
  592         struct ucred *cred = ap->a_cred;
  593         struct fuse_filehandle *fufh;
  594         struct mount *mp = vnode_mount(vp);
  595         struct fuse_dispatcher fdi;
  596         struct fuse_fallocate_in *ffi;
  597         struct uio io;
  598         pid_t pid = curthread->td_proc->p_pid;
  599         struct fuse_vnode_data *fvdat = VTOFUD(vp);
  600         off_t filesize;
  601         int err;
  602 
  603         if (fuse_isdeadfs(vp))
  604                 return (ENXIO);
  605 
  606         switch (vp->v_type) {
  607         case VFIFO:
  608                 return (ESPIPE);
  609         case VLNK:
  610         case VREG:
  611                 if (vfs_isrdonly(mp))
  612                         return (EROFS);
  613                 break;
  614         default:
  615                 return (ENODEV);
  616         }
  617 
  618         if (vfs_isrdonly(mp))
  619                 return (EROFS);
  620 
  621         if (fsess_not_impl(mp, FUSE_FALLOCATE))
  622                 return (EINVAL);
  623 
  624         io.uio_offset = *offset;
  625         io.uio_resid = *len;
  626         err = vn_rlimit_fsize(vp, &io, curthread);
  627         if (err)
  628                 return (err);
  629 
  630         err = fuse_filehandle_getrw(vp, FWRITE, &fufh, cred, pid);
  631         if (err)
  632                 return (err);
  633 
  634         fuse_vnode_update(vp, FN_MTIMECHANGE | FN_CTIMECHANGE);
  635 
  636         err = fuse_vnode_size(vp, &filesize, cred, curthread);
  637         if (err)
  638                 return (err);
  639         fuse_inval_buf_range(vp, filesize, *offset, *offset + *len);
  640 
  641         fdisp_init(&fdi, sizeof(*ffi));
  642         fdisp_make_vp(&fdi, FUSE_FALLOCATE, vp, curthread, cred);
  643         ffi = fdi.indata;
  644         ffi->fh = fufh->fh_id;
  645         ffi->offset = *offset;
  646         ffi->length = *len;
  647         ffi->mode = 0;
  648         err = fdisp_wait_answ(&fdi);
  649 
  650         if (err == ENOSYS) {
  651                 fsess_set_notimpl(mp, FUSE_FALLOCATE);
  652                 err = EINVAL;
  653         } else if (err == EOPNOTSUPP) {
  654                 /*
  655                  * The file system server does not support FUSE_FALLOCATE with
  656                  * the supplied mode for this particular file.
  657                  */
  658                 err = EINVAL;
  659         } else if (!err) {
  660                 *offset += *len;
  661                 *len = 0;
  662                 fuse_vnode_undirty_cached_timestamps(vp, false);
  663                 fuse_internal_clear_suid_on_write(vp, cred, curthread);
  664                 if (*offset > fvdat->cached_attrs.va_size) {
  665                         fuse_vnode_setsize(vp, *offset, false);
  666                         getnanouptime(&fvdat->last_local_modify);
  667                 }
  668         }
  669 
  670         return (err);
  671 }
  672 
  673 /* {
  674         struct vnode *a_vp;
  675         daddr_t a_bn;
  676         struct bufobj **a_bop;
  677         daddr_t *a_bnp;
  678         int *a_runp;
  679         int *a_runb;
  680 } */
  681 static int
  682 fuse_vnop_bmap(struct vop_bmap_args *ap)
  683 {
  684         struct vnode *vp = ap->a_vp;
  685         struct bufobj **bo = ap->a_bop;
  686         struct thread *td = curthread;
  687         struct mount *mp;
  688         struct fuse_dispatcher fdi;
  689         struct fuse_bmap_in *fbi;
  690         struct fuse_bmap_out *fbo;
  691         struct fuse_data *data;
  692         struct fuse_vnode_data *fvdat = VTOFUD(vp);
  693         uint64_t biosize;
  694         off_t fsize;
  695         daddr_t lbn = ap->a_bn;
  696         daddr_t *pbn = ap->a_bnp;
  697         int *runp = ap->a_runp;
  698         int *runb = ap->a_runb;
  699         int error = 0;
  700         int maxrun;
  701 
  702         if (fuse_isdeadfs(vp)) {
  703                 return ENXIO;
  704         }
  705 
  706         mp = vnode_mount(vp);
  707         data = fuse_get_mpdata(mp);
  708         biosize = fuse_iosize(vp);
  709         maxrun = MIN(vp->v_mount->mnt_iosize_max / biosize - 1,
  710                 data->max_readahead_blocks);
  711 
  712         if (bo != NULL)
  713                 *bo = &vp->v_bufobj;
  714 
  715         /*
  716          * The FUSE_BMAP operation does not include the runp and runb
  717          * variables, so we must guess.  Report nonzero contiguous runs so
  718          * cluster_read will combine adjacent reads.  It's worthwhile to reduce
  719          * upcalls even if we don't know the true physical layout of the file.
  720          * 
  721          * FUSE file systems may opt out of read clustering in two ways:
  722          * * mounting with -onoclusterr
  723          * * Setting max_readahead <= maxbcachebuf during FUSE_INIT
  724          */
  725         if (runb != NULL)
  726                 *runb = MIN(lbn, maxrun);
  727         if (runp != NULL && maxrun == 0)
  728                 *runp = 0;
  729         else if (runp != NULL) {
  730                 /*
  731                  * If the file's size is cached, use that value to calculate
  732                  * runp, even if the cache is expired.  runp is only advisory,
  733                  * and the risk of getting it wrong is not worth the cost of
  734                  * another upcall.
  735                  */
  736                 if (fvdat->cached_attrs.va_size != VNOVAL)
  737                         fsize = fvdat->cached_attrs.va_size;
  738                 else
  739                         error = fuse_vnode_size(vp, &fsize, td->td_ucred, td);
  740                 if (error == 0)
  741                         *runp = MIN(MAX(0, fsize / (off_t)biosize - lbn - 1),
  742                                     maxrun);
  743                 else
  744                         *runp = 0;
  745         }
  746 
  747         if (fsess_maybe_impl(mp, FUSE_BMAP)) {
  748                 fdisp_init(&fdi, sizeof(*fbi));
  749                 fdisp_make_vp(&fdi, FUSE_BMAP, vp, td, td->td_ucred);
  750                 fbi = fdi.indata;
  751                 fbi->block = lbn;
  752                 fbi->blocksize = biosize;
  753                 error = fdisp_wait_answ(&fdi);
  754                 if (error == ENOSYS) {
  755                         fdisp_destroy(&fdi);
  756                         fsess_set_notimpl(mp, FUSE_BMAP);
  757                         error = 0;
  758                 } else {
  759                         fbo = fdi.answ;
  760                         if (error == 0 && pbn != NULL)
  761                                 *pbn = fbo->block;
  762                         fdisp_destroy(&fdi);
  763                         return error;
  764                 }
  765         }
  766 
  767         /* If the daemon doesn't support BMAP, make up a sensible default */
  768         if (pbn != NULL)
  769                 *pbn = lbn * btodb(biosize);
  770         return (error);
  771 }
  772 
  773 /*
  774     struct vop_close_args {
  775         struct vnode *a_vp;
  776         int  a_fflag;
  777         struct ucred *a_cred;
  778         struct thread *a_td;
  779     };
  780 */
  781 static int
  782 fuse_vnop_close(struct vop_close_args *ap)
  783 {
  784         struct vnode *vp = ap->a_vp;
  785         struct ucred *cred = ap->a_cred;
  786         int fflag = ap->a_fflag;
  787         struct thread *td = ap->a_td;
  788         pid_t pid = td->td_proc->p_pid;
  789         struct fuse_vnode_data *fvdat = VTOFUD(vp);
  790         int err = 0;
  791 
  792         if (fuse_isdeadfs(vp))
  793                 return 0;
  794         if (vnode_isdir(vp))
  795                 return 0;
  796         if (fflag & IO_NDELAY)
  797                 return 0;
  798 
  799         err = fuse_flush(vp, cred, pid, fflag);
  800         if (err == 0 && (fvdat->flag & FN_ATIMECHANGE)) {
  801                 struct vattr vap;
  802 
  803                 VATTR_NULL(&vap);
  804                 vap.va_atime = fvdat->cached_attrs.va_atime;
  805                 err = fuse_internal_setattr(vp, &vap, td, NULL);
  806         }
  807         /* TODO: close the file handle, if we're sure it's no longer used */
  808         if ((fvdat->flag & FN_SIZECHANGE) != 0) {
  809                 fuse_vnode_savesize(vp, cred, td->td_proc->p_pid);
  810         }
  811         return err;
  812 }
  813 
  814 /*
  815    struct vop_copy_file_range_args {
  816         struct vop_generic_args a_gen;
  817         struct vnode *a_invp;
  818         off_t *a_inoffp;
  819         struct vnode *a_outvp;
  820         off_t *a_outoffp;
  821         size_t *a_lenp;
  822         unsigned int a_flags;
  823         struct ucred *a_incred;
  824         struct ucred *a_outcred;
  825         struct thread *a_fsizetd;
  826 }
  827  */
  828 static int
  829 fuse_vnop_copy_file_range(struct vop_copy_file_range_args *ap)
  830 {
  831         struct vnode *invp = ap->a_invp;
  832         struct vnode *outvp = ap->a_outvp;
  833         struct mount *mp = vnode_mount(invp);
  834         struct fuse_vnode_data *outfvdat = VTOFUD(outvp);
  835         struct fuse_dispatcher fdi;
  836         struct fuse_filehandle *infufh, *outfufh;
  837         struct fuse_copy_file_range_in *fcfri;
  838         struct ucred *incred = ap->a_incred;
  839         struct ucred *outcred = ap->a_outcred;
  840         struct fuse_write_out *fwo;
  841         struct thread *td;
  842         struct uio io;
  843         off_t outfilesize;
  844         ssize_t r = 0;
  845         pid_t pid;
  846         int err;
  847 
  848         if (mp != vnode_mount(outvp))
  849                 goto fallback;
  850 
  851         if (incred->cr_uid != outcred->cr_uid)
  852                 goto fallback;
  853 
  854         if (incred->cr_groups[0] != outcred->cr_groups[0])
  855                 goto fallback;
  856 
  857         if (fsess_not_impl(mp, FUSE_COPY_FILE_RANGE))
  858                 goto fallback;
  859 
  860         if (ap->a_fsizetd == NULL)
  861                 td = curthread;
  862         else
  863                 td = ap->a_fsizetd;
  864         pid = td->td_proc->p_pid;
  865 
  866         /* Lock both vnodes, avoiding risk of deadlock. */
  867         do {
  868                 err = vn_lock(outvp, LK_EXCLUSIVE);
  869                 if (invp == outvp)
  870                         break;
  871                 if (err == 0) {
  872                         err = vn_lock(invp, LK_SHARED | LK_NOWAIT);
  873                         if (err == 0)
  874                                 break;
  875                         VOP_UNLOCK(outvp);
  876                         err = vn_lock(invp, LK_SHARED);
  877                         if (err == 0)
  878                                 VOP_UNLOCK(invp);
  879                 }
  880         } while (err == 0);
  881         if (err != 0)
  882                 return (err);
  883 
  884         err = fuse_filehandle_getrw(invp, FREAD, &infufh, incred, pid);
  885         if (err)
  886                 goto unlock;
  887 
  888         err = fuse_filehandle_getrw(outvp, FWRITE, &outfufh, outcred, pid);
  889         if (err)
  890                 goto unlock;
  891 
  892         io.uio_resid = *ap->a_lenp;
  893         if (ap->a_fsizetd) {
  894                 io.uio_offset = *ap->a_outoffp;
  895                 err = vn_rlimit_fsizex(outvp, &io, 0, &r, ap->a_fsizetd);
  896                 if (err != 0)
  897                         goto unlock;
  898         }
  899 
  900         err = fuse_vnode_size(outvp, &outfilesize, outcred, curthread);
  901         if (err)
  902                 goto unlock;
  903 
  904         err = fuse_inval_buf_range(outvp, outfilesize, *ap->a_outoffp,
  905                 *ap->a_outoffp + io.uio_resid);
  906         if (err)
  907                 goto unlock;
  908 
  909         fdisp_init(&fdi, sizeof(*fcfri));
  910         fdisp_make_vp(&fdi, FUSE_COPY_FILE_RANGE, invp, td, incred);
  911         fcfri = fdi.indata;
  912         fcfri->fh_in = infufh->fh_id;
  913         fcfri->off_in = *ap->a_inoffp;
  914         fcfri->nodeid_out = VTOI(outvp);
  915         fcfri->fh_out = outfufh->fh_id;
  916         fcfri->off_out = *ap->a_outoffp;
  917         fcfri->len = io.uio_resid;
  918         fcfri->flags = 0;
  919 
  920         err = fdisp_wait_answ(&fdi);
  921         if (err == 0) {
  922                 fwo = fdi.answ;
  923                 *ap->a_lenp = fwo->size;
  924                 *ap->a_inoffp += fwo->size;
  925                 *ap->a_outoffp += fwo->size;
  926                 fuse_internal_clear_suid_on_write(outvp, outcred, td);
  927                 if (*ap->a_outoffp > outfvdat->cached_attrs.va_size) {
  928                         fuse_vnode_setsize(outvp, *ap->a_outoffp, false);
  929                         getnanouptime(&outfvdat->last_local_modify);
  930                 }
  931                 fuse_vnode_update(invp, FN_ATIMECHANGE);
  932                 fuse_vnode_update(outvp, FN_MTIMECHANGE | FN_CTIMECHANGE);
  933         }
  934         fdisp_destroy(&fdi);
  935 
  936 unlock:
  937         if (invp != outvp)
  938                 VOP_UNLOCK(invp);
  939         VOP_UNLOCK(outvp);
  940 
  941         if (err == ENOSYS) {
  942                 fsess_set_notimpl(mp, FUSE_COPY_FILE_RANGE);
  943 fallback:
  944                 err = vn_generic_copy_file_range(ap->a_invp, ap->a_inoffp,
  945                     ap->a_outvp, ap->a_outoffp, ap->a_lenp, ap->a_flags,
  946                     ap->a_incred, ap->a_outcred, ap->a_fsizetd);
  947         }
  948 
  949         /*
  950          * No need to call vn_rlimit_fsizex_res before return, since the uio is
  951          * local.
  952          */
  953         return (err);
  954 }
  955 
  956 static void
  957 fdisp_make_mknod_for_fallback(
  958         struct fuse_dispatcher *fdip,
  959         struct componentname *cnp,
  960         struct vnode *dvp,
  961         uint64_t parentnid,
  962         struct thread *td,
  963         struct ucred *cred,
  964         mode_t mode,
  965         enum fuse_opcode *op)
  966 {
  967         struct fuse_mknod_in *fmni;
  968 
  969         fdisp_init(fdip, sizeof(*fmni) + cnp->cn_namelen + 1);
  970         *op = FUSE_MKNOD;
  971         fdisp_make(fdip, *op, vnode_mount(dvp), parentnid, td, cred);
  972         fmni = fdip->indata;
  973         fmni->mode = mode;
  974         fmni->rdev = 0;
  975         memcpy((char *)fdip->indata + sizeof(*fmni), cnp->cn_nameptr,
  976             cnp->cn_namelen);
  977         ((char *)fdip->indata)[sizeof(*fmni) + cnp->cn_namelen] = '\0';
  978 }
  979 /*
  980     struct vnop_create_args {
  981         struct vnode *a_dvp;
  982         struct vnode **a_vpp;
  983         struct componentname *a_cnp;
  984         struct vattr *a_vap;
  985     };
  986 */
  987 static int
  988 fuse_vnop_create(struct vop_create_args *ap)
  989 {
  990         struct vnode *dvp = ap->a_dvp;
  991         struct vnode **vpp = ap->a_vpp;
  992         struct componentname *cnp = ap->a_cnp;
  993         struct vattr *vap = ap->a_vap;
  994         struct thread *td = curthread;
  995         struct ucred *cred = cnp->cn_cred;
  996 
  997         struct fuse_data *data;
  998         struct fuse_create_in *fci;
  999         struct fuse_entry_out *feo;
 1000         struct fuse_open_out *foo;
 1001         struct fuse_dispatcher fdi, fdi2;
 1002         struct fuse_dispatcher *fdip = &fdi;
 1003         struct fuse_dispatcher *fdip2 = NULL;
 1004 
 1005         int err;
 1006 
 1007         struct mount *mp = vnode_mount(dvp);
 1008         data = fuse_get_mpdata(mp);
 1009         uint64_t parentnid = VTOFUD(dvp)->nid;
 1010         mode_t mode = MAKEIMODE(vap->va_type, vap->va_mode);
 1011         enum fuse_opcode op;
 1012         int flags;
 1013 
 1014         if (fuse_isdeadfs(dvp))
 1015                 return ENXIO;
 1016 
 1017         /* FUSE expects sockets to be created with FUSE_MKNOD */
 1018         if (vap->va_type == VSOCK)
 1019                 return fuse_internal_mknod(dvp, vpp, cnp, vap);
 1020 
 1021         /* 
 1022          * VOP_CREATE doesn't tell us the open(2) flags, so we guess.  Only a
 1023          * writable mode makes sense, and we might as well include readability
 1024          * too.
 1025          */
 1026         flags = O_RDWR;
 1027 
 1028         bzero(&fdi, sizeof(fdi));
 1029 
 1030         if (vap->va_type != VREG)
 1031                 return (EINVAL);
 1032 
 1033         if (fsess_not_impl(mp, FUSE_CREATE) || vap->va_type == VSOCK) {
 1034                 /* Fallback to FUSE_MKNOD/FUSE_OPEN */
 1035                 fdisp_make_mknod_for_fallback(fdip, cnp, dvp, parentnid, td,
 1036                         cred, mode, &op);
 1037         } else {
 1038                 /* Use FUSE_CREATE */
 1039                 size_t insize;
 1040 
 1041                 op = FUSE_CREATE;
 1042                 fdisp_init(fdip, sizeof(*fci) + cnp->cn_namelen + 1);
 1043                 fdisp_make(fdip, op, vnode_mount(dvp), parentnid, td, cred);
 1044                 fci = fdip->indata;
 1045                 fci->mode = mode;
 1046                 fci->flags = O_CREAT | flags;
 1047                 if (fuse_libabi_geq(data, 7, 12)) {
 1048                         insize = sizeof(*fci);
 1049                         fci->umask = td->td_proc->p_pd->pd_cmask;
 1050                 } else {
 1051                         insize = sizeof(struct fuse_open_in);
 1052                 }
 1053 
 1054                 memcpy((char *)fdip->indata + insize, cnp->cn_nameptr,
 1055                     cnp->cn_namelen);
 1056                 ((char *)fdip->indata)[insize + cnp->cn_namelen] = '\0';
 1057         }
 1058 
 1059         err = fdisp_wait_answ(fdip);
 1060 
 1061         if (err) {
 1062                 if (err == ENOSYS && op == FUSE_CREATE) {
 1063                         fsess_set_notimpl(mp, FUSE_CREATE);
 1064                         fdisp_destroy(fdip);
 1065                         fdisp_make_mknod_for_fallback(fdip, cnp, dvp,
 1066                                 parentnid, td, cred, mode, &op);
 1067                         err = fdisp_wait_answ(fdip);
 1068                 }
 1069                 if (err)
 1070                         goto out;
 1071         }
 1072 
 1073         feo = fdip->answ;
 1074 
 1075         if ((err = fuse_internal_checkentry(feo, vap->va_type))) {
 1076                 goto out;
 1077         }
 1078 
 1079         if (op == FUSE_CREATE) {
 1080                 if (fuse_libabi_geq(data, 7, 9))
 1081                         foo = (struct fuse_open_out*)(feo + 1);
 1082                 else
 1083                         foo = (struct fuse_open_out*)((char*)feo +
 1084                                 FUSE_COMPAT_ENTRY_OUT_SIZE);
 1085         } else {
 1086                 /* Issue a separate FUSE_OPEN */
 1087                 struct fuse_open_in *foi;
 1088 
 1089                 fdip2 = &fdi2;
 1090                 fdisp_init(fdip2, sizeof(*foi));
 1091                 fdisp_make(fdip2, FUSE_OPEN, vnode_mount(dvp), feo->nodeid, td,
 1092                         cred);
 1093                 foi = fdip2->indata;
 1094                 foi->flags = flags;
 1095                 err = fdisp_wait_answ(fdip2);
 1096                 if (err)
 1097                         goto out;
 1098                 foo = fdip2->answ;
 1099         }
 1100         err = fuse_vnode_get(mp, feo, feo->nodeid, dvp, vpp, cnp, vap->va_type);
 1101         if (err) {
 1102                 struct fuse_release_in *fri;
 1103                 uint64_t nodeid = feo->nodeid;
 1104                 uint64_t fh_id = foo->fh;
 1105 
 1106                 fdisp_init(fdip, sizeof(*fri));
 1107                 fdisp_make(fdip, FUSE_RELEASE, mp, nodeid, td, cred);
 1108                 fri = fdip->indata;
 1109                 fri->fh = fh_id;
 1110                 fri->flags = flags;
 1111                 fuse_insert_callback(fdip->tick, fuse_internal_forget_callback);
 1112                 fuse_insert_message(fdip->tick, false);
 1113                 goto out;
 1114         }
 1115         ASSERT_VOP_ELOCKED(*vpp, "fuse_vnop_create");
 1116         fuse_internal_cache_attrs(*vpp, &feo->attr, feo->attr_valid,
 1117                 feo->attr_valid_nsec, NULL, true);
 1118 
 1119         fuse_filehandle_init(*vpp, FUFH_RDWR, NULL, td, cred, foo);
 1120         fuse_vnode_open(*vpp, foo->open_flags, td);
 1121         /* 
 1122          * Purge the parent's attribute cache because the daemon should've
 1123          * updated its mtime and ctime
 1124          */
 1125         fuse_vnode_clear_attr_cache(dvp);
 1126         cache_purge_negative(dvp);
 1127 
 1128 out:
 1129         if (fdip2)
 1130                 fdisp_destroy(fdip2);
 1131         fdisp_destroy(fdip);
 1132         return err;
 1133 }
 1134 
 1135 /*
 1136     struct vnop_fdatasync_args {
 1137         struct vop_generic_args a_gen;
 1138         struct vnode * a_vp;
 1139         struct thread * a_td;
 1140     };
 1141 */
 1142 static int
 1143 fuse_vnop_fdatasync(struct vop_fdatasync_args *ap)
 1144 {
 1145         struct vnode *vp = ap->a_vp;
 1146         struct thread *td = ap->a_td;
 1147         int waitfor = MNT_WAIT;
 1148 
 1149         int err = 0;
 1150 
 1151         if (fuse_isdeadfs(vp)) {
 1152                 return 0;
 1153         }
 1154         if ((err = vop_stdfdatasync_buf(ap)))
 1155                 return err;
 1156 
 1157         return fuse_internal_fsync(vp, td, waitfor, true);
 1158 }
 1159 
 1160 /*
 1161     struct vnop_fsync_args {
 1162         struct vop_generic_args a_gen;
 1163         struct vnode * a_vp;
 1164         int  a_waitfor;
 1165         struct thread * a_td;
 1166     };
 1167 */
 1168 static int
 1169 fuse_vnop_fsync(struct vop_fsync_args *ap)
 1170 {
 1171         struct vnode *vp = ap->a_vp;
 1172         struct thread *td = ap->a_td;
 1173         int waitfor = ap->a_waitfor;
 1174         int err = 0;
 1175 
 1176         if (fuse_isdeadfs(vp)) {
 1177                 return 0;
 1178         }
 1179         if ((err = vop_stdfsync(ap)))
 1180                 return err;
 1181 
 1182         return fuse_internal_fsync(vp, td, waitfor, false);
 1183 }
 1184 
 1185 /*
 1186     struct vnop_getattr_args {
 1187         struct vnode *a_vp;
 1188         struct vattr *a_vap;
 1189         struct ucred *a_cred;
 1190         struct thread *a_td;
 1191     };
 1192 */
 1193 static int
 1194 fuse_vnop_getattr(struct vop_getattr_args *ap)
 1195 {
 1196         struct vnode *vp = ap->a_vp;
 1197         struct vattr *vap = ap->a_vap;
 1198         struct ucred *cred = ap->a_cred;
 1199         struct thread *td = curthread;
 1200 
 1201         int err = 0;
 1202         int dataflags;
 1203 
 1204         dataflags = fuse_get_mpdata(vnode_mount(vp))->dataflags;
 1205 
 1206         /* Note that we are not bailing out on a dead file system just yet. */
 1207 
 1208         if (!(dataflags & FSESS_INITED)) {
 1209                 if (!vnode_isvroot(vp)) {
 1210                         fdata_set_dead(fuse_get_mpdata(vnode_mount(vp)));
 1211                         err = ENOTCONN;
 1212                         return err;
 1213                 } else {
 1214                         goto fake;
 1215                 }
 1216         }
 1217         err = fuse_internal_getattr(vp, vap, cred, td);
 1218         if (err == ENOTCONN && vnode_isvroot(vp)) {
 1219                 /* see comment in fuse_vfsop_statfs() */
 1220                 goto fake;
 1221         } else {
 1222                 return err;
 1223         }
 1224 
 1225 fake:
 1226         bzero(vap, sizeof(*vap));
 1227         vap->va_type = vnode_vtype(vp);
 1228 
 1229         return 0;
 1230 }
 1231 
 1232 /*
 1233     struct vnop_inactive_args {
 1234         struct vnode *a_vp;
 1235     };
 1236 */
 1237 static int
 1238 fuse_vnop_inactive(struct vop_inactive_args *ap)
 1239 {
 1240         struct vnode *vp = ap->a_vp;
 1241         struct thread *td = curthread;
 1242 
 1243         struct fuse_vnode_data *fvdat = VTOFUD(vp);
 1244         struct fuse_filehandle *fufh, *fufh_tmp;
 1245 
 1246         int need_flush = 1;
 1247 
 1248         LIST_FOREACH_SAFE(fufh, &fvdat->handles, next, fufh_tmp) {
 1249                 if (need_flush && vp->v_type == VREG) {
 1250                         if ((VTOFUD(vp)->flag & FN_SIZECHANGE) != 0) {
 1251                                 fuse_vnode_savesize(vp, NULL, 0);
 1252                         }
 1253                         if ((fvdat->flag & FN_REVOKED) != 0)
 1254                                 fuse_io_invalbuf(vp, td);
 1255                         else
 1256                                 fuse_io_flushbuf(vp, MNT_WAIT, td);
 1257                         need_flush = 0;
 1258                 }
 1259                 fuse_filehandle_close(vp, fufh, td, NULL);
 1260         }
 1261 
 1262         if ((fvdat->flag & FN_REVOKED) != 0)
 1263                 vrecycle(vp);
 1264 
 1265         return 0;
 1266 }
 1267 
 1268 /*
 1269     struct vnop_ioctl_args {
 1270         struct vnode *a_vp;
 1271         u_long a_command;
 1272         caddr_t a_data;
 1273         int a_fflag;
 1274         struct ucred *a_cred;
 1275         struct thread *a_td;
 1276     };
 1277 */
 1278 static int
 1279 fuse_vnop_ioctl(struct vop_ioctl_args *ap)
 1280 {
 1281         struct vnode *vp = ap->a_vp;
 1282         struct mount *mp = vnode_mount(vp);
 1283         struct ucred *cred = ap->a_cred;
 1284         off_t *offp;
 1285         pid_t pid = ap->a_td->td_proc->p_pid;
 1286         int err;
 1287 
 1288         switch (ap->a_command) {
 1289         case FIOSEEKDATA:
 1290         case FIOSEEKHOLE:
 1291                 /* Call FUSE_LSEEK, if we can, or fall back to vop_stdioctl */
 1292                 if (fsess_maybe_impl(mp, FUSE_LSEEK)) {
 1293                         int whence;
 1294 
 1295                         offp = ap->a_data;
 1296                         if (ap->a_command == FIOSEEKDATA)
 1297                                 whence = SEEK_DATA;
 1298                         else
 1299                                 whence = SEEK_HOLE;
 1300 
 1301                         vn_lock(vp, LK_SHARED | LK_RETRY);
 1302                         err = fuse_vnop_do_lseek(vp, ap->a_td, cred, pid, offp,
 1303                             whence);
 1304                         VOP_UNLOCK(vp);
 1305                 }
 1306                 if (fsess_not_impl(mp, FUSE_LSEEK))
 1307                         err = vop_stdioctl(ap);
 1308                 break;
 1309         default:
 1310                 /* TODO: implement FUSE_IOCTL */
 1311                 err = ENOTTY;
 1312                 break;
 1313         }
 1314         return (err);
 1315 }
 1316 
 1317 
 1318 /*
 1319     struct vnop_link_args {
 1320         struct vnode *a_tdvp;
 1321         struct vnode *a_vp;
 1322         struct componentname *a_cnp;
 1323     };
 1324 */
 1325 static int
 1326 fuse_vnop_link(struct vop_link_args *ap)
 1327 {
 1328         struct vnode *vp = ap->a_vp;
 1329         struct vnode *tdvp = ap->a_tdvp;
 1330         struct componentname *cnp = ap->a_cnp;
 1331 
 1332         struct vattr *vap = VTOVA(vp);
 1333 
 1334         struct fuse_dispatcher fdi;
 1335         struct fuse_entry_out *feo;
 1336         struct fuse_link_in fli;
 1337 
 1338         int err;
 1339 
 1340         if (fuse_isdeadfs(vp)) {
 1341                 return ENXIO;
 1342         }
 1343         if (vnode_mount(tdvp) != vnode_mount(vp)) {
 1344                 return EXDEV;
 1345         }
 1346 
 1347         /*
 1348          * This is a seatbelt check to protect naive userspace filesystems from
 1349          * themselves and the limitations of the FUSE IPC protocol.  If a
 1350          * filesystem does not allow attribute caching, assume it is capable of
 1351          * validating that nlink does not overflow.
 1352          */
 1353         if (vap != NULL && vap->va_nlink >= FUSE_LINK_MAX)
 1354                 return EMLINK;
 1355         fli.oldnodeid = VTOI(vp);
 1356 
 1357         fdisp_init(&fdi, 0);
 1358         fuse_internal_newentry_makerequest(vnode_mount(tdvp), VTOI(tdvp), cnp,
 1359             FUSE_LINK, &fli, sizeof(fli), &fdi);
 1360         if ((err = fdisp_wait_answ(&fdi))) {
 1361                 goto out;
 1362         }
 1363         feo = fdi.answ;
 1364 
 1365         if (fli.oldnodeid != feo->nodeid) {
 1366                 struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp));
 1367                 fuse_warn(data, FSESS_WARN_ILLEGAL_INODE,
 1368                         "Assigned wrong inode for a hard link.");
 1369                 fuse_vnode_clear_attr_cache(vp);
 1370                 fuse_vnode_clear_attr_cache(tdvp);
 1371                 err = EIO;
 1372                 goto out;
 1373         }
 1374 
 1375         err = fuse_internal_checkentry(feo, vnode_vtype(vp));
 1376         if (!err) {
 1377                 /* 
 1378                  * Purge the parent's attribute cache because the daemon
 1379                  * should've updated its mtime and ctime
 1380                  */
 1381                 fuse_vnode_clear_attr_cache(tdvp);
 1382                 fuse_internal_cache_attrs(vp, &feo->attr, feo->attr_valid,
 1383                         feo->attr_valid_nsec, NULL, true);
 1384         }
 1385 out:
 1386         fdisp_destroy(&fdi);
 1387         return err;
 1388 }
 1389 
 1390 struct fuse_lookup_alloc_arg {
 1391         struct fuse_entry_out *feo;
 1392         struct componentname *cnp;
 1393         uint64_t nid;
 1394         enum vtype vtyp;
 1395 };
 1396 
 1397 /* Callback for vn_get_ino */
 1398 static int
 1399 fuse_lookup_alloc(struct mount *mp, void *arg, int lkflags, struct vnode **vpp)
 1400 {
 1401         struct fuse_lookup_alloc_arg *flaa = arg;
 1402 
 1403         return fuse_vnode_get(mp, flaa->feo, flaa->nid, NULL, vpp, flaa->cnp,
 1404                 flaa->vtyp);
 1405 }
 1406 
 1407 SDT_PROBE_DEFINE3(fusefs, , vnops, cache_lookup,
 1408         "int", "struct timespec*", "struct timespec*");
 1409 /*
 1410     struct vnop_lookup_args {
 1411         struct vnodeop_desc *a_desc;
 1412         struct vnode *a_dvp;
 1413         struct vnode **a_vpp;
 1414         struct componentname *a_cnp;
 1415     };
 1416 */
 1417 int
 1418 fuse_vnop_lookup(struct vop_lookup_args *ap)
 1419 {
 1420         struct vnode *dvp = ap->a_dvp;
 1421         struct vnode **vpp = ap->a_vpp;
 1422         struct componentname *cnp = ap->a_cnp;
 1423         struct thread *td = curthread;
 1424         struct ucred *cred = cnp->cn_cred;
 1425         struct timespec now;
 1426 
 1427         int nameiop = cnp->cn_nameiop;
 1428         int flags = cnp->cn_flags;
 1429         int islastcn = flags & ISLASTCN;
 1430         struct mount *mp = vnode_mount(dvp);
 1431         struct fuse_data *data = fuse_get_mpdata(mp);
 1432         int default_permissions = data->dataflags & FSESS_DEFAULT_PERMISSIONS;
 1433         bool is_dot;
 1434 
 1435         int err = 0;
 1436         int lookup_err = 0;
 1437         struct vnode *vp = NULL;
 1438 
 1439         struct fuse_dispatcher fdi;
 1440         bool did_lookup = false;
 1441         struct fuse_entry_out *feo = NULL;
 1442         enum vtype vtyp;        /* vnode type of target */
 1443 
 1444         uint64_t nid;
 1445 
 1446         if (fuse_isdeadfs(dvp)) {
 1447                 *vpp = NULL;
 1448                 return ENXIO;
 1449         }
 1450         if (!vnode_isdir(dvp))
 1451                 return ENOTDIR;
 1452 
 1453         if (islastcn && vfs_isrdonly(mp) && (nameiop != LOOKUP))
 1454                 return EROFS;
 1455 
 1456         if ((cnp->cn_flags & NOEXECCHECK) != 0)
 1457                 cnp->cn_flags &= ~NOEXECCHECK;
 1458         else if ((err = fuse_internal_access(dvp, VEXEC, td, cred)))
 1459                 return err;
 1460 
 1461         is_dot = cnp->cn_namelen == 1 && *(cnp->cn_nameptr) == '.';
 1462         if ((flags & ISDOTDOT) && !(data->dataflags & FSESS_EXPORT_SUPPORT))
 1463         {
 1464                 if (!(VTOFUD(dvp)->flag & FN_PARENT_NID)) {
 1465                         /*
 1466                          * Since the file system doesn't support ".." lookups,
 1467                          * we have no way to find this entry.
 1468                          */
 1469                         return ESTALE;
 1470                 }
 1471                 nid = VTOFUD(dvp)->parent_nid;
 1472                 if (nid == 0)
 1473                         return ENOENT;
 1474                 /* .. is obviously a directory */
 1475                 vtyp = VDIR;
 1476         } else if (is_dot) {
 1477                 nid = VTOI(dvp);
 1478                 /* . is obviously a directory */
 1479                 vtyp = VDIR;
 1480         } else {
 1481                 struct timespec timeout;
 1482                 int ncpticks; /* here to accommodate for API contract */
 1483 
 1484                 err = cache_lookup(dvp, vpp, cnp, &timeout, &ncpticks);
 1485                 getnanouptime(&now);
 1486                 SDT_PROBE3(fusefs, , vnops, cache_lookup, err, &timeout, &now);
 1487                 switch (err) {
 1488                 case -1:                /* positive match */
 1489                         if (timespeccmp(&timeout, &now, >)) {
 1490                                 counter_u64_add(fuse_lookup_cache_hits, 1);
 1491                         } else {
 1492                                 /* Cache timeout */
 1493                                 counter_u64_add(fuse_lookup_cache_misses, 1);
 1494                                 bintime_clear(
 1495                                         &VTOFUD(*vpp)->entry_cache_timeout);
 1496                                 cache_purge(*vpp);
 1497                                 if (dvp != *vpp)
 1498                                         vput(*vpp);
 1499                                 else 
 1500                                         vrele(*vpp);
 1501                                 *vpp = NULL;
 1502                                 break;
 1503                         }
 1504                         return 0;
 1505 
 1506                 case 0:         /* no match in cache */
 1507                         counter_u64_add(fuse_lookup_cache_misses, 1);
 1508                         break;
 1509 
 1510                 case ENOENT:            /* negative match */
 1511                         if (timespeccmp(&timeout, &now, <=)) {
 1512                                 /* Cache timeout */
 1513                                 cache_purge_negative(dvp);
 1514                                 break;
 1515                         }
 1516                         /* fall through */
 1517                 default:
 1518                         return err;
 1519                 }
 1520 
 1521                 fdisp_init(&fdi, cnp->cn_namelen + 1);
 1522                 fdisp_make(&fdi, FUSE_LOOKUP, mp, VTOI(dvp), td, cred);
 1523 
 1524                 memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
 1525                 ((char *)fdi.indata)[cnp->cn_namelen] = '\0';
 1526                 lookup_err = fdisp_wait_answ(&fdi);
 1527                 did_lookup = true;
 1528 
 1529                 if (!lookup_err) {
 1530                         /* lookup call succeeded */
 1531                         feo = (struct fuse_entry_out *)fdi.answ;
 1532                         nid = feo->nodeid;
 1533                         if (nid == 0) {
 1534                                 /* zero nodeid means ENOENT and cache it */
 1535                                 struct timespec timeout;
 1536 
 1537                                 fdi.answ_stat = ENOENT;
 1538                                 lookup_err = ENOENT;
 1539                                 if (cnp->cn_flags & MAKEENTRY) {
 1540                                         fuse_validity_2_timespec(feo, &timeout);
 1541                                         /* Use the same entry_time for .. as for
 1542                                          * the file itself.  That doesn't honor
 1543                                          * exactly what the fuse server tells
 1544                                          * us, but to do otherwise would require
 1545                                          * another cache lookup at this point.
 1546                                          */
 1547                                         struct timespec *dtsp = NULL;
 1548                                         cache_enter_time(dvp, *vpp, cnp,
 1549                                                 &timeout, dtsp);
 1550                                 }
 1551                         }
 1552                         vtyp = IFTOVT(feo->attr.mode);
 1553                 }
 1554                 if (lookup_err && (!fdi.answ_stat || lookup_err != ENOENT)) {
 1555                         fdisp_destroy(&fdi);
 1556                         return lookup_err;
 1557                 }
 1558         }
 1559         /* lookup_err, if non-zero, must be ENOENT at this point */
 1560 
 1561         if (lookup_err) {
 1562                 /* Entry not found */
 1563                 if ((nameiop == CREATE || nameiop == RENAME) && islastcn) {
 1564                         if (default_permissions)
 1565                                 err = fuse_internal_access(dvp, VWRITE, td,
 1566                                     cred);
 1567                         else
 1568                                 err = 0;
 1569                         if (!err) {
 1570                                 err = EJUSTRETURN;
 1571                         }
 1572                 } else {
 1573                         err = ENOENT;
 1574                 }
 1575         } else {
 1576                 /* Entry was found */
 1577                 if (flags & ISDOTDOT) {
 1578                         struct fuse_lookup_alloc_arg flaa;
 1579 
 1580                         flaa.nid = nid;
 1581                         flaa.feo = feo;
 1582                         flaa.cnp = cnp;
 1583                         flaa.vtyp = vtyp;
 1584                         err = vn_vget_ino_gen(dvp, fuse_lookup_alloc, &flaa, 0,
 1585                                 &vp);
 1586                         *vpp = vp;
 1587                 } else if (nid == VTOI(dvp)) {
 1588                         if (is_dot) {
 1589                                 vref(dvp);
 1590                                 *vpp = dvp;
 1591                         } else {
 1592                                 fuse_warn(fuse_get_mpdata(mp),
 1593                                     FSESS_WARN_ILLEGAL_INODE,
 1594                                     "Assigned same inode to both parent and "
 1595                                     "child.");
 1596                                 err = EIO;
 1597                         }
 1598 
 1599                 } else {
 1600                         struct fuse_vnode_data *fvdat;
 1601 
 1602                         err = fuse_vnode_get(vnode_mount(dvp), feo, nid, dvp,
 1603                             &vp, cnp, vtyp);
 1604                         if (err)
 1605                                 goto out;
 1606                         *vpp = vp;
 1607                         fvdat = VTOFUD(vp);
 1608 
 1609                         MPASS(feo != NULL);
 1610                         if (timespeccmp(&now, &fvdat->last_local_modify, >)) {
 1611                                 /*
 1612                                  * Attributes from the server are definitely
 1613                                  * newer than the last attributes we sent to
 1614                                  * the server, so cache them.
 1615                                  */
 1616                                 fuse_internal_cache_attrs(*vpp, &feo->attr,
 1617                                         feo->attr_valid, feo->attr_valid_nsec,
 1618                                         NULL, true);
 1619                         }
 1620                         fuse_validity_2_bintime(feo->entry_valid,
 1621                                 feo->entry_valid_nsec,
 1622                                 &fvdat->entry_cache_timeout);
 1623 
 1624                         if ((nameiop == DELETE || nameiop == RENAME) &&
 1625                                 islastcn && default_permissions)
 1626                         {
 1627                                 struct vattr dvattr;
 1628 
 1629                                 err = fuse_internal_access(dvp, VWRITE, td,
 1630                                         cred);
 1631                                 if (err != 0)
 1632                                         goto out;
 1633                                 /* 
 1634                                  * if the parent's sticky bit is set, check
 1635                                  * whether we're allowed to remove the file.
 1636                                  * Need to figure out the vnode locking to make
 1637                                  * this work.
 1638                                  */
 1639                                 fuse_internal_getattr(dvp, &dvattr, cred, td);
 1640                                 if ((dvattr.va_mode & S_ISTXT) &&
 1641                                         fuse_internal_access(dvp, VADMIN, td,
 1642                                                 cred) &&
 1643                                         fuse_internal_access(*vpp, VADMIN, td,
 1644                                                 cred)) {
 1645                                         err = EPERM;
 1646                                         goto out;
 1647                                 }
 1648                         }
 1649                 }
 1650         }
 1651 out:
 1652         if (err) {
 1653                 if (vp != NULL && dvp != vp)
 1654                         vput(vp);
 1655                 else if (vp != NULL)
 1656                         vrele(vp);
 1657                 *vpp = NULL;
 1658         }
 1659         if (did_lookup)
 1660                 fdisp_destroy(&fdi);
 1661 
 1662         return err;
 1663 }
 1664 
 1665 /*
 1666     struct vnop_mkdir_args {
 1667         struct vnode *a_dvp;
 1668         struct vnode **a_vpp;
 1669         struct componentname *a_cnp;
 1670         struct vattr *a_vap;
 1671     };
 1672 */
 1673 static int
 1674 fuse_vnop_mkdir(struct vop_mkdir_args *ap)
 1675 {
 1676         struct vnode *dvp = ap->a_dvp;
 1677         struct vnode **vpp = ap->a_vpp;
 1678         struct componentname *cnp = ap->a_cnp;
 1679         struct vattr *vap = ap->a_vap;
 1680 
 1681         struct fuse_mkdir_in fmdi;
 1682 
 1683         if (fuse_isdeadfs(dvp)) {
 1684                 return ENXIO;
 1685         }
 1686         fmdi.mode = MAKEIMODE(vap->va_type, vap->va_mode);
 1687         fmdi.umask = curthread->td_proc->p_pd->pd_cmask;
 1688 
 1689         return (fuse_internal_newentry(dvp, vpp, cnp, FUSE_MKDIR, &fmdi,
 1690             sizeof(fmdi), VDIR));
 1691 }
 1692 
 1693 /*
 1694     struct vnop_mknod_args {
 1695         struct vnode *a_dvp;
 1696         struct vnode **a_vpp;
 1697         struct componentname *a_cnp;
 1698         struct vattr *a_vap;
 1699     };
 1700 */
 1701 static int
 1702 fuse_vnop_mknod(struct vop_mknod_args *ap)
 1703 {
 1704 
 1705         struct vnode *dvp = ap->a_dvp;
 1706         struct vnode **vpp = ap->a_vpp;
 1707         struct componentname *cnp = ap->a_cnp;
 1708         struct vattr *vap = ap->a_vap;
 1709 
 1710         if (fuse_isdeadfs(dvp))
 1711                 return ENXIO;
 1712 
 1713         return fuse_internal_mknod(dvp, vpp, cnp, vap);
 1714 }
 1715 
 1716 /*
 1717     struct vop_open_args {
 1718         struct vnode *a_vp;
 1719         int  a_mode;
 1720         struct ucred *a_cred;
 1721         struct thread *a_td;
 1722         int a_fdidx; / struct file *a_fp;
 1723     };
 1724 */
 1725 static int
 1726 fuse_vnop_open(struct vop_open_args *ap)
 1727 {
 1728         struct vnode *vp = ap->a_vp;
 1729         int a_mode = ap->a_mode;
 1730         struct thread *td = ap->a_td;
 1731         struct ucred *cred = ap->a_cred;
 1732         pid_t pid = td->td_proc->p_pid;
 1733 
 1734         if (fuse_isdeadfs(vp))
 1735                 return ENXIO;
 1736         if (vp->v_type == VCHR || vp->v_type == VBLK || vp->v_type == VFIFO)
 1737                 return (EOPNOTSUPP);
 1738         if ((a_mode & (FREAD | FWRITE | FEXEC)) == 0)
 1739                 return EINVAL;
 1740 
 1741         if (fuse_filehandle_validrw(vp, a_mode, cred, pid)) {
 1742                 fuse_vnode_open(vp, 0, td);
 1743                 return 0;
 1744         }
 1745 
 1746         return fuse_filehandle_open(vp, a_mode, NULL, td, cred);
 1747 }
 1748 
 1749 static int
 1750 fuse_vnop_pathconf(struct vop_pathconf_args *ap)
 1751 {
 1752         struct vnode *vp = ap->a_vp;
 1753         struct mount *mp;
 1754 
 1755         switch (ap->a_name) {
 1756         case _PC_FILESIZEBITS:
 1757                 *ap->a_retval = 64;
 1758                 return (0);
 1759         case _PC_NAME_MAX:
 1760                 *ap->a_retval = NAME_MAX;
 1761                 return (0);
 1762         case _PC_LINK_MAX:
 1763                 *ap->a_retval = MIN(LONG_MAX, FUSE_LINK_MAX);
 1764                 return (0);
 1765         case _PC_SYMLINK_MAX:
 1766                 *ap->a_retval = MAXPATHLEN;
 1767                 return (0);
 1768         case _PC_NO_TRUNC:
 1769                 *ap->a_retval = 1;
 1770                 return (0);
 1771         case _PC_MIN_HOLE_SIZE:
 1772                 /*
 1773                  * The FUSE protocol provides no mechanism for a server to
 1774                  * report _PC_MIN_HOLE_SIZE.  It's a protocol bug.  Instead,
 1775                  * return EINVAL if the server does not support FUSE_LSEEK, or
 1776                  * 1 if it does.
 1777                  */
 1778                 mp = vnode_mount(vp);
 1779                 if (!fsess_is_impl(mp, FUSE_LSEEK) &&
 1780                     !fsess_not_impl(mp, FUSE_LSEEK)) {
 1781                         off_t offset = 0;
 1782 
 1783                         /* Issue a FUSE_LSEEK to find out if it's implemented */
 1784                         fuse_vnop_do_lseek(vp, curthread, curthread->td_ucred,
 1785                             curthread->td_proc->p_pid, &offset, SEEK_DATA);
 1786                 }
 1787 
 1788                 if (fsess_is_impl(mp, FUSE_LSEEK)) {
 1789                         *ap->a_retval = 1;
 1790                         return (0);
 1791                 } else {
 1792                         /*
 1793                          * Probably FUSE_LSEEK is not implemented.  It might
 1794                          * be, if the FUSE_LSEEK above returned an error like
 1795                          * EACCES, but in that case we can't tell, so it's
 1796                          * safest to report EINVAL anyway.
 1797                          */
 1798                         return (EINVAL);
 1799                 }
 1800         default:
 1801                 return (vop_stdpathconf(ap));
 1802         }
 1803 }
 1804 
 1805 SDT_PROBE_DEFINE3(fusefs, , vnops, filehandles_closed, "struct vnode*",
 1806     "struct uio*", "struct ucred*");
 1807 /*
 1808     struct vnop_read_args {
 1809         struct vnode *a_vp;
 1810         struct uio *a_uio;
 1811         int  a_ioflag;
 1812         struct ucred *a_cred;
 1813     };
 1814 */
 1815 static int
 1816 fuse_vnop_read(struct vop_read_args *ap)
 1817 {
 1818         struct vnode *vp = ap->a_vp;
 1819         struct uio *uio = ap->a_uio;
 1820         int ioflag = ap->a_ioflag;
 1821         struct ucred *cred = ap->a_cred;
 1822         pid_t pid = curthread->td_proc->p_pid;
 1823         struct fuse_filehandle *fufh;
 1824         int err;
 1825         bool closefufh = false, directio;
 1826 
 1827         MPASS(vp->v_type == VREG || vp->v_type == VDIR);
 1828 
 1829         if (fuse_isdeadfs(vp)) {
 1830                 return ENXIO;
 1831         }
 1832 
 1833         if (VTOFUD(vp)->flag & FN_DIRECTIO) {
 1834                 ioflag |= IO_DIRECT;
 1835         }
 1836 
 1837         err = fuse_filehandle_getrw(vp, FREAD, &fufh, cred, pid);
 1838         if (err == EBADF && vnode_mount(vp)->mnt_flag & MNT_EXPORTED) {
 1839                 /*
 1840                  * nfsd will do I/O without first doing VOP_OPEN.  We
 1841                  * must implicitly open the file here
 1842                  */
 1843                 err = fuse_filehandle_open(vp, FREAD, &fufh, curthread, cred);
 1844                 closefufh = true;
 1845         }
 1846         if (err) {
 1847                 SDT_PROBE3(fusefs, , vnops, filehandles_closed, vp, uio, cred);
 1848                 return err;
 1849         }
 1850 
 1851         /*
 1852          * Ideally, when the daemon asks for direct io at open time, the
 1853          * standard file flag should be set according to this, so that would
 1854          * just change the default mode, which later on could be changed via
 1855          * fcntl(2).
 1856          * But this doesn't work, the O_DIRECT flag gets cleared at some point
 1857          * (don't know where). So to make any use of the Fuse direct_io option,
 1858          * we hardwire it into the file's private data (similarly to Linux,
 1859          * btw.).
 1860          */
 1861         directio = (ioflag & IO_DIRECT) || !fsess_opt_datacache(vnode_mount(vp));
 1862 
 1863         fuse_vnode_update(vp, FN_ATIMECHANGE);
 1864         if (directio) {
 1865                 SDT_PROBE2(fusefs, , vnops, trace, 1, "direct read of vnode");
 1866                 err = fuse_read_directbackend(vp, uio, cred, fufh);
 1867         } else {
 1868                 SDT_PROBE2(fusefs, , vnops, trace, 1, "buffered read of vnode");
 1869                 err = fuse_read_biobackend(vp, uio, ioflag, cred, fufh, pid);
 1870         }
 1871 
 1872         if (closefufh)
 1873                 fuse_filehandle_close(vp, fufh, curthread, cred);
 1874 
 1875         return (err);
 1876 }
 1877 
 1878 /*
 1879     struct vnop_readdir_args {
 1880         struct vnode *a_vp;
 1881         struct uio *a_uio;
 1882         struct ucred *a_cred;
 1883         int *a_eofflag;
 1884         int *a_ncookies;
 1885         uint64_t **a_cookies;
 1886     };
 1887 */
 1888 static int
 1889 fuse_vnop_readdir(struct vop_readdir_args *ap)
 1890 {
 1891         struct vnode *vp = ap->a_vp;
 1892         struct uio *uio = ap->a_uio;
 1893         struct ucred *cred = ap->a_cred;
 1894         struct fuse_filehandle *fufh = NULL;
 1895         struct mount *mp = vnode_mount(vp);
 1896         struct fuse_iov cookediov;
 1897         int err = 0;
 1898         uint64_t *cookies;
 1899         ssize_t tresid;
 1900         int ncookies;
 1901         bool closefufh = false;
 1902         pid_t pid = curthread->td_proc->p_pid;
 1903 
 1904         if (ap->a_eofflag)
 1905                 *ap->a_eofflag = 0;
 1906         if (fuse_isdeadfs(vp)) {
 1907                 return ENXIO;
 1908         }
 1909         if (                            /* XXXIP ((uio_iovcnt(uio) > 1)) || */
 1910             (uio_resid(uio) < sizeof(struct dirent))) {
 1911                 return EINVAL;
 1912         }
 1913 
 1914         tresid = uio->uio_resid;
 1915         err = fuse_filehandle_get_dir(vp, &fufh, cred, pid);
 1916         if (err == EBADF && mp->mnt_flag & MNT_EXPORTED) {
 1917                 KASSERT(fuse_get_mpdata(mp)->dataflags
 1918                                 & FSESS_NO_OPENDIR_SUPPORT,
 1919                         ("FUSE file systems that don't set "
 1920                          "FUSE_NO_OPENDIR_SUPPORT should not be exported"));
 1921                 /* 
 1922                  * nfsd will do VOP_READDIR without first doing VOP_OPEN.  We
 1923                  * must implicitly open the directory here.
 1924                  */
 1925                 err = fuse_filehandle_open(vp, FREAD, &fufh, curthread, cred);
 1926                 closefufh = true;
 1927         }
 1928         if (err)
 1929                 return (err);
 1930         if (ap->a_ncookies != NULL) {
 1931                 ncookies = uio->uio_resid /
 1932                         (offsetof(struct dirent, d_name) + 4) + 1;
 1933                 cookies = malloc(ncookies * sizeof(*cookies), M_TEMP, M_WAITOK);
 1934                 *ap->a_ncookies = ncookies;
 1935                 *ap->a_cookies = cookies;
 1936         } else {
 1937                 ncookies = 0;
 1938                 cookies = NULL;
 1939         }
 1940 #define DIRCOOKEDSIZE FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + MAXNAMLEN + 1)
 1941         fiov_init(&cookediov, DIRCOOKEDSIZE);
 1942 
 1943         err = fuse_internal_readdir(vp, uio, fufh, &cookediov,
 1944                 &ncookies, cookies);
 1945 
 1946         fiov_teardown(&cookediov);
 1947         if (closefufh)
 1948                 fuse_filehandle_close(vp, fufh, curthread, cred);
 1949 
 1950         if (ap->a_ncookies != NULL) {
 1951                 if (err == 0) {
 1952                         *ap->a_ncookies -= ncookies;
 1953                 } else {
 1954                         free(*ap->a_cookies, M_TEMP);
 1955                         *ap->a_ncookies = 0;
 1956                         *ap->a_cookies = NULL;
 1957                 }
 1958         }
 1959         if (err == 0 && tresid == uio->uio_resid)
 1960                 *ap->a_eofflag = 1;
 1961 
 1962         return err;
 1963 }
 1964 
 1965 /*
 1966     struct vnop_readlink_args {
 1967         struct vnode *a_vp;
 1968         struct uio *a_uio;
 1969         struct ucred *a_cred;
 1970     };
 1971 */
 1972 static int
 1973 fuse_vnop_readlink(struct vop_readlink_args *ap)
 1974 {
 1975         struct vnode *vp = ap->a_vp;
 1976         struct uio *uio = ap->a_uio;
 1977         struct ucred *cred = ap->a_cred;
 1978 
 1979         struct fuse_dispatcher fdi;
 1980         int err;
 1981 
 1982         if (fuse_isdeadfs(vp)) {
 1983                 return ENXIO;
 1984         }
 1985         if (!vnode_islnk(vp)) {
 1986                 return EINVAL;
 1987         }
 1988         fdisp_init(&fdi, 0);
 1989         err = fdisp_simple_putget_vp(&fdi, FUSE_READLINK, vp, curthread, cred);
 1990         if (err) {
 1991                 goto out;
 1992         }
 1993         if (((char *)fdi.answ)[0] == '/' &&
 1994             fuse_get_mpdata(vnode_mount(vp))->dataflags & FSESS_PUSH_SYMLINKS_IN) {
 1995                 char *mpth = vnode_mount(vp)->mnt_stat.f_mntonname;
 1996 
 1997                 err = uiomove(mpth, strlen(mpth), uio);
 1998         }
 1999         if (!err) {
 2000                 err = uiomove(fdi.answ, fdi.iosize, uio);
 2001         }
 2002 out:
 2003         fdisp_destroy(&fdi);
 2004         return err;
 2005 }
 2006 
 2007 /*
 2008     struct vnop_reclaim_args {
 2009         struct vnode *a_vp;
 2010     };
 2011 */
 2012 static int
 2013 fuse_vnop_reclaim(struct vop_reclaim_args *ap)
 2014 {
 2015         struct vnode *vp = ap->a_vp;
 2016         struct thread *td = curthread;
 2017         struct fuse_vnode_data *fvdat = VTOFUD(vp);
 2018         struct fuse_filehandle *fufh, *fufh_tmp;
 2019 
 2020         if (!fvdat) {
 2021                 panic("FUSE: no vnode data during recycling");
 2022         }
 2023         LIST_FOREACH_SAFE(fufh, &fvdat->handles, next, fufh_tmp) {
 2024                 printf("FUSE: vnode being reclaimed with open fufh "
 2025                         "(type=%#x)", fufh->fufh_type);
 2026                 fuse_filehandle_close(vp, fufh, td, NULL);
 2027         }
 2028 
 2029         if (VTOI(vp) == 1) {
 2030                 /*
 2031                  * Don't send FUSE_FORGET for the root inode, because
 2032                  * we never send FUSE_LOOKUP for it (see
 2033                  * fuse_vfsop_root) and we don't want the server to see
 2034                  * mismatched lookup counts.
 2035                  */
 2036                 struct fuse_data *data;
 2037                 struct vnode *vroot;
 2038 
 2039                 data = fuse_get_mpdata(vnode_mount(vp));
 2040                 FUSE_LOCK();
 2041                 vroot = data->vroot;
 2042                 data->vroot = NULL;
 2043                 FUSE_UNLOCK();
 2044                 if (vroot)
 2045                         vrele(vroot);
 2046         } else if (!fuse_isdeadfs(vp) && fvdat->nlookup > 0) {
 2047                 fuse_internal_forget_send(vnode_mount(vp), td, NULL, VTOI(vp),
 2048                     fvdat->nlookup);
 2049         }
 2050         cache_purge(vp);
 2051         vfs_hash_remove(vp);
 2052         fuse_vnode_destroy(vp);
 2053 
 2054         return 0;
 2055 }
 2056 
 2057 /*
 2058     struct vnop_remove_args {
 2059         struct vnode *a_dvp;
 2060         struct vnode *a_vp;
 2061         struct componentname *a_cnp;
 2062     };
 2063 */
 2064 static int
 2065 fuse_vnop_remove(struct vop_remove_args *ap)
 2066 {
 2067         struct vnode *dvp = ap->a_dvp;
 2068         struct vnode *vp = ap->a_vp;
 2069         struct componentname *cnp = ap->a_cnp;
 2070 
 2071         int err;
 2072 
 2073         if (fuse_isdeadfs(vp)) {
 2074                 return ENXIO;
 2075         }
 2076         if (vnode_isdir(vp)) {
 2077                 return EPERM;
 2078         }
 2079 
 2080         err = fuse_internal_remove(dvp, vp, cnp, FUSE_UNLINK);
 2081 
 2082         return err;
 2083 }
 2084 
 2085 /*
 2086     struct vnop_rename_args {
 2087         struct vnode *a_fdvp;
 2088         struct vnode *a_fvp;
 2089         struct componentname *a_fcnp;
 2090         struct vnode *a_tdvp;
 2091         struct vnode *a_tvp;
 2092         struct componentname *a_tcnp;
 2093     };
 2094 */
 2095 static int
 2096 fuse_vnop_rename(struct vop_rename_args *ap)
 2097 {
 2098         struct vnode *fdvp = ap->a_fdvp;
 2099         struct vnode *fvp = ap->a_fvp;
 2100         struct componentname *fcnp = ap->a_fcnp;
 2101         struct vnode *tdvp = ap->a_tdvp;
 2102         struct vnode *tvp = ap->a_tvp;
 2103         struct componentname *tcnp = ap->a_tcnp;
 2104         struct fuse_data *data;
 2105         bool newparent = fdvp != tdvp;
 2106         bool isdir = fvp->v_type == VDIR;
 2107         int err = 0;
 2108 
 2109         if (fuse_isdeadfs(fdvp)) {
 2110                 return ENXIO;
 2111         }
 2112         if (fvp->v_mount != tdvp->v_mount ||
 2113             (tvp && fvp->v_mount != tvp->v_mount)) {
 2114                 SDT_PROBE2(fusefs, , vnops, trace, 1, "cross-device rename");
 2115                 err = EXDEV;
 2116                 goto out;
 2117         }
 2118         cache_purge(fvp);
 2119 
 2120         /*
 2121          * FUSE library is expected to check if target directory is not
 2122          * under the source directory in the file system tree.
 2123          * Linux performs this check at VFS level.
 2124          */
 2125         /* 
 2126          * If source is a directory, and it will get a new parent, user must
 2127          * have write permission to it, so ".." can be modified.
 2128          */
 2129         data = fuse_get_mpdata(vnode_mount(tdvp));
 2130         if (data->dataflags & FSESS_DEFAULT_PERMISSIONS && isdir && newparent) {
 2131                 err = fuse_internal_access(fvp, VWRITE,
 2132                         curthread, tcnp->cn_cred);
 2133                 if (err)
 2134                         goto out;
 2135         }
 2136         sx_xlock(&data->rename_lock);
 2137         err = fuse_internal_rename(fdvp, fcnp, tdvp, tcnp);
 2138         if (err == 0) {
 2139                 if (tdvp != fdvp)
 2140                         fuse_vnode_setparent(fvp, tdvp);
 2141                 if (tvp != NULL)
 2142                         fuse_vnode_setparent(tvp, NULL);
 2143         }
 2144         sx_unlock(&data->rename_lock);
 2145 
 2146         if (tvp != NULL && tvp != fvp) {
 2147                 cache_purge(tvp);
 2148         }
 2149         if (vnode_isdir(fvp)) {
 2150                 if (((tvp != NULL) && vnode_isdir(tvp)) || vnode_isdir(fvp)) {
 2151                         cache_purge(tdvp);
 2152                 }
 2153                 cache_purge(fdvp);
 2154         }
 2155 out:
 2156         if (tdvp == tvp) {
 2157                 vrele(tdvp);
 2158         } else {
 2159                 vput(tdvp);
 2160         }
 2161         if (tvp != NULL) {
 2162                 vput(tvp);
 2163         }
 2164         vrele(fdvp);
 2165         vrele(fvp);
 2166 
 2167         return err;
 2168 }
 2169 
 2170 /*
 2171     struct vnop_rmdir_args {
 2172             struct vnode *a_dvp;
 2173             struct vnode *a_vp;
 2174             struct componentname *a_cnp;
 2175     } *ap;
 2176 */
 2177 static int
 2178 fuse_vnop_rmdir(struct vop_rmdir_args *ap)
 2179 {
 2180         struct vnode *dvp = ap->a_dvp;
 2181         struct vnode *vp = ap->a_vp;
 2182 
 2183         int err;
 2184 
 2185         if (fuse_isdeadfs(vp)) {
 2186                 return ENXIO;
 2187         }
 2188         if (VTOFUD(vp) == VTOFUD(dvp)) {
 2189                 return EINVAL;
 2190         }
 2191         err = fuse_internal_remove(dvp, vp, ap->a_cnp, FUSE_RMDIR);
 2192 
 2193         return err;
 2194 }
 2195 
 2196 /*
 2197     struct vnop_setattr_args {
 2198         struct vnode *a_vp;
 2199         struct vattr *a_vap;
 2200         struct ucred *a_cred;
 2201         struct thread *a_td;
 2202     };
 2203 */
 2204 static int
 2205 fuse_vnop_setattr(struct vop_setattr_args *ap)
 2206 {
 2207         struct vnode *vp = ap->a_vp;
 2208         struct vattr *vap = ap->a_vap;
 2209         struct ucred *cred = ap->a_cred;
 2210         struct thread *td = curthread;
 2211         struct mount *mp;
 2212         struct fuse_data *data;
 2213         struct vattr old_va;
 2214         int dataflags;
 2215         int err = 0, err2;
 2216         accmode_t accmode = 0;
 2217         bool checkperm;
 2218         bool drop_suid = false;
 2219         gid_t cr_gid;
 2220 
 2221         mp = vnode_mount(vp);
 2222         data = fuse_get_mpdata(mp);
 2223         dataflags = data->dataflags;
 2224         checkperm = dataflags & FSESS_DEFAULT_PERMISSIONS;
 2225         if (cred->cr_ngroups > 0)
 2226                 cr_gid = cred->cr_groups[0];
 2227         else
 2228                 cr_gid = 0;
 2229 
 2230         if (fuse_isdeadfs(vp)) {
 2231                 return ENXIO;
 2232         }
 2233 
 2234         if (vap->va_uid != (uid_t)VNOVAL) {
 2235                 if (checkperm) {
 2236                         /* Only root may change a file's owner */
 2237                         err = priv_check_cred(cred, PRIV_VFS_CHOWN);
 2238                         if (err) {
 2239                                 /* As a special case, allow the null chown */
 2240                                 err2 = fuse_internal_getattr(vp, &old_va, cred,
 2241                                         td);
 2242                                 if (err2)
 2243                                         return (err2);
 2244                                 if (vap->va_uid != old_va.va_uid)
 2245                                         return err;
 2246                                 else
 2247                                         accmode |= VADMIN;
 2248                                 drop_suid = true;
 2249                         } else
 2250                                 accmode |= VADMIN;
 2251                 } else
 2252                         accmode |= VADMIN;
 2253         }
 2254         if (vap->va_gid != (gid_t)VNOVAL) {
 2255                 if (checkperm && priv_check_cred(cred, PRIV_VFS_CHOWN))
 2256                         drop_suid = true;
 2257                 if (checkperm && !groupmember(vap->va_gid, cred))
 2258                 {
 2259                         /*
 2260                          * Non-root users may only chgrp to one of their own
 2261                          * groups 
 2262                          */
 2263                         err = priv_check_cred(cred, PRIV_VFS_CHOWN);
 2264                         if (err) {
 2265                                 /* As a special case, allow the null chgrp */
 2266                                 err2 = fuse_internal_getattr(vp, &old_va, cred,
 2267                                         td);
 2268                                 if (err2)
 2269                                         return (err2);
 2270                                 if (vap->va_gid != old_va.va_gid)
 2271                                         return err;
 2272                                 accmode |= VADMIN;
 2273                         } else
 2274                                 accmode |= VADMIN;
 2275                 } else
 2276                         accmode |= VADMIN;
 2277         }
 2278         if (vap->va_size != VNOVAL) {
 2279                 switch (vp->v_type) {
 2280                 case VDIR:
 2281                         return (EISDIR);
 2282                 case VLNK:
 2283                 case VREG:
 2284                         if (vfs_isrdonly(mp))
 2285                                 return (EROFS);
 2286                         err = vn_rlimit_trunc(vap->va_size, td);
 2287                         if (err)
 2288                                 return (err);
 2289                         break;
 2290                 default:
 2291                         /*
 2292                          * According to POSIX, the result is unspecified
 2293                          * for file types other than regular files,
 2294                          * directories and shared memory objects.  We
 2295                          * don't support shared memory objects in the file
 2296                          * system, and have dubious support for truncating
 2297                          * symlinks.  Just ignore the request in other cases.
 2298                          */
 2299                         return (0);
 2300                 }
 2301                 /* Don't set accmode.  Permission to trunc is checked upstack */
 2302         }
 2303         if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
 2304                 if (vap->va_vaflags & VA_UTIMES_NULL)
 2305                         accmode |= VWRITE;
 2306                 else
 2307                         accmode |= VADMIN;
 2308         }
 2309         if (drop_suid) {
 2310                 if (vap->va_mode != (mode_t)VNOVAL)
 2311                         vap->va_mode &= ~(S_ISUID | S_ISGID);
 2312                 else {
 2313                         err = fuse_internal_getattr(vp, &old_va, cred, td);
 2314                         if (err)
 2315                                 return (err);
 2316                         vap->va_mode = old_va.va_mode & ~(S_ISUID | S_ISGID);
 2317                 }
 2318         }
 2319         if (vap->va_mode != (mode_t)VNOVAL) {
 2320                 /* Only root may set the sticky bit on non-directories */
 2321                 if (checkperm && vp->v_type != VDIR && (vap->va_mode & S_ISTXT)
 2322                     && priv_check_cred(cred, PRIV_VFS_STICKYFILE))
 2323                         return EFTYPE;
 2324                 if (checkperm && (vap->va_mode & S_ISGID)) {
 2325                         err = fuse_internal_getattr(vp, &old_va, cred, td);
 2326                         if (err)
 2327                                 return (err);
 2328                         if (!groupmember(old_va.va_gid, cred)) {
 2329                                 err = priv_check_cred(cred, PRIV_VFS_SETGID);
 2330                                 if (err)
 2331                                         return (err);
 2332                         }
 2333                 }
 2334                 accmode |= VADMIN;
 2335         }
 2336 
 2337         if (vfs_isrdonly(mp))
 2338                 return EROFS;
 2339 
 2340         if (checkperm) {
 2341                 err = fuse_internal_access(vp, accmode, td, cred);
 2342         } else {
 2343                 err = 0;
 2344         }
 2345         if (err)
 2346                 return err;
 2347         else
 2348                 return fuse_internal_setattr(vp, vap, td, cred);
 2349 }
 2350 
 2351 /*
 2352     struct vnop_strategy_args {
 2353         struct vnode *a_vp;
 2354         struct buf *a_bp;
 2355     };
 2356 */
 2357 static int
 2358 fuse_vnop_strategy(struct vop_strategy_args *ap)
 2359 {
 2360         struct vnode *vp = ap->a_vp;
 2361         struct buf *bp = ap->a_bp;
 2362 
 2363         if (!vp || fuse_isdeadfs(vp)) {
 2364                 bp->b_ioflags |= BIO_ERROR;
 2365                 bp->b_error = ENXIO;
 2366                 bufdone(bp);
 2367                 return 0;
 2368         }
 2369 
 2370         /*
 2371          * VOP_STRATEGY always returns zero and signals error via bp->b_ioflags.
 2372          * fuse_io_strategy sets bp's error fields
 2373          */
 2374         (void)fuse_io_strategy(vp, bp);
 2375 
 2376         return 0;
 2377 }
 2378 
 2379 /*
 2380     struct vnop_symlink_args {
 2381         struct vnode *a_dvp;
 2382         struct vnode **a_vpp;
 2383         struct componentname *a_cnp;
 2384         struct vattr *a_vap;
 2385         char *a_target;
 2386     };
 2387 */
 2388 static int
 2389 fuse_vnop_symlink(struct vop_symlink_args *ap)
 2390 {
 2391         struct vnode *dvp = ap->a_dvp;
 2392         struct vnode **vpp = ap->a_vpp;
 2393         struct componentname *cnp = ap->a_cnp;
 2394         const char *target = ap->a_target;
 2395 
 2396         struct fuse_dispatcher fdi;
 2397 
 2398         int err;
 2399         size_t len;
 2400 
 2401         if (fuse_isdeadfs(dvp)) {
 2402                 return ENXIO;
 2403         }
 2404         /*
 2405          * Unlike the other creator type calls, here we have to create a message
 2406          * where the name of the new entry comes first, and the data describing
 2407          * the entry comes second.
 2408          * Hence we can't rely on our handy fuse_internal_newentry() routine,
 2409          * but put together the message manually and just call the core part.
 2410          */
 2411 
 2412         len = strlen(target) + 1;
 2413         fdisp_init(&fdi, len + cnp->cn_namelen + 1);
 2414         fdisp_make_vp(&fdi, FUSE_SYMLINK, dvp, curthread, NULL);
 2415 
 2416         memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
 2417         ((char *)fdi.indata)[cnp->cn_namelen] = '\0';
 2418         memcpy((char *)fdi.indata + cnp->cn_namelen + 1, target, len);
 2419 
 2420         err = fuse_internal_newentry_core(dvp, vpp, cnp, VLNK, &fdi);
 2421         fdisp_destroy(&fdi);
 2422         return err;
 2423 }
 2424 
 2425 /*
 2426     struct vnop_write_args {
 2427         struct vnode *a_vp;
 2428         struct uio *a_uio;
 2429         int  a_ioflag;
 2430         struct ucred *a_cred;
 2431     };
 2432 */
 2433 static int
 2434 fuse_vnop_write(struct vop_write_args *ap)
 2435 {
 2436         struct vnode *vp = ap->a_vp;
 2437         struct uio *uio = ap->a_uio;
 2438         int ioflag = ap->a_ioflag;
 2439         struct ucred *cred = ap->a_cred;
 2440         pid_t pid = curthread->td_proc->p_pid;
 2441         struct fuse_filehandle *fufh;
 2442         int err;
 2443         bool closefufh = false, directio;
 2444 
 2445         MPASS(vp->v_type == VREG || vp->v_type == VDIR);
 2446 
 2447         if (fuse_isdeadfs(vp)) {
 2448                 return ENXIO;
 2449         }
 2450 
 2451         if (VTOFUD(vp)->flag & FN_DIRECTIO) {
 2452                 ioflag |= IO_DIRECT;
 2453         }
 2454 
 2455         err = fuse_filehandle_getrw(vp, FWRITE, &fufh, cred, pid);
 2456         if (err == EBADF && vnode_mount(vp)->mnt_flag & MNT_EXPORTED) {
 2457                 /*
 2458                  * nfsd will do I/O without first doing VOP_OPEN.  We
 2459                  * must implicitly open the file here
 2460                  */
 2461                 err = fuse_filehandle_open(vp, FWRITE, &fufh, curthread, cred);
 2462                 closefufh = true;
 2463         }
 2464         if (err) {
 2465                 SDT_PROBE3(fusefs, , vnops, filehandles_closed, vp, uio, cred);
 2466                 return err;
 2467         }
 2468 
 2469         /*
 2470          * Ideally, when the daemon asks for direct io at open time, the
 2471          * standard file flag should be set according to this, so that would
 2472          * just change the default mode, which later on could be changed via
 2473          * fcntl(2).
 2474          * But this doesn't work, the O_DIRECT flag gets cleared at some point
 2475          * (don't know where). So to make any use of the Fuse direct_io option,
 2476          * we hardwire it into the file's private data (similarly to Linux,
 2477          * btw.).
 2478          */
 2479         directio = (ioflag & IO_DIRECT) || !fsess_opt_datacache(vnode_mount(vp));
 2480 
 2481         fuse_vnode_update(vp, FN_MTIMECHANGE | FN_CTIMECHANGE);
 2482         if (directio) {
 2483                 off_t start, end, filesize;
 2484                 bool pages = (ioflag & IO_VMIO) != 0;
 2485 
 2486                 SDT_PROBE2(fusefs, , vnops, trace, 1, "direct write of vnode");
 2487 
 2488                 err = fuse_vnode_size(vp, &filesize, cred, curthread);
 2489                 if (err)
 2490                         goto out;
 2491 
 2492                 start = uio->uio_offset;
 2493                 end = start + uio->uio_resid;
 2494                 if (!pages) {
 2495                         err = fuse_inval_buf_range(vp, filesize, start,
 2496                             end);
 2497                         if (err)
 2498                                 goto out;
 2499                 }
 2500                 err = fuse_write_directbackend(vp, uio, cred, fufh,
 2501                         filesize, ioflag, pages);
 2502         } else {
 2503                 SDT_PROBE2(fusefs, , vnops, trace, 1,
 2504                         "buffered write of vnode");
 2505                 if (!fsess_opt_writeback(vnode_mount(vp)))
 2506                         ioflag |= IO_SYNC;
 2507                 err = fuse_write_biobackend(vp, uio, cred, fufh, ioflag, pid);
 2508         }
 2509         fuse_internal_clear_suid_on_write(vp, cred, uio->uio_td);
 2510 
 2511 out:
 2512         if (closefufh)
 2513                 fuse_filehandle_close(vp, fufh, curthread, cred);
 2514 
 2515         return (err);
 2516 }
 2517 
 2518 static daddr_t
 2519 fuse_gbp_getblkno(struct vnode *vp, vm_ooffset_t off)
 2520 {
 2521         const int biosize = fuse_iosize(vp);
 2522 
 2523         return (off / biosize);
 2524 }
 2525 
 2526 static int
 2527 fuse_gbp_getblksz(struct vnode *vp, daddr_t lbn, long *blksz)
 2528 {
 2529         off_t filesize;
 2530         int err;
 2531         const int biosize = fuse_iosize(vp);
 2532 
 2533         err = fuse_vnode_size(vp, &filesize, NULL, NULL);
 2534         if (err) {
 2535                 /* This will turn into a SIGBUS */
 2536                 return (EIO);
 2537         } else if ((off_t)lbn * biosize >= filesize) {
 2538                 *blksz = 0;
 2539         } else if ((off_t)(lbn + 1) * biosize > filesize) {
 2540                 *blksz = filesize - (off_t)lbn *biosize;
 2541         } else {
 2542                 *blksz = biosize;
 2543         }
 2544         return (0);
 2545 }
 2546 
 2547 /*
 2548     struct vnop_getpages_args {
 2549         struct vnode *a_vp;
 2550         vm_page_t *a_m;
 2551         int a_count;
 2552         int a_reqpage;
 2553     };
 2554 */
 2555 static int
 2556 fuse_vnop_getpages(struct vop_getpages_args *ap)
 2557 {
 2558         struct vnode *vp = ap->a_vp;
 2559 
 2560         if (!fsess_opt_mmap(vnode_mount(vp))) {
 2561                 SDT_PROBE2(fusefs, , vnops, trace, 1,
 2562                         "called on non-cacheable vnode??\n");
 2563                 return (VM_PAGER_ERROR);
 2564         }
 2565 
 2566         return (vfs_bio_getpages(vp, ap->a_m, ap->a_count, ap->a_rbehind,
 2567             ap->a_rahead, fuse_gbp_getblkno, fuse_gbp_getblksz));
 2568 }
 2569 
 2570 static const char extattr_namespace_separator = '.';
 2571 
 2572 /*
 2573     struct vop_getextattr_args {
 2574         struct vop_generic_args a_gen;
 2575         struct vnode *a_vp;
 2576         int a_attrnamespace;
 2577         const char *a_name;
 2578         struct uio *a_uio;
 2579         size_t *a_size;
 2580         struct ucred *a_cred;
 2581         struct thread *a_td;
 2582     };
 2583 */
 2584 static int
 2585 fuse_vnop_getextattr(struct vop_getextattr_args *ap)
 2586 {
 2587         struct vnode *vp = ap->a_vp;
 2588         struct uio *uio = ap->a_uio;
 2589         struct fuse_dispatcher fdi;
 2590         struct fuse_getxattr_in *get_xattr_in;
 2591         struct fuse_getxattr_out *get_xattr_out;
 2592         struct mount *mp = vnode_mount(vp);
 2593         struct thread *td = ap->a_td;
 2594         struct ucred *cred = ap->a_cred;
 2595         char *prefix;
 2596         char *attr_str;
 2597         size_t len;
 2598         int err;
 2599 
 2600         if (fuse_isdeadfs(vp))
 2601                 return (ENXIO);
 2602 
 2603         if (fsess_not_impl(mp, FUSE_GETXATTR))
 2604                 return EOPNOTSUPP;
 2605 
 2606         err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td, VREAD);
 2607         if (err)
 2608                 return err;
 2609 
 2610         /* Default to looking for user attributes. */
 2611         if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
 2612                 prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
 2613         else
 2614                 prefix = EXTATTR_NAMESPACE_USER_STRING;
 2615 
 2616         len = strlen(prefix) + sizeof(extattr_namespace_separator) +
 2617             strlen(ap->a_name) + 1;
 2618 
 2619         fdisp_init(&fdi, len + sizeof(*get_xattr_in));
 2620         fdisp_make_vp(&fdi, FUSE_GETXATTR, vp, td, cred);
 2621 
 2622         get_xattr_in = fdi.indata;
 2623         /*
 2624          * Check to see whether we're querying the available size or
 2625          * issuing the actual request.  If we pass in 0, we get back struct
 2626          * fuse_getxattr_out.  If we pass in a non-zero size, we get back
 2627          * that much data, without the struct fuse_getxattr_out header.
 2628          */
 2629         if (uio == NULL)
 2630                 get_xattr_in->size = 0;
 2631         else
 2632                 get_xattr_in->size = uio->uio_resid;
 2633 
 2634         attr_str = (char *)fdi.indata + sizeof(*get_xattr_in);
 2635         snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator,
 2636             ap->a_name);
 2637 
 2638         err = fdisp_wait_answ(&fdi);
 2639         if (err != 0) {
 2640                 if (err == ENOSYS) {
 2641                         fsess_set_notimpl(mp, FUSE_GETXATTR);
 2642                         err = EOPNOTSUPP;
 2643                 }
 2644                 goto out;
 2645         }
 2646 
 2647         get_xattr_out = fdi.answ;
 2648 
 2649         if (ap->a_size != NULL)
 2650                 *ap->a_size = get_xattr_out->size;
 2651 
 2652         if (uio != NULL)
 2653                 err = uiomove(fdi.answ, fdi.iosize, uio);
 2654 
 2655 out:
 2656         fdisp_destroy(&fdi);
 2657         return (err);
 2658 }
 2659 
 2660 /*
 2661     struct vop_setextattr_args {
 2662         struct vop_generic_args a_gen;
 2663         struct vnode *a_vp;
 2664         int a_attrnamespace;
 2665         const char *a_name;
 2666         struct uio *a_uio;
 2667         struct ucred *a_cred;
 2668         struct thread *a_td;
 2669     };
 2670 */
 2671 static int
 2672 fuse_vnop_setextattr(struct vop_setextattr_args *ap)
 2673 {
 2674         struct vnode *vp = ap->a_vp;
 2675         struct uio *uio = ap->a_uio;
 2676         struct fuse_dispatcher fdi;
 2677         struct fuse_setxattr_in *set_xattr_in;
 2678         struct mount *mp = vnode_mount(vp);
 2679         struct thread *td = ap->a_td;
 2680         struct ucred *cred = ap->a_cred;
 2681         char *prefix;
 2682         size_t len;
 2683         char *attr_str;
 2684         int err;
 2685 
 2686         if (fuse_isdeadfs(vp))
 2687                 return (ENXIO);
 2688 
 2689         if (fsess_not_impl(mp, FUSE_SETXATTR))
 2690                 return EOPNOTSUPP;
 2691 
 2692         if (vfs_isrdonly(mp))
 2693                 return EROFS;
 2694 
 2695         /* Deleting xattrs must use VOP_DELETEEXTATTR instead */
 2696         if (ap->a_uio == NULL) {
 2697                 /*
 2698                  * If we got here as fallback from VOP_DELETEEXTATTR, then
 2699                  * return EOPNOTSUPP.
 2700                  */
 2701                 if (fsess_not_impl(mp, FUSE_REMOVEXATTR))
 2702                         return (EOPNOTSUPP);
 2703                 else
 2704                         return (EINVAL);
 2705         }
 2706 
 2707         err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td,
 2708                 VWRITE);
 2709         if (err)
 2710                 return err;
 2711 
 2712         /* Default to looking for user attributes. */
 2713         if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
 2714                 prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
 2715         else
 2716                 prefix = EXTATTR_NAMESPACE_USER_STRING;
 2717 
 2718         len = strlen(prefix) + sizeof(extattr_namespace_separator) +
 2719             strlen(ap->a_name) + 1;
 2720 
 2721         fdisp_init(&fdi, len + sizeof(*set_xattr_in) + uio->uio_resid);
 2722         fdisp_make_vp(&fdi, FUSE_SETXATTR, vp, td, cred);
 2723 
 2724         set_xattr_in = fdi.indata;
 2725         set_xattr_in->size = uio->uio_resid;
 2726 
 2727         attr_str = (char *)fdi.indata + sizeof(*set_xattr_in);
 2728         snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator,
 2729             ap->a_name);
 2730 
 2731         err = uiomove((char *)fdi.indata + sizeof(*set_xattr_in) + len,
 2732             uio->uio_resid, uio);
 2733         if (err != 0) {
 2734                 goto out;
 2735         }
 2736 
 2737         err = fdisp_wait_answ(&fdi);
 2738 
 2739         if (err == ENOSYS) {
 2740                 fsess_set_notimpl(mp, FUSE_SETXATTR);
 2741                 err = EOPNOTSUPP;
 2742         }
 2743         if (err == ERESTART) {
 2744                 /* Can't restart after calling uiomove */
 2745                 err = EINTR;
 2746         }
 2747 
 2748 out:
 2749         fdisp_destroy(&fdi);
 2750         return (err);
 2751 }
 2752 
 2753 /*
 2754  * The Linux / FUSE extended attribute list is simply a collection of
 2755  * NUL-terminated strings.  The FreeBSD extended attribute list is a single
 2756  * byte length followed by a non-NUL terminated string.  So, this allows
 2757  * conversion of the Linux / FUSE format to the FreeBSD format in place.
 2758  * Linux attribute names are reported with the namespace as a prefix (e.g.
 2759  * "user.attribute_name"), but in FreeBSD they are reported without the
 2760  * namespace prefix (e.g. "attribute_name").  So, we're going from:
 2761  *
 2762  * user.attr_name1\0user.attr_name2\0
 2763  *
 2764  * to:
 2765  *
 2766  * <num>attr_name1<num>attr_name2
 2767  *
 2768  * Where "<num>" is a single byte number of characters in the attribute name.
 2769  * 
 2770  * Args:
 2771  * prefix - exattr namespace prefix string
 2772  * list, list_len - input list with namespace prefixes
 2773  * bsd_list, bsd_list_len - output list compatible with bsd vfs
 2774  */
 2775 static int
 2776 fuse_xattrlist_convert(char *prefix, const char *list, int list_len,
 2777     char *bsd_list, int *bsd_list_len)
 2778 {
 2779         int len, pos, dist_to_next, prefix_len;
 2780 
 2781         pos = 0;
 2782         *bsd_list_len = 0;
 2783         prefix_len = strlen(prefix);
 2784 
 2785         while (pos < list_len && list[pos] != '\0') {
 2786                 dist_to_next = strlen(&list[pos]) + 1;
 2787                 if (bcmp(&list[pos], prefix, prefix_len) == 0 &&
 2788                     list[pos + prefix_len] == extattr_namespace_separator) {
 2789                         len = dist_to_next -
 2790                             (prefix_len + sizeof(extattr_namespace_separator)) - 1;
 2791                         if (len >= EXTATTR_MAXNAMELEN)
 2792                                 return (ENAMETOOLONG);
 2793 
 2794                         bsd_list[*bsd_list_len] = len;
 2795                         memcpy(&bsd_list[*bsd_list_len + 1],
 2796                             &list[pos + prefix_len +
 2797                             sizeof(extattr_namespace_separator)], len);
 2798 
 2799                         *bsd_list_len += len + 1;
 2800                 }
 2801 
 2802                 pos += dist_to_next;
 2803         }
 2804 
 2805         return (0);
 2806 }
 2807 
 2808 /*
 2809  * List extended attributes
 2810  *
 2811  * The FUSE_LISTXATTR operation is based on Linux's listxattr(2) syscall, which
 2812  * has a number of differences compared to its FreeBSD equivalent,
 2813  * extattr_list_file:
 2814  *
 2815  * - FUSE_LISTXATTR returns all extended attributes across all namespaces,
 2816  *   whereas listxattr(2) only returns attributes for a single namespace
 2817  * - FUSE_LISTXATTR prepends each attribute name with "namespace."
 2818  * - If the provided buffer is not large enough to hold the result,
 2819  *   FUSE_LISTXATTR should return ERANGE, whereas listxattr is expected to
 2820  *   return as many results as will fit.
 2821  */
 2822 /*
 2823     struct vop_listextattr_args {
 2824         struct vop_generic_args a_gen;
 2825         struct vnode *a_vp;
 2826         int a_attrnamespace;
 2827         struct uio *a_uio;
 2828         size_t *a_size;
 2829         struct ucred *a_cred;
 2830         struct thread *a_td;
 2831     };
 2832 */
 2833 static int
 2834 fuse_vnop_listextattr(struct vop_listextattr_args *ap)
 2835 {
 2836         struct vnode *vp = ap->a_vp;
 2837         struct uio *uio = ap->a_uio;
 2838         struct fuse_dispatcher fdi;
 2839         struct fuse_listxattr_in *list_xattr_in;
 2840         struct fuse_listxattr_out *list_xattr_out;
 2841         struct mount *mp = vnode_mount(vp);
 2842         struct thread *td = ap->a_td;
 2843         struct ucred *cred = ap->a_cred;
 2844         char *prefix;
 2845         char *bsd_list = NULL;
 2846         char *linux_list;
 2847         int bsd_list_len;
 2848         int linux_list_len;
 2849         int err;
 2850 
 2851         if (fuse_isdeadfs(vp))
 2852                 return (ENXIO);
 2853 
 2854         if (fsess_not_impl(mp, FUSE_LISTXATTR))
 2855                 return EOPNOTSUPP;
 2856 
 2857         err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td, VREAD);
 2858         if (err)
 2859                 return err;
 2860 
 2861         /*
 2862          * Add space for a NUL and the period separator if enabled.
 2863          * Default to looking for user attributes.
 2864          */
 2865         if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
 2866                 prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
 2867         else
 2868                 prefix = EXTATTR_NAMESPACE_USER_STRING;
 2869 
 2870         fdisp_init(&fdi, sizeof(*list_xattr_in));
 2871         fdisp_make_vp(&fdi, FUSE_LISTXATTR, vp, td, cred);
 2872 
 2873         /*
 2874          * Retrieve Linux / FUSE compatible list size.
 2875          */
 2876         list_xattr_in = fdi.indata;
 2877         list_xattr_in->size = 0;
 2878 
 2879         err = fdisp_wait_answ(&fdi);
 2880         if (err != 0) {
 2881                 if (err == ENOSYS) {
 2882                         fsess_set_notimpl(mp, FUSE_LISTXATTR);
 2883                         err = EOPNOTSUPP;
 2884                 }
 2885                 goto out;
 2886         }
 2887 
 2888         list_xattr_out = fdi.answ;
 2889         linux_list_len = list_xattr_out->size;
 2890         if (linux_list_len == 0) {
 2891                 if (ap->a_size != NULL)
 2892                         *ap->a_size = linux_list_len;
 2893                 goto out;
 2894         }
 2895 
 2896         /*
 2897          * Retrieve Linux / FUSE compatible list values.
 2898          */
 2899         fdisp_refresh_vp(&fdi, FUSE_LISTXATTR, vp, td, cred);
 2900         list_xattr_in = fdi.indata;
 2901         list_xattr_in->size = linux_list_len;
 2902 
 2903         err = fdisp_wait_answ(&fdi);
 2904         if (err == ERANGE) {
 2905                 /* 
 2906                  * Race detected.  The attribute list must've grown since the
 2907                  * first FUSE_LISTXATTR call.  Start over.  Go all the way back
 2908                  * to userland so we can process signals, if necessary, before
 2909                  * restarting.
 2910                  */
 2911                 err = ERESTART;
 2912                 goto out;
 2913         } else if (err != 0)
 2914                 goto out;
 2915 
 2916         linux_list = fdi.answ;
 2917         /* FUSE doesn't allow the server to return more data than requested */
 2918         if (fdi.iosize > linux_list_len) {
 2919                 struct fuse_data *data = fuse_get_mpdata(mp);
 2920 
 2921                 fuse_warn(data, FSESS_WARN_LSEXTATTR_LONG,
 2922                         "server returned "
 2923                         "more extended attribute data than requested; "
 2924                         "should've returned ERANGE instead.");
 2925         } else {
 2926                 /* But returning less data is fine */
 2927                 linux_list_len = fdi.iosize;
 2928         }
 2929 
 2930         /*
 2931          * Retrieve the BSD compatible list values.
 2932          * The Linux / FUSE attribute list format isn't the same
 2933          * as FreeBSD's format. So we need to transform it into
 2934          * FreeBSD's format before giving it to the user.
 2935          */
 2936         bsd_list = malloc(linux_list_len, M_TEMP, M_WAITOK);
 2937         err = fuse_xattrlist_convert(prefix, linux_list, linux_list_len,
 2938             bsd_list, &bsd_list_len);
 2939         if (err != 0)
 2940                 goto out;
 2941 
 2942         if (ap->a_size != NULL)
 2943                 *ap->a_size = bsd_list_len;
 2944 
 2945         if (uio != NULL)
 2946                 err = uiomove(bsd_list, bsd_list_len, uio);
 2947 
 2948 out:
 2949         free(bsd_list, M_TEMP);
 2950         fdisp_destroy(&fdi);
 2951         return (err);
 2952 }
 2953 
 2954 /*
 2955     struct vop_deallocate_args {
 2956         struct vop_generic_args a_gen;
 2957         struct vnode *a_vp;
 2958         off_t *a_offset;
 2959         off_t *a_len;
 2960         int a_flags;
 2961         int a_ioflag;
 2962         struct ucred *a_cred;
 2963     };
 2964 */
 2965 static int
 2966 fuse_vnop_deallocate(struct vop_deallocate_args *ap)
 2967 {
 2968         struct vnode *vp = ap->a_vp;
 2969         struct mount *mp = vnode_mount(vp);
 2970         struct fuse_filehandle *fufh;
 2971         struct fuse_dispatcher fdi;
 2972         struct fuse_fallocate_in *ffi;
 2973         struct ucred *cred = ap->a_cred;
 2974         pid_t pid = curthread->td_proc->p_pid;
 2975         off_t *len = ap->a_len;
 2976         off_t *offset = ap->a_offset;
 2977         int ioflag = ap->a_ioflag;
 2978         off_t filesize;
 2979         int err;
 2980         bool closefufh = false;
 2981 
 2982         if (fuse_isdeadfs(vp))
 2983                 return (ENXIO);
 2984 
 2985         if (vfs_isrdonly(mp))
 2986                 return (EROFS);
 2987 
 2988         if (fsess_not_impl(mp, FUSE_FALLOCATE))
 2989                 goto fallback;
 2990 
 2991         err = fuse_filehandle_getrw(vp, FWRITE, &fufh, cred, pid);
 2992         if (err == EBADF && vnode_mount(vp)->mnt_flag & MNT_EXPORTED) {
 2993                 /*
 2994                  * nfsd will do I/O without first doing VOP_OPEN.  We
 2995                  * must implicitly open the file here
 2996                  */
 2997                 err = fuse_filehandle_open(vp, FWRITE, &fufh, curthread, cred);
 2998                 closefufh = true;
 2999         }
 3000         if (err)
 3001                 return (err);
 3002 
 3003         fuse_vnode_update(vp, FN_MTIMECHANGE | FN_CTIMECHANGE);
 3004 
 3005         err = fuse_vnode_size(vp, &filesize, cred, curthread);
 3006         if (err)
 3007                 goto out;
 3008         fuse_inval_buf_range(vp, filesize, *offset, *offset + *len);
 3009 
 3010         fdisp_init(&fdi, sizeof(*ffi));
 3011         fdisp_make_vp(&fdi, FUSE_FALLOCATE, vp, curthread, cred);
 3012         ffi = fdi.indata;
 3013         ffi->fh = fufh->fh_id;
 3014         ffi->offset = *offset;
 3015         ffi->length = *len;
 3016         /*
 3017          * FreeBSD's fspacectl is equivalent to Linux's fallocate with
 3018          * mode == FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE
 3019          */
 3020         ffi->mode = FUSE_FALLOC_FL_PUNCH_HOLE | FUSE_FALLOC_FL_KEEP_SIZE;
 3021         err = fdisp_wait_answ(&fdi);
 3022 
 3023         if (err == ENOSYS) {
 3024                 fsess_set_notimpl(mp, FUSE_FALLOCATE);
 3025                 goto fallback;
 3026         } else if (err == EOPNOTSUPP) {
 3027                 /*
 3028                  * The file system server does not support FUSE_FALLOCATE with
 3029                  * the supplied mode for this particular file.
 3030                  */
 3031                 goto fallback;
 3032         } else if (!err) {
 3033                 /*
 3034                  * Clip the returned offset to EoF.  Do it here rather than
 3035                  * before FUSE_FALLOCATE just in case the kernel's cached file
 3036                  * size is out of date.  Unfortunately, FUSE does not return
 3037                  * any information about filesize from that operation.
 3038                  */
 3039                 *offset = MIN(*offset + *len, filesize);
 3040                 *len = 0;
 3041                 fuse_vnode_undirty_cached_timestamps(vp, false);
 3042                 fuse_internal_clear_suid_on_write(vp, cred, curthread);
 3043 
 3044                 if (ioflag & IO_SYNC)
 3045                         err = fuse_internal_fsync(vp, curthread, MNT_WAIT,
 3046                             false);
 3047         }
 3048 
 3049 out:
 3050         if (closefufh)
 3051                 fuse_filehandle_close(vp, fufh, curthread, cred);
 3052 
 3053         return (err);
 3054 
 3055 fallback:
 3056         if (closefufh)
 3057                 fuse_filehandle_close(vp, fufh, curthread, cred);
 3058 
 3059         return (vop_stddeallocate(ap));
 3060 }
 3061 
 3062 /*
 3063     struct vop_deleteextattr_args {
 3064         struct vop_generic_args a_gen;
 3065         struct vnode *a_vp;
 3066         int a_attrnamespace;
 3067         const char *a_name;
 3068         struct ucred *a_cred;
 3069         struct thread *a_td;
 3070     };
 3071 */
 3072 static int
 3073 fuse_vnop_deleteextattr(struct vop_deleteextattr_args *ap)
 3074 {
 3075         struct vnode *vp = ap->a_vp;
 3076         struct fuse_dispatcher fdi;
 3077         struct mount *mp = vnode_mount(vp);
 3078         struct thread *td = ap->a_td;
 3079         struct ucred *cred = ap->a_cred;
 3080         char *prefix;
 3081         size_t len;
 3082         char *attr_str;
 3083         int err;
 3084 
 3085         if (fuse_isdeadfs(vp))
 3086                 return (ENXIO);
 3087 
 3088         if (fsess_not_impl(mp, FUSE_REMOVEXATTR))
 3089                 return EOPNOTSUPP;
 3090 
 3091         if (vfs_isrdonly(mp))
 3092                 return EROFS;
 3093 
 3094         err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td,
 3095                 VWRITE);
 3096         if (err)
 3097                 return err;
 3098 
 3099         /* Default to looking for user attributes. */
 3100         if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
 3101                 prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
 3102         else
 3103                 prefix = EXTATTR_NAMESPACE_USER_STRING;
 3104 
 3105         len = strlen(prefix) + sizeof(extattr_namespace_separator) +
 3106             strlen(ap->a_name) + 1;
 3107 
 3108         fdisp_init(&fdi, len);
 3109         fdisp_make_vp(&fdi, FUSE_REMOVEXATTR, vp, td, cred);
 3110 
 3111         attr_str = fdi.indata;
 3112         snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator,
 3113             ap->a_name);
 3114 
 3115         err = fdisp_wait_answ(&fdi);
 3116         if (err == ENOSYS) {
 3117                 fsess_set_notimpl(mp, FUSE_REMOVEXATTR);
 3118                 err = EOPNOTSUPP;
 3119         }
 3120 
 3121         fdisp_destroy(&fdi);
 3122         return (err);
 3123 }
 3124 
 3125 /*
 3126     struct vnop_print_args {
 3127         struct vnode *a_vp;
 3128     };
 3129 */
 3130 static int
 3131 fuse_vnop_print(struct vop_print_args *ap)
 3132 {
 3133         struct fuse_vnode_data *fvdat = VTOFUD(ap->a_vp);
 3134 
 3135         printf("nodeid: %ju, parent nodeid: %ju, nlookup: %ju, flag: %#x\n",
 3136             (uintmax_t)VTOILLU(ap->a_vp), (uintmax_t)fvdat->parent_nid,
 3137             (uintmax_t)fvdat->nlookup,
 3138             fvdat->flag);
 3139 
 3140         return 0;
 3141 }
 3142 
 3143 /*
 3144  * Get an NFS filehandle for a FUSE file.
 3145  *
 3146  * This will only work for FUSE file systems that guarantee the uniqueness of
 3147  * nodeid:generation, which most don't.
 3148  */
 3149 /*
 3150 vop_vptofh {
 3151         IN struct vnode *a_vp;
 3152         IN struct fid *a_fhp;
 3153 };
 3154 */
 3155 static int
 3156 fuse_vnop_vptofh(struct vop_vptofh_args *ap)
 3157 {
 3158         struct vnode *vp = ap->a_vp;
 3159         struct fuse_vnode_data *fvdat = VTOFUD(vp);
 3160         struct fuse_fid *fhp = (struct fuse_fid *)(ap->a_fhp);
 3161         _Static_assert(sizeof(struct fuse_fid) <= sizeof(struct fid),
 3162                 "FUSE fid type is too big");
 3163         struct mount *mp = vnode_mount(vp);
 3164         struct fuse_data *data = fuse_get_mpdata(mp);
 3165         struct vattr va;
 3166         int err;
 3167 
 3168         if (!(data->dataflags & FSESS_EXPORT_SUPPORT)) {
 3169                 /* NFS requires lookups for "." and ".." */
 3170                 SDT_PROBE2(fusefs, , vnops, trace, 1,
 3171                         "VOP_VPTOFH without FUSE_EXPORT_SUPPORT");
 3172                 return EOPNOTSUPP;
 3173         }
 3174         if ((mp->mnt_flag & MNT_EXPORTED) &&
 3175                 !(data->dataflags & FSESS_NO_OPENDIR_SUPPORT))
 3176         {
 3177                 /*
 3178                  * NFS is stateless, so nfsd must reopen a directory on every
 3179                  * call to VOP_READDIR, passing in the d_off field from the
 3180                  * final dirent of the previous invocation.  But without
 3181                  * FUSE_NO_OPENDIR_SUPPORT, the FUSE protocol does not
 3182                  * guarantee that d_off will be valid after a directory is
 3183                  * closed and reopened.  So prohibit exporting FUSE file
 3184                  * systems that don't set that flag.
 3185                  *
 3186                  * But userspace NFS servers don't have this problem.
 3187                  */
 3188                 SDT_PROBE2(fusefs, , vnops, trace, 1,
 3189                         "VOP_VPTOFH without FUSE_NO_OPENDIR_SUPPORT");
 3190                 return EOPNOTSUPP;
 3191         }
 3192 
 3193         err = fuse_internal_getattr(vp, &va, curthread->td_ucred, curthread);
 3194         if (err)
 3195                 return err;
 3196 
 3197         /*ip = VTOI(ap->a_vp);*/
 3198         /*ufhp = (struct ufid *)ap->a_fhp;*/
 3199         fhp->len = sizeof(struct fuse_fid);
 3200         fhp->nid = fvdat->nid;
 3201         if (fvdat->generation <= UINT32_MAX)
 3202                 fhp->gen = fvdat->generation;
 3203         else
 3204                 return EOVERFLOW;
 3205         return (0);
 3206 }

Cache object: ae4579af3493381976354dc901c2cb5b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.