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_ipc.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$");
   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/mount.h>
   74 #include <sys/vnode.h>
   75 #include <sys/signalvar.h>
   76 #include <sys/syscallsubr.h>
   77 #include <sys/sysctl.h>
   78 #include <vm/uma.h>
   79 
   80 #include "fuse.h"
   81 #include "fuse_node.h"
   82 #include "fuse_ipc.h"
   83 #include "fuse_internal.h"
   84 
   85 #define FUSE_DEBUG_MODULE IPC
   86 #include "fuse_debug.h"
   87 
   88 static struct fuse_ticket *fticket_alloc(struct fuse_data *data);
   89 static void fticket_refresh(struct fuse_ticket *ftick);
   90 static void fticket_destroy(struct fuse_ticket *ftick);
   91 static int fticket_wait_answer(struct fuse_ticket *ftick);
   92 static __inline__ int 
   93 fticket_aw_pull_uio(struct fuse_ticket *ftick,
   94     struct uio *uio);
   95 
   96 static int fuse_body_audit(struct fuse_ticket *ftick, size_t blen);
   97 static __inline__ void 
   98 fuse_setup_ihead(struct fuse_in_header *ihead,
   99     struct fuse_ticket *ftick,
  100     uint64_t nid,
  101     enum fuse_opcode op,
  102     size_t blen,
  103     pid_t pid,
  104     struct ucred *cred);
  105 
  106 static fuse_handler_t fuse_standard_handler;
  107 
  108 SYSCTL_NODE(_vfs, OID_AUTO, fuse, CTLFLAG_RW, 0, "FUSE tunables");
  109 SYSCTL_STRING(_vfs_fuse, OID_AUTO, version, CTLFLAG_RD,
  110     FUSE_FREEBSD_VERSION, 0, "fuse-freebsd version");
  111 static int fuse_ticket_count = 0;
  112 
  113 SYSCTL_INT(_vfs_fuse, OID_AUTO, ticket_count, CTLFLAG_RW,
  114     &fuse_ticket_count, 0, "number of allocated tickets");
  115 static long fuse_iov_permanent_bufsize = 1 << 19;
  116 
  117 SYSCTL_LONG(_vfs_fuse, OID_AUTO, iov_permanent_bufsize, CTLFLAG_RW,
  118     &fuse_iov_permanent_bufsize, 0,
  119     "limit for permanently stored buffer size for fuse_iovs");
  120 static int fuse_iov_credit = 16;
  121 
  122 SYSCTL_INT(_vfs_fuse, OID_AUTO, iov_credit, CTLFLAG_RW,
  123     &fuse_iov_credit, 0,
  124     "how many times is an oversized fuse_iov tolerated");
  125 
  126 MALLOC_DEFINE(M_FUSEMSG, "fuse_msgbuf", "fuse message buffer");
  127 static uma_zone_t ticket_zone;
  128 
  129 static void
  130 fuse_block_sigs(sigset_t *oldset)
  131 {
  132         sigset_t newset;
  133 
  134         SIGFILLSET(newset);
  135         SIGDELSET(newset, SIGKILL);
  136         if (kern_sigprocmask(curthread, SIG_BLOCK, &newset, oldset, 0))
  137                 panic("%s: Invalid operation for kern_sigprocmask()",
  138                     __func__);
  139 }
  140 
  141 static void
  142 fuse_restore_sigs(sigset_t *oldset)
  143 {
  144 
  145         if (kern_sigprocmask(curthread, SIG_SETMASK, oldset, NULL, 0))
  146                 panic("%s: Invalid operation for kern_sigprocmask()",
  147                     __func__);
  148 }
  149 
  150 void
  151 fiov_init(struct fuse_iov *fiov, size_t size)
  152 {
  153         uint32_t msize = FU_AT_LEAST(size);
  154 
  155         debug_printf("fiov=%p, size=%zd\n", fiov, size);
  156 
  157         fiov->len = 0;
  158 
  159         fiov->base = malloc(msize, M_FUSEMSG, M_WAITOK | M_ZERO);
  160 
  161         fiov->allocated_size = msize;
  162         fiov->credit = fuse_iov_credit;
  163 }
  164 
  165 void
  166 fiov_teardown(struct fuse_iov *fiov)
  167 {
  168         debug_printf("fiov=%p\n", fiov);
  169 
  170         MPASS(fiov->base != NULL);
  171         free(fiov->base, M_FUSEMSG);
  172 }
  173 
  174 void
  175 fiov_adjust(struct fuse_iov *fiov, size_t size)
  176 {
  177         debug_printf("fiov=%p, size=%zd\n", fiov, size);
  178 
  179         if (fiov->allocated_size < size ||
  180             (fuse_iov_permanent_bufsize >= 0 &&
  181             fiov->allocated_size - size > fuse_iov_permanent_bufsize &&
  182             --fiov->credit < 0)) {
  183 
  184                 fiov->base = realloc(fiov->base, FU_AT_LEAST(size), M_FUSEMSG,
  185                     M_WAITOK | M_ZERO);
  186                 if (!fiov->base) {
  187                         panic("FUSE: realloc failed");
  188                 }
  189                 fiov->allocated_size = FU_AT_LEAST(size);
  190                 fiov->credit = fuse_iov_credit;
  191         }
  192         fiov->len = size;
  193 }
  194 
  195 void
  196 fiov_refresh(struct fuse_iov *fiov)
  197 {
  198         debug_printf("fiov=%p\n", fiov);
  199 
  200         bzero(fiov->base, fiov->len);
  201         fiov_adjust(fiov, 0);
  202 }
  203 
  204 static int
  205 fticket_ctor(void *mem, int size, void *arg, int flags)
  206 {
  207         struct fuse_ticket *ftick = mem;
  208         struct fuse_data *data = arg;
  209 
  210         debug_printf("ftick=%p data=%p\n", ftick, data);
  211 
  212         FUSE_ASSERT_MS_DONE(ftick);
  213         FUSE_ASSERT_AW_DONE(ftick);
  214 
  215         ftick->tk_data = data;
  216 
  217         if (ftick->tk_unique != 0)
  218                 fticket_refresh(ftick);
  219 
  220         /* May be truncated to 32 bits */
  221         ftick->tk_unique = atomic_fetchadd_long(&data->ticketer, 1);
  222         if (ftick->tk_unique == 0)
  223                 ftick->tk_unique = atomic_fetchadd_long(&data->ticketer, 1);
  224 
  225         refcount_init(&ftick->tk_refcount, 1);
  226         atomic_add_acq_int(&fuse_ticket_count, 1);
  227 
  228         return 0;
  229 }
  230 
  231 static void
  232 fticket_dtor(void *mem, int size, void *arg)
  233 {
  234         struct fuse_ticket *ftick = mem;
  235 
  236         debug_printf("ftick=%p\n", ftick);
  237 
  238         FUSE_ASSERT_MS_DONE(ftick);
  239         FUSE_ASSERT_AW_DONE(ftick);
  240 
  241         atomic_subtract_acq_int(&fuse_ticket_count, 1);
  242 }
  243 
  244 static int
  245 fticket_init(void *mem, int size, int flags)
  246 {
  247         struct fuse_ticket *ftick = mem;
  248 
  249         FS_DEBUG("ftick=%p\n", ftick);
  250 
  251         bzero(ftick, sizeof(struct fuse_ticket));
  252 
  253         fiov_init(&ftick->tk_ms_fiov, sizeof(struct fuse_in_header));
  254         ftick->tk_ms_type = FT_M_FIOV;
  255 
  256         mtx_init(&ftick->tk_aw_mtx, "fuse answer delivery mutex", NULL, MTX_DEF);
  257         fiov_init(&ftick->tk_aw_fiov, 0);
  258         ftick->tk_aw_type = FT_A_FIOV;
  259 
  260         return 0;
  261 }
  262 
  263 static void
  264 fticket_fini(void *mem, int size)
  265 {
  266         struct fuse_ticket *ftick = mem;
  267 
  268         FS_DEBUG("ftick=%p\n", ftick);
  269 
  270         fiov_teardown(&ftick->tk_ms_fiov);
  271         fiov_teardown(&ftick->tk_aw_fiov);
  272         mtx_destroy(&ftick->tk_aw_mtx);
  273 }
  274 
  275 static __inline struct fuse_ticket *
  276 fticket_alloc(struct fuse_data *data)
  277 {
  278         return uma_zalloc_arg(ticket_zone, data, M_WAITOK);
  279 }
  280 
  281 static __inline void
  282 fticket_destroy(struct fuse_ticket *ftick)
  283 {
  284         return uma_zfree(ticket_zone, ftick);
  285 }
  286 
  287 static  __inline__
  288 void
  289 fticket_refresh(struct fuse_ticket *ftick)
  290 {
  291         debug_printf("ftick=%p\n", ftick);
  292 
  293         FUSE_ASSERT_MS_DONE(ftick);
  294         FUSE_ASSERT_AW_DONE(ftick);
  295 
  296         fiov_refresh(&ftick->tk_ms_fiov);
  297         ftick->tk_ms_bufdata = NULL;
  298         ftick->tk_ms_bufsize = 0;
  299         ftick->tk_ms_type = FT_M_FIOV;
  300 
  301         bzero(&ftick->tk_aw_ohead, sizeof(struct fuse_out_header));
  302 
  303         fiov_refresh(&ftick->tk_aw_fiov);
  304         ftick->tk_aw_errno = 0;
  305         ftick->tk_aw_bufdata = NULL;
  306         ftick->tk_aw_bufsize = 0;
  307         ftick->tk_aw_type = FT_A_FIOV;
  308 
  309         ftick->tk_flag = 0;
  310 }
  311 
  312 static int
  313 fticket_wait_answer(struct fuse_ticket *ftick)
  314 {
  315         sigset_t tset;
  316         int err = 0;
  317         struct fuse_data *data;
  318 
  319         debug_printf("ftick=%p\n", ftick);
  320         fuse_lck_mtx_lock(ftick->tk_aw_mtx);
  321 
  322         if (fticket_answered(ftick)) {
  323                 goto out;
  324         }
  325         data = ftick->tk_data;
  326 
  327         if (fdata_get_dead(data)) {
  328                 err = ENOTCONN;
  329                 fticket_set_answered(ftick);
  330                 goto out;
  331         }
  332         fuse_block_sigs(&tset);
  333         err = msleep(ftick, &ftick->tk_aw_mtx, PCATCH, "fu_ans",
  334             data->daemon_timeout * hz);
  335         fuse_restore_sigs(&tset);
  336         if (err == EAGAIN) {            /* same as EWOULDBLOCK */
  337 #ifdef XXXIP                            /* die conditionally */
  338                 if (!fdata_get_dead(data)) {
  339                         fdata_set_dead(data);
  340                 }
  341 #endif
  342                 err = ETIMEDOUT;
  343                 fticket_set_answered(ftick);
  344         }
  345 out:
  346         if (!(err || fticket_answered(ftick))) {
  347                 debug_printf("FUSE: requester was woken up but still no answer");
  348                 err = ENXIO;
  349         }
  350         fuse_lck_mtx_unlock(ftick->tk_aw_mtx);
  351 
  352         return err;
  353 }
  354 
  355 static  __inline__
  356 int
  357 fticket_aw_pull_uio(struct fuse_ticket *ftick, struct uio *uio)
  358 {
  359         int err = 0;
  360         size_t len = uio_resid(uio);
  361 
  362         debug_printf("ftick=%p, uio=%p\n", ftick, uio);
  363 
  364         if (len) {
  365                 switch (ftick->tk_aw_type) {
  366                 case FT_A_FIOV:
  367                         fiov_adjust(fticket_resp(ftick), len);
  368                         err = uiomove(fticket_resp(ftick)->base, len, uio);
  369                         if (err) {
  370                                 debug_printf("FUSE: FT_A_FIOV: error is %d"
  371                                              " (%p, %zd, %p)\n",
  372                                              err, fticket_resp(ftick)->base, 
  373                                              len, uio);
  374                         }
  375                         break;
  376 
  377                 case FT_A_BUF:
  378                         ftick->tk_aw_bufsize = len;
  379                         err = uiomove(ftick->tk_aw_bufdata, len, uio);
  380                         if (err) {
  381                                 debug_printf("FUSE: FT_A_BUF: error is %d"
  382                                              " (%p, %zd, %p)\n",
  383                                              err, ftick->tk_aw_bufdata, len, uio);
  384                         }
  385                         break;
  386 
  387                 default:
  388                         panic("FUSE: unknown answer type for ticket %p", ftick);
  389                 }
  390         }
  391         return err;
  392 }
  393 
  394 int
  395 fticket_pull(struct fuse_ticket *ftick, struct uio *uio)
  396 {
  397         int err = 0;
  398 
  399         debug_printf("ftick=%p, uio=%p\n", ftick, uio);
  400 
  401         if (ftick->tk_aw_ohead.error) {
  402                 return 0;
  403         }
  404         err = fuse_body_audit(ftick, uio_resid(uio));
  405         if (!err) {
  406                 err = fticket_aw_pull_uio(ftick, uio);
  407         }
  408         return err;
  409 }
  410 
  411 struct fuse_data *
  412 fdata_alloc(struct cdev *fdev, struct ucred *cred)
  413 {
  414         struct fuse_data *data;
  415 
  416         debug_printf("fdev=%p\n", fdev);
  417 
  418         data = malloc(sizeof(struct fuse_data), M_FUSEMSG, M_WAITOK | M_ZERO);
  419 
  420         data->fdev = fdev;
  421         mtx_init(&data->ms_mtx, "fuse message list mutex", NULL, MTX_DEF);
  422         STAILQ_INIT(&data->ms_head);
  423         mtx_init(&data->aw_mtx, "fuse answer list mutex", NULL, MTX_DEF);
  424         TAILQ_INIT(&data->aw_head);
  425         data->daemoncred = crhold(cred);
  426         data->daemon_timeout = FUSE_DEFAULT_DAEMON_TIMEOUT;
  427         sx_init(&data->rename_lock, "fuse rename lock");
  428         data->ref = 1;
  429 
  430         return data;
  431 }
  432 
  433 void
  434 fdata_trydestroy(struct fuse_data *data)
  435 {
  436         FS_DEBUG("data=%p data.mp=%p data.fdev=%p data.flags=%04x\n",
  437             data, data->mp, data->fdev, data->dataflags);
  438 
  439         FS_DEBUG("destroy: data=%p\n", data);
  440         data->ref--;
  441         MPASS(data->ref >= 0);
  442         if (data->ref != 0)
  443                 return;
  444 
  445         /* Driving off stage all that stuff thrown at device... */
  446         mtx_destroy(&data->ms_mtx);
  447         mtx_destroy(&data->aw_mtx);
  448         sx_destroy(&data->rename_lock);
  449 
  450         crfree(data->daemoncred);
  451 
  452         free(data, M_FUSEMSG);
  453 }
  454 
  455 void
  456 fdata_set_dead(struct fuse_data *data)
  457 {
  458         debug_printf("data=%p\n", data);
  459 
  460         FUSE_LOCK();
  461         if (fdata_get_dead(data)) {
  462                 FUSE_UNLOCK();
  463                 return;
  464         }
  465         fuse_lck_mtx_lock(data->ms_mtx);
  466         data->dataflags |= FSESS_DEAD;
  467         wakeup_one(data);
  468         selwakeuppri(&data->ks_rsel, PZERO + 1);
  469         wakeup(&data->ticketer);
  470         fuse_lck_mtx_unlock(data->ms_mtx);
  471         FUSE_UNLOCK();
  472 }
  473 
  474 struct fuse_ticket *
  475 fuse_ticket_fetch(struct fuse_data *data)
  476 {
  477         int err = 0;
  478         struct fuse_ticket *ftick;
  479 
  480         debug_printf("data=%p\n", data);
  481 
  482         ftick = fticket_alloc(data);
  483 
  484         if (!(data->dataflags & FSESS_INITED)) {
  485                 /* Sleep until get answer for INIT messsage */
  486                 FUSE_LOCK();
  487                 if (!(data->dataflags & FSESS_INITED) && data->ticketer > 2) {
  488                         err = msleep(&data->ticketer, &fuse_mtx, PCATCH | PDROP,
  489                             "fu_ini", 0);
  490                         if (err)
  491                                 fdata_set_dead(data);
  492                 } else
  493                         FUSE_UNLOCK();
  494         }
  495         return ftick;
  496 }
  497 
  498 int
  499 fuse_ticket_drop(struct fuse_ticket *ftick)
  500 {
  501         int die;
  502 
  503         die = refcount_release(&ftick->tk_refcount);
  504         debug_printf("ftick=%p refcount=%d\n", ftick, ftick->tk_refcount);
  505         if (die)
  506                 fticket_destroy(ftick);
  507 
  508         return die;
  509 }
  510 
  511 void
  512 fuse_insert_callback(struct fuse_ticket *ftick, fuse_handler_t * handler)
  513 {
  514         debug_printf("ftick=%p, handler=%p data=%p\n", ftick, ftick->tk_data, 
  515                      handler);
  516 
  517         if (fdata_get_dead(ftick->tk_data)) {
  518                 return;
  519         }
  520         ftick->tk_aw_handler = handler;
  521 
  522         fuse_lck_mtx_lock(ftick->tk_data->aw_mtx);
  523         fuse_aw_push(ftick);
  524         fuse_lck_mtx_unlock(ftick->tk_data->aw_mtx);
  525 }
  526 
  527 void
  528 fuse_insert_message(struct fuse_ticket *ftick)
  529 {
  530         debug_printf("ftick=%p\n", ftick);
  531 
  532         if (ftick->tk_flag & FT_DIRTY) {
  533                 panic("FUSE: ticket reused without being refreshed");
  534         }
  535         ftick->tk_flag |= FT_DIRTY;
  536 
  537         if (fdata_get_dead(ftick->tk_data)) {
  538                 return;
  539         }
  540         fuse_lck_mtx_lock(ftick->tk_data->ms_mtx);
  541         fuse_ms_push(ftick);
  542         wakeup_one(ftick->tk_data);
  543         selwakeuppri(&ftick->tk_data->ks_rsel, PZERO + 1);
  544         fuse_lck_mtx_unlock(ftick->tk_data->ms_mtx);
  545 }
  546 
  547 static int
  548 fuse_body_audit(struct fuse_ticket *ftick, size_t blen)
  549 {
  550         int err = 0;
  551         enum fuse_opcode opcode;
  552 
  553         debug_printf("ftick=%p, blen = %zu\n", ftick, blen);
  554 
  555         opcode = fticket_opcode(ftick);
  556 
  557         switch (opcode) {
  558         case FUSE_LOOKUP:
  559                 err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL;
  560                 break;
  561 
  562         case FUSE_FORGET:
  563                 panic("FUSE: a handler has been intalled for FUSE_FORGET");
  564                 break;
  565 
  566         case FUSE_GETATTR:
  567                 err = (blen == sizeof(struct fuse_attr_out)) ? 0 : EINVAL;
  568                 break;
  569 
  570         case FUSE_SETATTR:
  571                 err = (blen == sizeof(struct fuse_attr_out)) ? 0 : EINVAL;
  572                 break;
  573 
  574         case FUSE_READLINK:
  575                 err = (PAGE_SIZE >= blen) ? 0 : EINVAL;
  576                 break;
  577 
  578         case FUSE_SYMLINK:
  579                 err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL;
  580                 break;
  581 
  582         case FUSE_MKNOD:
  583                 err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL;
  584                 break;
  585 
  586         case FUSE_MKDIR:
  587                 err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL;
  588                 break;
  589 
  590         case FUSE_UNLINK:
  591                 err = (blen == 0) ? 0 : EINVAL;
  592                 break;
  593 
  594         case FUSE_RMDIR:
  595                 err = (blen == 0) ? 0 : EINVAL;
  596                 break;
  597 
  598         case FUSE_RENAME:
  599                 err = (blen == 0) ? 0 : EINVAL;
  600                 break;
  601 
  602         case FUSE_LINK:
  603                 err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL;
  604                 break;
  605 
  606         case FUSE_OPEN:
  607                 err = (blen == sizeof(struct fuse_open_out)) ? 0 : EINVAL;
  608                 break;
  609 
  610         case FUSE_READ:
  611                 err = (((struct fuse_read_in *)(
  612                     (char *)ftick->tk_ms_fiov.base +
  613                     sizeof(struct fuse_in_header)
  614                     ))->size >= blen) ? 0 : EINVAL;
  615                 break;
  616 
  617         case FUSE_WRITE:
  618                 err = (blen == sizeof(struct fuse_write_out)) ? 0 : EINVAL;
  619                 break;
  620 
  621         case FUSE_STATFS:
  622                 if (fuse_libabi_geq(ftick->tk_data, 7, 4)) {
  623                         err = (blen == sizeof(struct fuse_statfs_out)) ? 
  624                           0 : EINVAL;
  625                 } else {
  626                         err = (blen == FUSE_COMPAT_STATFS_SIZE) ? 0 : EINVAL;
  627                 }
  628                 break;
  629 
  630         case FUSE_RELEASE:
  631                 err = (blen == 0) ? 0 : EINVAL;
  632                 break;
  633 
  634         case FUSE_FSYNC:
  635                 err = (blen == 0) ? 0 : EINVAL;
  636                 break;
  637 
  638         case FUSE_SETXATTR:
  639                 err = (blen == 0) ? 0 : EINVAL;
  640                 break;
  641 
  642         case FUSE_GETXATTR:
  643         case FUSE_LISTXATTR:
  644                 /*
  645                  * These can have varying response lengths, and 0 length
  646                  * isn't necessarily invalid.
  647                  */
  648                 err = 0;
  649                 break;
  650 
  651         case FUSE_REMOVEXATTR:
  652                 err = (blen == 0) ? 0 : EINVAL;
  653                 break;
  654 
  655         case FUSE_FLUSH:
  656                 err = (blen == 0) ? 0 : EINVAL;
  657                 break;
  658 
  659         case FUSE_INIT:
  660                 if (blen == sizeof(struct fuse_init_out) || blen == 8) {
  661                         err = 0;
  662                 } else {
  663                         err = EINVAL;
  664                 }
  665                 break;
  666 
  667         case FUSE_OPENDIR:
  668                 err = (blen == sizeof(struct fuse_open_out)) ? 0 : EINVAL;
  669                 break;
  670 
  671         case FUSE_READDIR:
  672                 err = (((struct fuse_read_in *)(
  673                     (char *)ftick->tk_ms_fiov.base +
  674                     sizeof(struct fuse_in_header)
  675                     ))->size >= blen) ? 0 : EINVAL;
  676                 break;
  677 
  678         case FUSE_RELEASEDIR:
  679                 err = (blen == 0) ? 0 : EINVAL;
  680                 break;
  681 
  682         case FUSE_FSYNCDIR:
  683                 err = (blen == 0) ? 0 : EINVAL;
  684                 break;
  685 
  686         case FUSE_GETLK:
  687                 panic("FUSE: no response body format check for FUSE_GETLK");
  688                 break;
  689 
  690         case FUSE_SETLK:
  691                 panic("FUSE: no response body format check for FUSE_SETLK");
  692                 break;
  693 
  694         case FUSE_SETLKW:
  695                 panic("FUSE: no response body format check for FUSE_SETLKW");
  696                 break;
  697 
  698         case FUSE_ACCESS:
  699                 err = (blen == 0) ? 0 : EINVAL;
  700                 break;
  701 
  702         case FUSE_CREATE:
  703                 err = (blen == sizeof(struct fuse_entry_out) +
  704                     sizeof(struct fuse_open_out)) ? 0 : EINVAL;
  705                 break;
  706 
  707         case FUSE_DESTROY:
  708                 err = (blen == 0) ? 0 : EINVAL;
  709                 break;
  710 
  711         default:
  712                 panic("FUSE: opcodes out of sync (%d)\n", opcode);
  713         }
  714 
  715         return err;
  716 }
  717 
  718 static void
  719 fuse_setup_ihead(struct fuse_in_header *ihead,
  720     struct fuse_ticket *ftick,
  721     uint64_t nid,
  722     enum fuse_opcode op,
  723     size_t blen,
  724     pid_t pid,
  725     struct ucred *cred)
  726 {
  727         ihead->len = sizeof(*ihead) + blen;
  728         ihead->unique = ftick->tk_unique;
  729         ihead->nodeid = nid;
  730         ihead->opcode = op;
  731 
  732         debug_printf("ihead=%p, ftick=%p, nid=%ju, op=%d, blen=%zu\n",
  733             ihead, ftick, (uintmax_t)nid, op, blen);
  734 
  735         ihead->pid = pid;
  736         ihead->uid = cred->cr_uid;
  737         ihead->gid = cred->cr_rgid;
  738 }
  739 
  740 /*
  741  * fuse_standard_handler just pulls indata and wakes up pretender.
  742  * Doesn't try to interpret data, that's left for the pretender.
  743  * Though might do a basic size verification before the pull-in takes place
  744  */
  745 
  746 static int
  747 fuse_standard_handler(struct fuse_ticket *ftick, struct uio *uio)
  748 {
  749         int err = 0;
  750 
  751         debug_printf("ftick=%p, uio=%p\n", ftick, uio);
  752 
  753         err = fticket_pull(ftick, uio);
  754 
  755         fuse_lck_mtx_lock(ftick->tk_aw_mtx);
  756 
  757         if (!fticket_answered(ftick)) {
  758                 fticket_set_answered(ftick);
  759                 ftick->tk_aw_errno = err;
  760                 wakeup(ftick);
  761         }
  762         fuse_lck_mtx_unlock(ftick->tk_aw_mtx);
  763 
  764         return err;
  765 }
  766 
  767 void
  768 fdisp_make_pid(struct fuse_dispatcher *fdip,
  769     enum fuse_opcode op,
  770     struct mount *mp,
  771     uint64_t nid,
  772     pid_t pid,
  773     struct ucred *cred)
  774 {
  775         struct fuse_data *data = fuse_get_mpdata(mp);
  776 
  777         debug_printf("fdip=%p, op=%d, mp=%p, nid=%ju\n",
  778             fdip, op, mp, (uintmax_t)nid);
  779 
  780         if (fdip->tick) {
  781                 fticket_refresh(fdip->tick);
  782         } else {
  783                 fdip->tick = fuse_ticket_fetch(data);
  784         }
  785 
  786         FUSE_DIMALLOC(&fdip->tick->tk_ms_fiov, fdip->finh,
  787             fdip->indata, fdip->iosize);
  788 
  789         fuse_setup_ihead(fdip->finh, fdip->tick, nid, op, fdip->iosize, pid, cred);
  790 }
  791 
  792 void
  793 fdisp_make(struct fuse_dispatcher *fdip,
  794     enum fuse_opcode op,
  795     struct mount *mp,
  796     uint64_t nid,
  797     struct thread *td,
  798     struct ucred *cred)
  799 {
  800         RECTIFY_TDCR(td, cred);
  801 
  802         return fdisp_make_pid(fdip, op, mp, nid, td->td_proc->p_pid, cred);
  803 }
  804 
  805 void
  806 fdisp_make_vp(struct fuse_dispatcher *fdip,
  807     enum fuse_opcode op,
  808     struct vnode *vp,
  809     struct thread *td,
  810     struct ucred *cred)
  811 {
  812         debug_printf("fdip=%p, op=%d, vp=%p\n", fdip, op, vp);
  813         RECTIFY_TDCR(td, cred);
  814         return fdisp_make_pid(fdip, op, vnode_mount(vp), VTOI(vp),
  815             td->td_proc->p_pid, cred);
  816 }
  817 
  818 int
  819 fdisp_wait_answ(struct fuse_dispatcher *fdip)
  820 {
  821         int err = 0;
  822 
  823         fdip->answ_stat = 0;
  824         fuse_insert_callback(fdip->tick, fuse_standard_handler);
  825         fuse_insert_message(fdip->tick);
  826 
  827         if ((err = fticket_wait_answer(fdip->tick))) {
  828                 debug_printf("IPC: interrupted, err = %d\n", err);
  829 
  830                 fuse_lck_mtx_lock(fdip->tick->tk_aw_mtx);
  831 
  832                 if (fticket_answered(fdip->tick)) {
  833                         /*
  834                          * Just between noticing the interrupt and getting here,
  835                          * the standard handler has completed his job.
  836                          * So we drop the ticket and exit as usual.
  837                          */
  838                         debug_printf("IPC: already answered\n");
  839                         fuse_lck_mtx_unlock(fdip->tick->tk_aw_mtx);
  840                         goto out;
  841                 } else {
  842                         /*
  843                          * So we were faster than the standard handler.
  844                          * Then by setting the answered flag we get *him*
  845                          * to drop the ticket.
  846                          */
  847                         debug_printf("IPC: setting to answered\n");
  848                         fticket_set_answered(fdip->tick);
  849                         fuse_lck_mtx_unlock(fdip->tick->tk_aw_mtx);
  850                         return err;
  851                 }
  852         }
  853         debug_printf("IPC: not interrupted, err = %d\n", err);
  854 
  855         if (fdip->tick->tk_aw_errno) {
  856                 debug_printf("IPC: explicit EIO-ing, tk_aw_errno = %d\n",
  857                     fdip->tick->tk_aw_errno);
  858                 err = EIO;
  859                 goto out;
  860         }
  861         if ((err = fdip->tick->tk_aw_ohead.error)) {
  862                 debug_printf("IPC: setting status to %d\n",
  863                     fdip->tick->tk_aw_ohead.error);
  864                 /*
  865                  * This means a "proper" fuse syscall error.
  866                  * We record this value so the caller will
  867                  * be able to know it's not a boring messaging
  868                  * failure, if she wishes so (and if not, she can
  869                  * just simply propagate the return value of this routine).
  870                  * [XXX Maybe a bitflag would do the job too,
  871                  * if other flags needed, this will be converted thusly.]
  872                  */
  873                 fdip->answ_stat = err;
  874                 goto out;
  875         }
  876         fdip->answ = fticket_resp(fdip->tick)->base;
  877         fdip->iosize = fticket_resp(fdip->tick)->len;
  878 
  879         debug_printf("IPC: all is well\n");
  880 
  881         return 0;
  882 
  883 out:
  884         debug_printf("IPC: dropping ticket, err = %d\n", err);
  885 
  886         return err;
  887 }
  888 
  889 void
  890 fuse_ipc_init(void)
  891 {
  892         ticket_zone = uma_zcreate("fuse_ticket", sizeof(struct fuse_ticket),
  893             fticket_ctor, fticket_dtor, fticket_init, fticket_fini,
  894             UMA_ALIGN_PTR, 0);
  895 }
  896 
  897 void
  898 fuse_ipc_destroy(void)
  899 {
  900         uma_zdestroy(ticket_zone);
  901 }

Cache object: c1cb09e71b79e9cdf8e32bcba1cf3121


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