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: releng/10.1/sys/fs/fuse/fuse_ipc.c 241521 2012-10-14 03:51:59Z 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/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                 panic("FUSE_SETXATTR implementor has forgotten to define a"
  640                       " response body format check");
  641                 break;
  642 
  643         case FUSE_GETXATTR:
  644                 panic("FUSE_GETXATTR implementor has forgotten to define a"
  645                       " response body format check");
  646                 break;
  647 
  648         case FUSE_LISTXATTR:
  649                 panic("FUSE_LISTXATTR implementor has forgotten to define a"
  650                       " response body format check");
  651                 break;
  652 
  653         case FUSE_REMOVEXATTR:
  654                 panic("FUSE_REMOVEXATTR implementor has forgotten to define a"
  655                       " response body format check");
  656                 break;
  657 
  658         case FUSE_FLUSH:
  659                 err = (blen == 0) ? 0 : EINVAL;
  660                 break;
  661 
  662         case FUSE_INIT:
  663                 if (blen == sizeof(struct fuse_init_out) || blen == 8) {
  664                         err = 0;
  665                 } else {
  666                         err = EINVAL;
  667                 }
  668                 break;
  669 
  670         case FUSE_OPENDIR:
  671                 err = (blen == sizeof(struct fuse_open_out)) ? 0 : EINVAL;
  672                 break;
  673 
  674         case FUSE_READDIR:
  675                 err = (((struct fuse_read_in *)(
  676                     (char *)ftick->tk_ms_fiov.base +
  677                     sizeof(struct fuse_in_header)
  678                     ))->size >= blen) ? 0 : EINVAL;
  679                 break;
  680 
  681         case FUSE_RELEASEDIR:
  682                 err = (blen == 0) ? 0 : EINVAL;
  683                 break;
  684 
  685         case FUSE_FSYNCDIR:
  686                 err = (blen == 0) ? 0 : EINVAL;
  687                 break;
  688 
  689         case FUSE_GETLK:
  690                 panic("FUSE: no response body format check for FUSE_GETLK");
  691                 break;
  692 
  693         case FUSE_SETLK:
  694                 panic("FUSE: no response body format check for FUSE_SETLK");
  695                 break;
  696 
  697         case FUSE_SETLKW:
  698                 panic("FUSE: no response body format check for FUSE_SETLKW");
  699                 break;
  700 
  701         case FUSE_ACCESS:
  702                 err = (blen == 0) ? 0 : EINVAL;
  703                 break;
  704 
  705         case FUSE_CREATE:
  706                 err = (blen == sizeof(struct fuse_entry_out) +
  707                     sizeof(struct fuse_open_out)) ? 0 : EINVAL;
  708                 break;
  709 
  710         case FUSE_DESTROY:
  711                 err = (blen == 0) ? 0 : EINVAL;
  712                 break;
  713 
  714         default:
  715                 panic("FUSE: opcodes out of sync (%d)\n", opcode);
  716         }
  717 
  718         return err;
  719 }
  720 
  721 static void
  722 fuse_setup_ihead(struct fuse_in_header *ihead,
  723     struct fuse_ticket *ftick,
  724     uint64_t nid,
  725     enum fuse_opcode op,
  726     size_t blen,
  727     pid_t pid,
  728     struct ucred *cred)
  729 {
  730         ihead->len = sizeof(*ihead) + blen;
  731         ihead->unique = ftick->tk_unique;
  732         ihead->nodeid = nid;
  733         ihead->opcode = op;
  734 
  735         debug_printf("ihead=%p, ftick=%p, nid=%ju, op=%d, blen=%zu\n",
  736             ihead, ftick, (uintmax_t)nid, op, blen);
  737 
  738         ihead->pid = pid;
  739         ihead->uid = cred->cr_uid;
  740         ihead->gid = cred->cr_rgid;
  741 }
  742 
  743 /*
  744  * fuse_standard_handler just pulls indata and wakes up pretender.
  745  * Doesn't try to interpret data, that's left for the pretender.
  746  * Though might do a basic size verification before the pull-in takes place
  747  */
  748 
  749 static int
  750 fuse_standard_handler(struct fuse_ticket *ftick, struct uio *uio)
  751 {
  752         int err = 0;
  753 
  754         debug_printf("ftick=%p, uio=%p\n", ftick, uio);
  755 
  756         err = fticket_pull(ftick, uio);
  757 
  758         fuse_lck_mtx_lock(ftick->tk_aw_mtx);
  759 
  760         if (!fticket_answered(ftick)) {
  761                 fticket_set_answered(ftick);
  762                 ftick->tk_aw_errno = err;
  763                 wakeup(ftick);
  764         }
  765         fuse_lck_mtx_unlock(ftick->tk_aw_mtx);
  766 
  767         return err;
  768 }
  769 
  770 void
  771 fdisp_make_pid(struct fuse_dispatcher *fdip,
  772     enum fuse_opcode op,
  773     struct mount *mp,
  774     uint64_t nid,
  775     pid_t pid,
  776     struct ucred *cred)
  777 {
  778         struct fuse_data *data = fuse_get_mpdata(mp);
  779 
  780         debug_printf("fdip=%p, op=%d, mp=%p, nid=%ju\n",
  781             fdip, op, mp, (uintmax_t)nid);
  782 
  783         if (fdip->tick) {
  784                 fticket_refresh(fdip->tick);
  785         } else {
  786                 fdip->tick = fuse_ticket_fetch(data);
  787         }
  788 
  789         FUSE_DIMALLOC(&fdip->tick->tk_ms_fiov, fdip->finh,
  790             fdip->indata, fdip->iosize);
  791 
  792         fuse_setup_ihead(fdip->finh, fdip->tick, nid, op, fdip->iosize, pid, cred);
  793 }
  794 
  795 void
  796 fdisp_make(struct fuse_dispatcher *fdip,
  797     enum fuse_opcode op,
  798     struct mount *mp,
  799     uint64_t nid,
  800     struct thread *td,
  801     struct ucred *cred)
  802 {
  803         RECTIFY_TDCR(td, cred);
  804 
  805         return fdisp_make_pid(fdip, op, mp, nid, td->td_proc->p_pid, cred);
  806 }
  807 
  808 void
  809 fdisp_make_vp(struct fuse_dispatcher *fdip,
  810     enum fuse_opcode op,
  811     struct vnode *vp,
  812     struct thread *td,
  813     struct ucred *cred)
  814 {
  815         debug_printf("fdip=%p, op=%d, vp=%p\n", fdip, op, vp);
  816         RECTIFY_TDCR(td, cred);
  817         return fdisp_make_pid(fdip, op, vnode_mount(vp), VTOI(vp),
  818             td->td_proc->p_pid, cred);
  819 }
  820 
  821 int
  822 fdisp_wait_answ(struct fuse_dispatcher *fdip)
  823 {
  824         int err = 0;
  825 
  826         fdip->answ_stat = 0;
  827         fuse_insert_callback(fdip->tick, fuse_standard_handler);
  828         fuse_insert_message(fdip->tick);
  829 
  830         if ((err = fticket_wait_answer(fdip->tick))) {
  831                 debug_printf("IPC: interrupted, err = %d\n", err);
  832 
  833                 fuse_lck_mtx_lock(fdip->tick->tk_aw_mtx);
  834 
  835                 if (fticket_answered(fdip->tick)) {
  836                         /*
  837                          * Just between noticing the interrupt and getting here,
  838                          * the standard handler has completed his job.
  839                          * So we drop the ticket and exit as usual.
  840                          */
  841                         debug_printf("IPC: already answered\n");
  842                         fuse_lck_mtx_unlock(fdip->tick->tk_aw_mtx);
  843                         goto out;
  844                 } else {
  845                         /*
  846                          * So we were faster than the standard handler.
  847                          * Then by setting the answered flag we get *him*
  848                          * to drop the ticket.
  849                          */
  850                         debug_printf("IPC: setting to answered\n");
  851                         fticket_set_answered(fdip->tick);
  852                         fuse_lck_mtx_unlock(fdip->tick->tk_aw_mtx);
  853                         return err;
  854                 }
  855         }
  856         debug_printf("IPC: not interrupted, err = %d\n", err);
  857 
  858         if (fdip->tick->tk_aw_errno) {
  859                 debug_printf("IPC: explicit EIO-ing, tk_aw_errno = %d\n",
  860                     fdip->tick->tk_aw_errno);
  861                 err = EIO;
  862                 goto out;
  863         }
  864         if ((err = fdip->tick->tk_aw_ohead.error)) {
  865                 debug_printf("IPC: setting status to %d\n",
  866                     fdip->tick->tk_aw_ohead.error);
  867                 /*
  868                  * This means a "proper" fuse syscall error.
  869                  * We record this value so the caller will
  870                  * be able to know it's not a boring messaging
  871                  * failure, if she wishes so (and if not, she can
  872                  * just simply propagate the return value of this routine).
  873                  * [XXX Maybe a bitflag would do the job too,
  874                  * if other flags needed, this will be converted thusly.]
  875                  */
  876                 fdip->answ_stat = err;
  877                 goto out;
  878         }
  879         fdip->answ = fticket_resp(fdip->tick)->base;
  880         fdip->iosize = fticket_resp(fdip->tick)->len;
  881 
  882         debug_printf("IPC: all is well\n");
  883 
  884         return 0;
  885 
  886 out:
  887         debug_printf("IPC: dropping ticket, err = %d\n", err);
  888 
  889         return err;
  890 }
  891 
  892 void
  893 fuse_ipc_init(void)
  894 {
  895         ticket_zone = uma_zcreate("fuse_ticket", sizeof(struct fuse_ticket),
  896             fticket_ctor, fticket_dtor, fticket_init, fticket_fini,
  897             UMA_ALIGN_PTR, 0);
  898 }
  899 
  900 void
  901 fuse_ipc_destroy(void)
  902 {
  903         uma_zdestroy(ticket_zone);
  904 }

Cache object: e260e4b69cf36a7f3d1dd59ef4c07053


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