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_file.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/systm.h>
   68 #include <sys/counter.h>
   69 #include <sys/module.h>
   70 #include <sys/errno.h>
   71 #include <sys/kernel.h>
   72 #include <sys/conf.h>
   73 #include <sys/uio.h>
   74 #include <sys/malloc.h>
   75 #include <sys/queue.h>
   76 #include <sys/lock.h>
   77 #include <sys/sx.h>
   78 #include <sys/mutex.h>
   79 #include <sys/proc.h>
   80 #include <sys/mount.h>
   81 #include <sys/vnode.h>
   82 #include <sys/sdt.h>
   83 #include <sys/sysctl.h>
   84 
   85 #include "fuse.h"
   86 #include "fuse_file.h"
   87 #include "fuse_internal.h"
   88 #include "fuse_io.h"
   89 #include "fuse_ipc.h"
   90 #include "fuse_node.h"
   91 
   92 MALLOC_DEFINE(M_FUSE_FILEHANDLE, "fuse_filefilehandle", "FUSE file handle");
   93 
   94 SDT_PROVIDER_DECLARE(fusefs);
   95 /* 
   96  * Fuse trace probe:
   97  * arg0: verbosity.  Higher numbers give more verbose messages
   98  * arg1: Textual message
   99  */
  100 SDT_PROBE_DEFINE2(fusefs, , file, trace, "int", "char*");
  101 
  102 static counter_u64_t fuse_fh_count;
  103 
  104 SYSCTL_COUNTER_U64(_vfs_fusefs_stats, OID_AUTO, filehandle_count, CTLFLAG_RD,
  105     &fuse_fh_count, "number of open FUSE filehandles");
  106 
  107 /* Get the FUFH type for a particular access mode */
  108 static inline fufh_type_t
  109 fflags_2_fufh_type(int fflags)
  110 {
  111         if ((fflags & FREAD) && (fflags & FWRITE))
  112                 return FUFH_RDWR;
  113         else if (fflags & (FWRITE))
  114                 return FUFH_WRONLY;
  115         else if (fflags & (FREAD))
  116                 return FUFH_RDONLY;
  117         else if (fflags & (FEXEC))
  118                 return FUFH_EXEC;
  119         else
  120                 panic("FUSE: What kind of a flag is this (%x)?", fflags);
  121 }
  122 
  123 int
  124 fuse_filehandle_open(struct vnode *vp, int a_mode,
  125     struct fuse_filehandle **fufhp, struct thread *td, struct ucred *cred)
  126 {
  127         struct mount *mp = vnode_mount(vp);
  128         struct fuse_data *data = fuse_get_mpdata(mp);
  129         struct fuse_dispatcher fdi;
  130         const struct fuse_open_out default_foo = {
  131                 .fh = 0,
  132                 .open_flags = FOPEN_KEEP_CACHE,
  133                 .padding = 0
  134         };
  135         struct fuse_open_in *foi = NULL;
  136         const struct fuse_open_out *foo;
  137         fufh_type_t fufh_type;
  138         int dataflags = data->dataflags;
  139         int err = 0;
  140         int oflags = 0;
  141         int op = FUSE_OPEN;
  142         int relop = FUSE_RELEASE;
  143         int fsess_no_op_support = FSESS_NO_OPEN_SUPPORT;
  144 
  145         fufh_type = fflags_2_fufh_type(a_mode);
  146         oflags = fufh_type_2_fflags(fufh_type);
  147 
  148         if (vnode_isdir(vp)) {
  149                 op = FUSE_OPENDIR;
  150                 relop = FUSE_RELEASEDIR;
  151                 fsess_no_op_support = FSESS_NO_OPENDIR_SUPPORT;
  152                 /* vn_open_vnode already rejects FWRITE on directories */
  153                 MPASS(fufh_type == FUFH_RDONLY || fufh_type == FUFH_EXEC);
  154         }
  155         fdisp_init(&fdi, sizeof(*foi));
  156         if (fsess_not_impl(mp, op) && dataflags & fsess_no_op_support) {
  157                 /* The operation implicitly succeeds */
  158                 foo = &default_foo;
  159         } else {
  160                 fdisp_make_vp(&fdi, op, vp, td, cred);
  161 
  162                 foi = fdi.indata;
  163                 foi->flags = oflags;
  164 
  165                 err = fdisp_wait_answ(&fdi);
  166                 if (err == ENOSYS && dataflags & fsess_no_op_support) {
  167                         /* The operation implicitly succeeds */
  168                         foo = &default_foo;
  169                         fsess_set_notimpl(mp, op);
  170                         fsess_set_notimpl(mp, relop);
  171                         err = 0;
  172                 } else if (err) {
  173                         SDT_PROBE2(fusefs, , file, trace, 1,
  174                                 "OUCH ... daemon didn't give fh");
  175                         if (err == ENOENT)
  176                                 fuse_internal_vnode_disappear(vp);
  177                         goto out;
  178                 } else {
  179                         foo = fdi.answ;
  180                 }
  181         }
  182 
  183         fuse_filehandle_init(vp, fufh_type, fufhp, td, cred, foo);
  184         fuse_vnode_open(vp, foo->open_flags, td);
  185 
  186 out:
  187         if (foi)
  188                 fdisp_destroy(&fdi);
  189         return err;
  190 }
  191 
  192 int
  193 fuse_filehandle_close(struct vnode *vp, struct fuse_filehandle *fufh,
  194     struct thread *td, struct ucred *cred)
  195 {
  196         struct mount *mp = vnode_mount(vp);
  197         struct fuse_dispatcher fdi;
  198         struct fuse_release_in *fri;
  199 
  200         int err = 0;
  201         int op = FUSE_RELEASE;
  202 
  203         if (fuse_isdeadfs(vp)) {
  204                 goto out;
  205         }
  206         if (vnode_isdir(vp))
  207                 op = FUSE_RELEASEDIR;
  208 
  209         if (fsess_not_impl(mp, op))
  210                 goto out;
  211 
  212         fdisp_init(&fdi, sizeof(*fri));
  213         fdisp_make_vp(&fdi, op, vp, td, cred);
  214         fri = fdi.indata;
  215         fri->fh = fufh->fh_id;
  216         fri->flags = fufh_type_2_fflags(fufh->fufh_type);
  217         /* 
  218          * If the file has a POSIX lock then we're supposed to set lock_owner.
  219          * If not, then lock_owner is undefined.  So we may as well always set
  220          * it.
  221          */
  222         fri->lock_owner = td->td_proc->p_pid;
  223 
  224         err = fdisp_wait_answ(&fdi);
  225         fdisp_destroy(&fdi);
  226 
  227 out:
  228         counter_u64_add(fuse_fh_count, -1);
  229         LIST_REMOVE(fufh, next);
  230         free(fufh, M_FUSE_FILEHANDLE);
  231 
  232         return err;
  233 }
  234 
  235 /*
  236  * Check for a valid file handle, first the type requested, but if that
  237  * isn't valid, try for FUFH_RDWR.
  238  * Return true if there is any file handle with the correct credentials and
  239  * a fufh type that includes the provided one.
  240  * A pid of 0 means "don't care"
  241  */
  242 bool
  243 fuse_filehandle_validrw(struct vnode *vp, int mode,
  244         struct ucred *cred, pid_t pid)
  245 {
  246         struct fuse_vnode_data *fvdat = VTOFUD(vp);
  247         struct fuse_filehandle *fufh;
  248         fufh_type_t fufh_type = fflags_2_fufh_type(mode);
  249 
  250         /* 
  251          * Unlike fuse_filehandle_get, we want to search for a filehandle with
  252          * the exact cred, and no fallback
  253          */
  254         LIST_FOREACH(fufh, &fvdat->handles, next) {
  255                 if (fufh->fufh_type == fufh_type &&
  256                     fufh->uid == cred->cr_uid &&
  257                     fufh->gid == cred->cr_rgid &&
  258                     (pid == 0 || fufh->pid == pid))
  259                         return true;
  260         }
  261 
  262         if (fufh_type == FUFH_EXEC)
  263                 return false;
  264 
  265         /* Fallback: find a RDWR list entry with the right cred */
  266         LIST_FOREACH(fufh, &fvdat->handles, next) {
  267                 if (fufh->fufh_type == FUFH_RDWR &&
  268                     fufh->uid == cred->cr_uid &&
  269                     fufh->gid == cred->cr_rgid &&
  270                     (pid == 0 || fufh->pid == pid))
  271                         return true;
  272         }
  273 
  274         return false;
  275 }
  276 
  277 int
  278 fuse_filehandle_get(struct vnode *vp, int fflag,
  279     struct fuse_filehandle **fufhp, struct ucred *cred, pid_t pid)
  280 {
  281         struct fuse_vnode_data *fvdat = VTOFUD(vp);
  282         struct fuse_filehandle *fufh;
  283         fufh_type_t fufh_type;
  284 
  285         fufh_type = fflags_2_fufh_type(fflag);
  286         /* cred can be NULL for in-kernel clients */
  287         if (cred == NULL)
  288                 goto fallback;
  289 
  290         LIST_FOREACH(fufh, &fvdat->handles, next) {
  291                 if (fufh->fufh_type == fufh_type &&
  292                     fufh->uid == cred->cr_uid &&
  293                     fufh->gid == cred->cr_rgid &&
  294                     (pid == 0 || fufh->pid == pid))
  295                         goto found;
  296         }
  297 
  298 fallback:
  299         /* Fallback: find a list entry with the right flags */
  300         LIST_FOREACH(fufh, &fvdat->handles, next) {
  301                 if (fufh->fufh_type == fufh_type)
  302                         break;
  303         }
  304 
  305         if (fufh == NULL)
  306                 return EBADF;
  307 
  308 found:
  309         if (fufhp != NULL)
  310                 *fufhp = fufh;
  311         return 0;
  312 }
  313 
  314 /* Get a file handle with any kind of flags */
  315 int
  316 fuse_filehandle_get_anyflags(struct vnode *vp,
  317     struct fuse_filehandle **fufhp, struct ucred *cred, pid_t pid)
  318 {
  319         struct fuse_vnode_data *fvdat = VTOFUD(vp);
  320         struct fuse_filehandle *fufh;
  321 
  322         if (cred == NULL)
  323                 goto fallback;
  324 
  325         LIST_FOREACH(fufh, &fvdat->handles, next) {
  326                 if (fufh->uid == cred->cr_uid &&
  327                     fufh->gid == cred->cr_rgid &&
  328                     (pid == 0 || fufh->pid == pid))
  329                         goto found;
  330         }
  331 
  332 fallback:
  333         /* Fallback: find any list entry */
  334         fufh = LIST_FIRST(&fvdat->handles);
  335 
  336         if (fufh == NULL)
  337                 return EBADF;
  338 
  339 found:
  340         if (fufhp != NULL)
  341                 *fufhp = fufh;
  342         return 0;
  343 }
  344 
  345 int
  346 fuse_filehandle_getrw(struct vnode *vp, int fflag,
  347     struct fuse_filehandle **fufhp, struct ucred *cred, pid_t pid)
  348 {
  349         int err;
  350 
  351         err = fuse_filehandle_get(vp, fflag, fufhp, cred, pid);
  352         if (err)
  353                 err = fuse_filehandle_get(vp, FREAD | FWRITE, fufhp, cred, pid);
  354         return err;
  355 }
  356 
  357 void
  358 fuse_filehandle_init(struct vnode *vp, fufh_type_t fufh_type,
  359     struct fuse_filehandle **fufhp, struct thread *td, const struct ucred *cred,
  360     const struct fuse_open_out *foo)
  361 {
  362         struct fuse_vnode_data *fvdat = VTOFUD(vp);
  363         struct fuse_filehandle *fufh;
  364 
  365         fufh = malloc(sizeof(struct fuse_filehandle), M_FUSE_FILEHANDLE,
  366                 M_WAITOK);
  367         MPASS(fufh != NULL);
  368         fufh->fh_id = foo->fh;
  369         fufh->fufh_type = fufh_type;
  370         fufh->gid = cred->cr_rgid;
  371         fufh->uid = cred->cr_uid;
  372         fufh->pid = td->td_proc->p_pid;
  373         fufh->fuse_open_flags = foo->open_flags;
  374         if (!FUFH_IS_VALID(fufh)) {
  375                 panic("FUSE: init: invalid filehandle id (type=%d)", fufh_type);
  376         }
  377         LIST_INSERT_HEAD(&fvdat->handles, fufh, next);
  378         if (fufhp != NULL)
  379                 *fufhp = fufh;
  380 
  381         counter_u64_add(fuse_fh_count, 1);
  382 
  383         if (foo->open_flags & FOPEN_DIRECT_IO) {
  384                 ASSERT_VOP_ELOCKED(vp, __func__);
  385                 VTOFUD(vp)->flag |= FN_DIRECTIO;
  386                 fuse_io_invalbuf(vp, td);
  387         } else {
  388                 if ((foo->open_flags & FOPEN_KEEP_CACHE) == 0)
  389                         fuse_io_invalbuf(vp, td);
  390                 VTOFUD(vp)->flag &= ~FN_DIRECTIO;
  391         }
  392 
  393 }
  394 
  395 void
  396 fuse_file_init(void)
  397 {
  398         fuse_fh_count = counter_u64_alloc(M_WAITOK);
  399 }
  400 
  401 void
  402 fuse_file_destroy(void)
  403 {
  404         counter_u64_free(fuse_fh_count);
  405 }

Cache object: 6a46668b1a0bb91a867611b9148794cb


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