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 fuse_dispatcher fdi;
  128         struct fuse_open_in *foi;
  129         struct fuse_open_out *foo;
  130         fufh_type_t fufh_type;
  131 
  132         int err = 0;
  133         int oflags = 0;
  134         int op = FUSE_OPEN;
  135 
  136         fufh_type = fflags_2_fufh_type(a_mode);
  137         oflags = fufh_type_2_fflags(fufh_type);
  138 
  139         if (vnode_isdir(vp)) {
  140                 op = FUSE_OPENDIR;
  141                 /* vn_open_vnode already rejects FWRITE on directories */
  142                 MPASS(fufh_type == FUFH_RDONLY || fufh_type == FUFH_EXEC);
  143         }
  144         fdisp_init(&fdi, sizeof(*foi));
  145         fdisp_make_vp(&fdi, op, vp, td, cred);
  146 
  147         foi = fdi.indata;
  148         foi->flags = oflags;
  149 
  150         if ((err = fdisp_wait_answ(&fdi))) {
  151                 SDT_PROBE2(fusefs, , file, trace, 1,
  152                         "OUCH ... daemon didn't give fh");
  153                 if (err == ENOENT) {
  154                         fuse_internal_vnode_disappear(vp);
  155                 }
  156                 goto out;
  157         }
  158         foo = fdi.answ;
  159 
  160         fuse_filehandle_init(vp, fufh_type, fufhp, td, cred, foo);
  161         fuse_vnode_open(vp, foo->open_flags, td);
  162 
  163 out:
  164         fdisp_destroy(&fdi);
  165         return err;
  166 }
  167 
  168 int
  169 fuse_filehandle_close(struct vnode *vp, struct fuse_filehandle *fufh,
  170     struct thread *td, struct ucred *cred)
  171 {
  172         struct fuse_dispatcher fdi;
  173         struct fuse_release_in *fri;
  174 
  175         int err = 0;
  176         int op = FUSE_RELEASE;
  177 
  178         if (fuse_isdeadfs(vp)) {
  179                 goto out;
  180         }
  181         if (vnode_isdir(vp))
  182                 op = FUSE_RELEASEDIR;
  183         fdisp_init(&fdi, sizeof(*fri));
  184         fdisp_make_vp(&fdi, op, vp, td, cred);
  185         fri = fdi.indata;
  186         fri->fh = fufh->fh_id;
  187         fri->flags = fufh_type_2_fflags(fufh->fufh_type);
  188         /* 
  189          * If the file has a POSIX lock then we're supposed to set lock_owner.
  190          * If not, then lock_owner is undefined.  So we may as well always set
  191          * it.
  192          */
  193         fri->lock_owner = td->td_proc->p_pid;
  194 
  195         err = fdisp_wait_answ(&fdi);
  196         fdisp_destroy(&fdi);
  197 
  198 out:
  199         counter_u64_add(fuse_fh_count, -1);
  200         LIST_REMOVE(fufh, next);
  201         free(fufh, M_FUSE_FILEHANDLE);
  202 
  203         return err;
  204 }
  205 
  206 /*
  207  * Check for a valid file handle, first the type requested, but if that
  208  * isn't valid, try for FUFH_RDWR.
  209  * Return true if there is any file handle with the correct credentials and
  210  * a fufh type that includes the provided one.
  211  * A pid of 0 means "don't care"
  212  */
  213 bool
  214 fuse_filehandle_validrw(struct vnode *vp, int mode,
  215         struct ucred *cred, pid_t pid)
  216 {
  217         struct fuse_vnode_data *fvdat = VTOFUD(vp);
  218         struct fuse_filehandle *fufh;
  219         fufh_type_t fufh_type = fflags_2_fufh_type(mode);
  220 
  221         /* 
  222          * Unlike fuse_filehandle_get, we want to search for a filehandle with
  223          * the exact cred, and no fallback
  224          */
  225         LIST_FOREACH(fufh, &fvdat->handles, next) {
  226                 if (fufh->fufh_type == fufh_type &&
  227                     fufh->uid == cred->cr_uid &&
  228                     fufh->gid == cred->cr_rgid &&
  229                     (pid == 0 || fufh->pid == pid))
  230                         return true;
  231         }
  232 
  233         if (fufh_type == FUFH_EXEC)
  234                 return false;
  235 
  236         /* Fallback: find a RDWR list entry with the right cred */
  237         LIST_FOREACH(fufh, &fvdat->handles, next) {
  238                 if (fufh->fufh_type == FUFH_RDWR &&
  239                     fufh->uid == cred->cr_uid &&
  240                     fufh->gid == cred->cr_rgid &&
  241                     (pid == 0 || fufh->pid == pid))
  242                         return true;
  243         }
  244 
  245         return false;
  246 }
  247 
  248 int
  249 fuse_filehandle_get(struct vnode *vp, int fflag,
  250     struct fuse_filehandle **fufhp, struct ucred *cred, pid_t pid)
  251 {
  252         struct fuse_vnode_data *fvdat = VTOFUD(vp);
  253         struct fuse_filehandle *fufh;
  254         fufh_type_t fufh_type;
  255 
  256         fufh_type = fflags_2_fufh_type(fflag);
  257         /* cred can be NULL for in-kernel clients */
  258         if (cred == NULL)
  259                 goto fallback;
  260 
  261         LIST_FOREACH(fufh, &fvdat->handles, next) {
  262                 if (fufh->fufh_type == fufh_type &&
  263                     fufh->uid == cred->cr_uid &&
  264                     fufh->gid == cred->cr_rgid &&
  265                     (pid == 0 || fufh->pid == pid))
  266                         goto found;
  267         }
  268 
  269 fallback:
  270         /* Fallback: find a list entry with the right flags */
  271         LIST_FOREACH(fufh, &fvdat->handles, next) {
  272                 if (fufh->fufh_type == fufh_type)
  273                         break;
  274         }
  275 
  276         if (fufh == NULL)
  277                 return EBADF;
  278 
  279 found:
  280         if (fufhp != NULL)
  281                 *fufhp = fufh;
  282         return 0;
  283 }
  284 
  285 /* Get a file handle with any kind of flags */
  286 int
  287 fuse_filehandle_get_anyflags(struct vnode *vp,
  288     struct fuse_filehandle **fufhp, struct ucred *cred, pid_t pid)
  289 {
  290         struct fuse_vnode_data *fvdat = VTOFUD(vp);
  291         struct fuse_filehandle *fufh;
  292 
  293         if (cred == NULL)
  294                 goto fallback;
  295 
  296         LIST_FOREACH(fufh, &fvdat->handles, next) {
  297                 if (fufh->uid == cred->cr_uid &&
  298                     fufh->gid == cred->cr_rgid &&
  299                     (pid == 0 || fufh->pid == pid))
  300                         goto found;
  301         }
  302 
  303 fallback:
  304         /* Fallback: find any list entry */
  305         fufh = LIST_FIRST(&fvdat->handles);
  306 
  307         if (fufh == NULL)
  308                 return EBADF;
  309 
  310 found:
  311         if (fufhp != NULL)
  312                 *fufhp = fufh;
  313         return 0;
  314 }
  315 
  316 int
  317 fuse_filehandle_getrw(struct vnode *vp, int fflag,
  318     struct fuse_filehandle **fufhp, struct ucred *cred, pid_t pid)
  319 {
  320         int err;
  321 
  322         err = fuse_filehandle_get(vp, fflag, fufhp, cred, pid);
  323         if (err)
  324                 err = fuse_filehandle_get(vp, FREAD | FWRITE, fufhp, cred, pid);
  325         return err;
  326 }
  327 
  328 void
  329 fuse_filehandle_init(struct vnode *vp, fufh_type_t fufh_type,
  330     struct fuse_filehandle **fufhp, struct thread *td, struct ucred *cred,
  331     struct fuse_open_out *foo)
  332 {
  333         struct fuse_vnode_data *fvdat = VTOFUD(vp);
  334         struct fuse_filehandle *fufh;
  335 
  336         fufh = malloc(sizeof(struct fuse_filehandle), M_FUSE_FILEHANDLE,
  337                 M_WAITOK);
  338         MPASS(fufh != NULL);
  339         fufh->fh_id = foo->fh;
  340         fufh->fufh_type = fufh_type;
  341         fufh->gid = cred->cr_rgid;
  342         fufh->uid = cred->cr_uid;
  343         fufh->pid = td->td_proc->p_pid;
  344         fufh->fuse_open_flags = foo->open_flags;
  345         if (!FUFH_IS_VALID(fufh)) {
  346                 panic("FUSE: init: invalid filehandle id (type=%d)", fufh_type);
  347         }
  348         LIST_INSERT_HEAD(&fvdat->handles, fufh, next);
  349         if (fufhp != NULL)
  350                 *fufhp = fufh;
  351 
  352         counter_u64_add(fuse_fh_count, 1);
  353 
  354         if (foo->open_flags & FOPEN_DIRECT_IO) {
  355                 ASSERT_VOP_ELOCKED(vp, __func__);
  356                 VTOFUD(vp)->flag |= FN_DIRECTIO;
  357                 fuse_io_invalbuf(vp, td);
  358         } else {
  359                 if ((foo->open_flags & FOPEN_KEEP_CACHE) == 0)
  360                         fuse_io_invalbuf(vp, td);
  361                 VTOFUD(vp)->flag &= ~FN_DIRECTIO;
  362         }
  363 
  364 }
  365 
  366 void
  367 fuse_file_init(void)
  368 {
  369         fuse_fh_count = counter_u64_alloc(M_WAITOK);
  370 }
  371 
  372 void
  373 fuse_file_destroy(void)
  374 {
  375         counter_u64_free(fuse_fh_count);
  376 }

Cache object: 845a9020f882daf5d342e90cf2c353b3


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