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_node.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  * Copyright (c) 2007-2009 Google Inc. and Amit Singh
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions are
    7  * met:
    8  *
    9  * * Redistributions of source code must retain the above copyright
   10  *   notice, this list of conditions and the following disclaimer.
   11  * * Redistributions in binary form must reproduce the above
   12  *   copyright notice, this list of conditions and the following disclaimer
   13  *   in the documentation and/or other materials provided with the
   14  *   distribution.
   15  * * Neither the name of Google Inc. nor the names of its
   16  *   contributors may be used to endorse or promote products derived from
   17  *   this software without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   30  *
   31  * Copyright (C) 2005 Csaba Henk.
   32  * All rights reserved.
   33  *
   34  * Redistribution and use in source and binary forms, with or without
   35  * modification, are permitted provided that the following conditions
   36  * are met:
   37  * 1. Redistributions of source code must retain the above copyright
   38  *    notice, this list of conditions and the following disclaimer.
   39  * 2. Redistributions in binary form must reproduce the above copyright
   40  *    notice, this list of conditions and the following disclaimer in the
   41  *    documentation and/or other materials provided with the distribution.
   42  *
   43  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   44  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   45  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   46  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
   47  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   48  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   49  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   50  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   51  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   52  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   53  * SUCH DAMAGE.
   54  */
   55 
   56 #include <sys/cdefs.h>
   57 __FBSDID("$FreeBSD: releng/10.1/sys/fs/fuse/fuse_node.c 242727 2012-11-08 00:32:49Z attilio $");
   58 
   59 #include <sys/types.h>
   60 #include <sys/module.h>
   61 #include <sys/systm.h>
   62 #include <sys/errno.h>
   63 #include <sys/param.h>
   64 #include <sys/kernel.h>
   65 #include <sys/conf.h>
   66 #include <sys/uio.h>
   67 #include <sys/malloc.h>
   68 #include <sys/queue.h>
   69 #include <sys/lock.h>
   70 #include <sys/sx.h>
   71 #include <sys/mutex.h>
   72 #include <sys/proc.h>
   73 #include <sys/vnode.h>
   74 #include <sys/namei.h>
   75 #include <sys/mount.h>
   76 #include <sys/sysctl.h>
   77 #include <sys/fcntl.h>
   78 #include <sys/fnv_hash.h>
   79 #include <sys/priv.h>
   80 #include <security/mac/mac_framework.h>
   81 #include <vm/vm.h>
   82 #include <vm/vm_extern.h>
   83 
   84 #include "fuse.h"
   85 #include "fuse_node.h"
   86 #include "fuse_internal.h"
   87 #include "fuse_io.h"
   88 #include "fuse_ipc.h"
   89 
   90 #define FUSE_DEBUG_MODULE VNOPS
   91 #include "fuse_debug.h"
   92 
   93 MALLOC_DEFINE(M_FUSEVN, "fuse_vnode", "fuse vnode private data");
   94 
   95 static int fuse_node_count = 0;
   96 
   97 SYSCTL_INT(_vfs_fuse, OID_AUTO, node_count, CTLFLAG_RD,
   98     &fuse_node_count, 0, "");
   99 
  100 int     fuse_data_cache_enable = 1;
  101 
  102 SYSCTL_INT(_vfs_fuse, OID_AUTO, data_cache_enable, CTLFLAG_RW,
  103     &fuse_data_cache_enable, 0, "");
  104 
  105 int     fuse_data_cache_invalidate = 0;
  106 
  107 SYSCTL_INT(_vfs_fuse, OID_AUTO, data_cache_invalidate, CTLFLAG_RW,
  108     &fuse_data_cache_invalidate, 0, "");
  109 
  110 int     fuse_mmap_enable = 1;
  111 
  112 SYSCTL_INT(_vfs_fuse, OID_AUTO, mmap_enable, CTLFLAG_RW,
  113     &fuse_mmap_enable, 0, "");
  114 
  115 int     fuse_refresh_size = 0;
  116 
  117 SYSCTL_INT(_vfs_fuse, OID_AUTO, refresh_size, CTLFLAG_RW,
  118     &fuse_refresh_size, 0, "");
  119 
  120 int     fuse_sync_resize = 1;
  121 
  122 SYSCTL_INT(_vfs_fuse, OID_AUTO, sync_resize, CTLFLAG_RW,
  123     &fuse_sync_resize, 0, "");
  124 
  125 int     fuse_fix_broken_io = 0;
  126 
  127 SYSCTL_INT(_vfs_fuse, OID_AUTO, fix_broken_io, CTLFLAG_RW,
  128     &fuse_fix_broken_io, 0, "");
  129 
  130 static void
  131 fuse_vnode_init(struct vnode *vp, struct fuse_vnode_data *fvdat,
  132     uint64_t nodeid, enum vtype vtyp)
  133 {
  134         int i;
  135 
  136         fvdat->nid = nodeid;
  137         if (nodeid == FUSE_ROOT_ID) {
  138                 vp->v_vflag |= VV_ROOT;
  139         }
  140         vp->v_type = vtyp;
  141         vp->v_data = fvdat;
  142 
  143         for (i = 0; i < FUFH_MAXTYPE; i++)
  144                 fvdat->fufh[i].fh_type = FUFH_INVALID;
  145 
  146         atomic_add_acq_int(&fuse_node_count, 1);
  147 }
  148 
  149 void
  150 fuse_vnode_destroy(struct vnode *vp)
  151 {
  152         struct fuse_vnode_data *fvdat = vp->v_data;
  153 
  154         vp->v_data = NULL;
  155         free(fvdat, M_FUSEVN);
  156 
  157         atomic_subtract_acq_int(&fuse_node_count, 1);
  158 }
  159 
  160 static int
  161 fuse_vnode_cmp(struct vnode *vp, void *nidp)
  162 {
  163         return (VTOI(vp) != *((uint64_t *)nidp));
  164 }
  165 
  166 static uint32_t __inline
  167 fuse_vnode_hash(uint64_t id)
  168 {
  169         return (fnv_32_buf(&id, sizeof(id), FNV1_32_INIT));
  170 }
  171 
  172 static int
  173 fuse_vnode_alloc(struct mount *mp,
  174     struct thread *td,
  175     uint64_t nodeid,
  176     enum vtype vtyp,
  177     struct vnode **vpp)
  178 {
  179         struct fuse_vnode_data *fvdat;
  180         struct vnode *vp2;
  181         int err = 0;
  182 
  183         FS_DEBUG("been asked for vno #%ju\n", (uintmax_t)nodeid);
  184 
  185         if (vtyp == VNON) {
  186                 return EINVAL;
  187         }
  188         *vpp = NULL;
  189         err = vfs_hash_get(mp, fuse_vnode_hash(nodeid), LK_EXCLUSIVE, td, vpp,
  190             fuse_vnode_cmp, &nodeid);
  191         if (err)
  192                 return (err);
  193 
  194         if (*vpp) {
  195                 MPASS((*vpp)->v_type == vtyp && (*vpp)->v_data != NULL);
  196                 FS_DEBUG("vnode taken from hash\n");
  197                 return (0);
  198         }
  199         fvdat = malloc(sizeof(*fvdat), M_FUSEVN, M_WAITOK | M_ZERO);
  200         err = getnewvnode("fuse", mp, &fuse_vnops, vpp);
  201         if (err) {
  202                 free(fvdat, M_FUSEVN);
  203                 return (err);
  204         }
  205         lockmgr((*vpp)->v_vnlock, LK_EXCLUSIVE, NULL);
  206         fuse_vnode_init(*vpp, fvdat, nodeid, vtyp);
  207         err = insmntque(*vpp, mp);
  208         ASSERT_VOP_ELOCKED(*vpp, "fuse_vnode_alloc");
  209         if (err) {
  210                 free(fvdat, M_FUSEVN);
  211                 *vpp = NULL;
  212                 return (err);
  213         }
  214         err = vfs_hash_insert(*vpp, fuse_vnode_hash(nodeid), LK_EXCLUSIVE,
  215             td, &vp2, fuse_vnode_cmp, &nodeid);
  216         if (err)
  217                 return (err);
  218         if (vp2 != NULL) {
  219                 *vpp = vp2;
  220                 return (0);
  221         }
  222 
  223         ASSERT_VOP_ELOCKED(*vpp, "fuse_vnode_alloc");
  224 
  225         return (0);
  226 }
  227 
  228 int
  229 fuse_vnode_get(struct mount *mp,
  230     uint64_t nodeid,
  231     struct vnode *dvp,
  232     struct vnode **vpp,
  233     struct componentname *cnp,
  234     enum vtype vtyp)
  235 {
  236         struct thread *td = (cnp != NULL ? cnp->cn_thread : curthread);
  237         int err = 0;
  238 
  239         debug_printf("dvp=%p\n", dvp);
  240 
  241         err = fuse_vnode_alloc(mp, td, nodeid, vtyp, vpp);
  242         if (err) {
  243                 return err;
  244         }
  245         if (dvp != NULL) {
  246                 MPASS((cnp->cn_flags & ISDOTDOT) == 0);
  247                 MPASS(!(cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.'));
  248                 fuse_vnode_setparent(*vpp, dvp);
  249         }
  250         if (dvp != NULL && cnp != NULL && (cnp->cn_flags & MAKEENTRY) != 0) {
  251                 ASSERT_VOP_LOCKED(*vpp, "fuse_vnode_get");
  252                 ASSERT_VOP_LOCKED(dvp, "fuse_vnode_get");
  253                 cache_enter(dvp, *vpp, cnp);
  254         }
  255 
  256         /*
  257          * In userland, libfuse uses cached lookups for dot and dotdot entries,
  258          * thus it does not really bump the nlookup counter for forget.
  259          * Follow the same semantic and avoid tu bump it in order to keep
  260          * nlookup counters consistent.
  261          */
  262         if (cnp == NULL || ((cnp->cn_flags & ISDOTDOT) == 0 &&
  263             (cnp->cn_namelen != 1 || cnp->cn_nameptr[0] != '.')))
  264                 VTOFUD(*vpp)->nlookup++;
  265 
  266         return 0;
  267 }
  268 
  269 void
  270 fuse_vnode_open(struct vnode *vp, int32_t fuse_open_flags, struct thread *td)
  271 {
  272         /*
  273          * Funcation is called for every vnode open.
  274          * Merge fuse_open_flags it may be 0
  275          *
  276          * XXXIP: Handle FOPEN_DIRECT_IO and FOPEN_KEEP_CACHE
  277          */
  278 
  279         if (vnode_vtype(vp) == VREG) {
  280                 /* XXXIP prevent getattr, by using cached node size */
  281                 vnode_create_vobject(vp, 0, td);
  282         }
  283 }
  284 
  285 int
  286 fuse_vnode_savesize(struct vnode *vp, struct ucred *cred)
  287 {
  288         struct fuse_vnode_data *fvdat = VTOFUD(vp);
  289         struct thread *td = curthread;
  290         struct fuse_filehandle *fufh = NULL;
  291         struct fuse_dispatcher fdi;
  292         struct fuse_setattr_in *fsai;
  293         int err = 0;
  294 
  295         FS_DEBUG("inode=%ju size=%ju\n", (uintmax_t)VTOI(vp),
  296             (uintmax_t)fvdat->filesize);
  297         ASSERT_VOP_ELOCKED(vp, "fuse_io_extend");
  298 
  299         if (fuse_isdeadfs(vp)) {
  300                 return EBADF;
  301         }
  302         if (vnode_vtype(vp) == VDIR) {
  303                 return EISDIR;
  304         }
  305         if (vfs_isrdonly(vnode_mount(vp))) {
  306                 return EROFS;
  307         }
  308         if (cred == NULL) {
  309                 cred = td->td_ucred;
  310         }
  311         fdisp_init(&fdi, sizeof(*fsai));
  312         fdisp_make_vp(&fdi, FUSE_SETATTR, vp, td, cred);
  313         fsai = fdi.indata;
  314         fsai->valid = 0;
  315 
  316         /* Truncate to a new value. */
  317             fsai->size = fvdat->filesize;
  318         fsai->valid |= FATTR_SIZE;
  319 
  320         fuse_filehandle_getrw(vp, FUFH_WRONLY, &fufh);
  321         if (fufh) {
  322                 fsai->fh = fufh->fh_id;
  323                 fsai->valid |= FATTR_FH;
  324         }
  325         err = fdisp_wait_answ(&fdi);
  326         fdisp_destroy(&fdi);
  327         if (err == 0)
  328                 fvdat->flag &= ~FN_SIZECHANGE;
  329 
  330         return err;
  331 }
  332 
  333 void
  334 fuse_vnode_refreshsize(struct vnode *vp, struct ucred *cred)
  335 {
  336 
  337         struct fuse_vnode_data *fvdat = VTOFUD(vp);
  338         struct vattr va;
  339 
  340         if ((fvdat->flag & FN_SIZECHANGE) != 0 ||
  341             (fuse_refresh_size == 0 && fvdat->filesize != 0))
  342                 return;
  343 
  344         VOP_GETATTR(vp, &va, cred);
  345         FS_DEBUG("refreshed file size: %jd\n", (intmax_t)VTOFUD(vp)->filesize);
  346 }
  347 
  348 int
  349 fuse_vnode_setsize(struct vnode *vp, struct ucred *cred, off_t newsize)
  350 {
  351         struct fuse_vnode_data *fvdat = VTOFUD(vp);
  352         off_t oldsize;
  353         int err = 0;
  354 
  355         FS_DEBUG("inode=%ju oldsize=%ju newsize=%ju\n",
  356             (uintmax_t)VTOI(vp), (uintmax_t)fvdat->filesize,
  357             (uintmax_t)newsize);
  358         ASSERT_VOP_ELOCKED(vp, "fuse_vnode_setsize");
  359 
  360         oldsize = fvdat->filesize;
  361         fvdat->filesize = newsize;
  362         fvdat->flag |= FN_SIZECHANGE;
  363 
  364         if (newsize < oldsize) {
  365                 err = vtruncbuf(vp, cred, newsize, fuse_iosize(vp));
  366         }
  367         vnode_pager_setsize(vp, newsize);
  368         return err;
  369 }

Cache object: e803527f040abbf08ea7d96edb727981


[ 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.