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  * 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/module.h>
   68 #include <sys/systm.h>
   69 #include <sys/counter.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/sdt.h>
   82 #include <sys/vnode.h>
   83 #include <sys/signalvar.h>
   84 #include <sys/syscallsubr.h>
   85 #include <sys/sysctl.h>
   86 #include <vm/uma.h>
   87 
   88 #include "fuse.h"
   89 #include "fuse_node.h"
   90 #include "fuse_ipc.h"
   91 #include "fuse_internal.h"
   92 
   93 SDT_PROVIDER_DECLARE(fusefs);
   94 /* 
   95  * Fuse trace probe:
   96  * arg0: verbosity.  Higher numbers give more verbose messages
   97  * arg1: Textual message
   98  */
   99 SDT_PROBE_DEFINE2(fusefs, , ipc, trace, "int", "char*");
  100 
  101 static void fdisp_make_pid(struct fuse_dispatcher *fdip, enum fuse_opcode op,
  102     struct fuse_data *data, uint64_t nid, pid_t pid, struct ucred *cred);
  103 static void fuse_interrupt_send(struct fuse_ticket *otick, int err);
  104 static struct fuse_ticket *fticket_alloc(struct fuse_data *data);
  105 static void fticket_refresh(struct fuse_ticket *ftick);
  106 static inline void fticket_reset(struct fuse_ticket *ftick);
  107 static void fticket_destroy(struct fuse_ticket *ftick);
  108 static int fticket_wait_answer(struct fuse_ticket *ftick);
  109 static inline int 
  110 fticket_aw_pull_uio(struct fuse_ticket *ftick,
  111     struct uio *uio);
  112 
  113 static int fuse_body_audit(struct fuse_ticket *ftick, size_t blen);
  114 
  115 static fuse_handler_t fuse_standard_handler;
  116 
  117 static counter_u64_t fuse_ticket_count;
  118 SYSCTL_COUNTER_U64(_vfs_fusefs_stats, OID_AUTO, ticket_count, CTLFLAG_RD,
  119     &fuse_ticket_count, "Number of allocated tickets");
  120 
  121 static long fuse_iov_permanent_bufsize = 1 << 19;
  122 
  123 SYSCTL_LONG(_vfs_fusefs, OID_AUTO, iov_permanent_bufsize, CTLFLAG_RW,
  124     &fuse_iov_permanent_bufsize, 0,
  125     "limit for permanently stored buffer size for fuse_iovs");
  126 static int fuse_iov_credit = 16;
  127 
  128 SYSCTL_INT(_vfs_fusefs, OID_AUTO, iov_credit, CTLFLAG_RW,
  129     &fuse_iov_credit, 0,
  130     "how many times is an oversized fuse_iov tolerated");
  131 
  132 MALLOC_DEFINE(M_FUSEMSG, "fuse_msgbuf", "fuse message buffer");
  133 static uma_zone_t ticket_zone;
  134 
  135 /* 
  136  * TODO: figure out how to timeout INTERRUPT requests, because the daemon may
  137  * leagally never respond
  138  */
  139 static int
  140 fuse_interrupt_callback(struct fuse_ticket *tick, struct uio *uio)
  141 {
  142         struct fuse_ticket *otick, *x_tick;
  143         struct fuse_interrupt_in *fii;
  144         struct fuse_data *data = tick->tk_data;
  145         bool found = false;
  146 
  147         fii = (struct fuse_interrupt_in*)((char*)tick->tk_ms_fiov.base +
  148                 sizeof(struct fuse_in_header));
  149 
  150         fuse_lck_mtx_lock(data->aw_mtx);
  151         TAILQ_FOREACH_SAFE(otick, &data->aw_head, tk_aw_link, x_tick) {
  152                 if (otick->tk_unique == fii->unique) {
  153                         found = true;
  154                         break;
  155                 }
  156         }
  157         fuse_lck_mtx_unlock(data->aw_mtx);
  158 
  159         if (!found) {
  160                 /* Original is already complete.  Just return */
  161                 return 0;
  162         }
  163 
  164         /* Clear the original ticket's interrupt association */
  165         otick->irq_unique = 0;
  166 
  167         if (tick->tk_aw_ohead.error == ENOSYS) {
  168                 fsess_set_notimpl(data->mp, FUSE_INTERRUPT);
  169                 return 0;
  170         } else if (tick->tk_aw_ohead.error == EAGAIN) {
  171                 /* 
  172                  * There are two reasons we might get this:
  173                  * 1) the daemon received the INTERRUPT request before the
  174                  *    original, or
  175                  * 2) the daemon received the INTERRUPT request after it
  176                  *    completed the original request.
  177                  * In the first case we should re-send the INTERRUPT.  In the
  178                  * second, we should ignore it.
  179                  */
  180                 /* Resend */
  181                 fuse_interrupt_send(otick, EINTR);
  182                 return 0;
  183         } else {
  184                 /* Illegal FUSE_INTERRUPT response */
  185                 return EINVAL;
  186         }
  187 }
  188 
  189 /* Interrupt the operation otick.  Return err as its error code */
  190 void
  191 fuse_interrupt_send(struct fuse_ticket *otick, int err)
  192 {
  193         struct fuse_dispatcher fdi;
  194         struct fuse_interrupt_in *fii;
  195         struct fuse_in_header *ftick_hdr;
  196         struct fuse_data *data = otick->tk_data;
  197         struct fuse_ticket *tick, *xtick;
  198         struct ucred reused_creds;
  199         gid_t reused_groups[1];
  200 
  201         if (otick->irq_unique == 0) {
  202                 /* 
  203                  * If the daemon hasn't yet received otick, then we can answer
  204                  * it ourselves and return.
  205                  */
  206                 fuse_lck_mtx_lock(data->ms_mtx);
  207                 STAILQ_FOREACH_SAFE(tick, &otick->tk_data->ms_head, tk_ms_link,
  208                         xtick) {
  209                         if (tick == otick) {
  210                                 STAILQ_REMOVE(&otick->tk_data->ms_head, tick,
  211                                         fuse_ticket, tk_ms_link);
  212                                 otick->tk_data->ms_count--;
  213                                 otick->tk_ms_link.stqe_next = NULL;
  214                                 fuse_lck_mtx_unlock(data->ms_mtx);
  215 
  216                                 fuse_lck_mtx_lock(otick->tk_aw_mtx);
  217                                 if (!fticket_answered(otick)) {
  218                                         fticket_set_answered(otick);
  219                                         otick->tk_aw_errno = err;
  220                                         wakeup(otick);
  221                                 }
  222                                 fuse_lck_mtx_unlock(otick->tk_aw_mtx);
  223 
  224                                 fuse_ticket_drop(tick);
  225                                 return;
  226                         }
  227                 }
  228                 fuse_lck_mtx_unlock(data->ms_mtx);
  229 
  230                 /*
  231                  * If the fuse daemon doesn't support interrupts, then there's
  232                  * nothing more that we can do
  233                  */
  234                 if (!fsess_isimpl(data->mp, FUSE_INTERRUPT))
  235                         return;
  236 
  237                 /* 
  238                  * If the fuse daemon has already received otick, then we must
  239                  * send FUSE_INTERRUPT.
  240                  */
  241                 ftick_hdr = fticket_in_header(otick);
  242                 reused_creds.cr_uid = ftick_hdr->uid;
  243                 reused_groups[0] = ftick_hdr->gid;
  244                 reused_creds.cr_groups = reused_groups;
  245                 fdisp_init(&fdi, sizeof(*fii));
  246                 fdisp_make_pid(&fdi, FUSE_INTERRUPT, data, ftick_hdr->nodeid,
  247                         ftick_hdr->pid, &reused_creds);
  248 
  249                 fii = fdi.indata;
  250                 fii->unique = otick->tk_unique;
  251                 fuse_insert_callback(fdi.tick, fuse_interrupt_callback);
  252 
  253                 otick->irq_unique = fdi.tick->tk_unique;
  254                 /* Interrupt ops should be delivered ASAP */
  255                 fuse_insert_message(fdi.tick, true);
  256                 fdisp_destroy(&fdi);
  257         } else {
  258                 /* This ticket has already been interrupted */
  259         }
  260 }
  261 
  262 void
  263 fiov_init(struct fuse_iov *fiov, size_t size)
  264 {
  265         uint32_t msize = FU_AT_LEAST(size);
  266 
  267         fiov->len = 0;
  268 
  269         fiov->base = malloc(msize, M_FUSEMSG, M_WAITOK | M_ZERO);
  270 
  271         fiov->allocated_size = msize;
  272         fiov->credit = fuse_iov_credit;
  273 }
  274 
  275 void
  276 fiov_teardown(struct fuse_iov *fiov)
  277 {
  278         MPASS(fiov->base != NULL);
  279         free(fiov->base, M_FUSEMSG);
  280 }
  281 
  282 void
  283 fiov_adjust(struct fuse_iov *fiov, size_t size)
  284 {
  285         if (fiov->allocated_size < size ||
  286             (fuse_iov_permanent_bufsize >= 0 &&
  287             fiov->allocated_size - size > fuse_iov_permanent_bufsize &&
  288             --fiov->credit < 0)) {
  289 
  290                 fiov->base = realloc(fiov->base, FU_AT_LEAST(size), M_FUSEMSG,
  291                     M_WAITOK | M_ZERO);
  292                 if (!fiov->base) {
  293                         panic("FUSE: realloc failed");
  294                 }
  295                 fiov->allocated_size = FU_AT_LEAST(size);
  296                 fiov->credit = fuse_iov_credit;
  297                 /* Clear data buffer after reallocation */
  298                 bzero(fiov->base, size);
  299         } else if (size > fiov->len) {
  300                 /* Clear newly extended portion of data buffer */
  301                 bzero((char*)fiov->base + fiov->len, size - fiov->len);
  302         }
  303         fiov->len = size;
  304 }
  305 
  306 /* Resize the fiov if needed, and clear it's buffer */
  307 void
  308 fiov_refresh(struct fuse_iov *fiov)
  309 {
  310         fiov_adjust(fiov, 0);
  311 }
  312 
  313 static int
  314 fticket_ctor(void *mem, int size, void *arg, int flags)
  315 {
  316         struct fuse_ticket *ftick = mem;
  317         struct fuse_data *data = arg;
  318 
  319         FUSE_ASSERT_MS_DONE(ftick);
  320         FUSE_ASSERT_AW_DONE(ftick);
  321 
  322         ftick->tk_data = data;
  323         ftick->irq_unique = 0;
  324         refcount_init(&ftick->tk_refcount, 1);
  325         counter_u64_add(fuse_ticket_count, 1);
  326 
  327         fticket_refresh(ftick);
  328 
  329         return 0;
  330 }
  331 
  332 static void
  333 fticket_dtor(void *mem, int size, void *arg)
  334 {
  335 #ifdef INVARIANTS
  336         struct fuse_ticket *ftick = mem;
  337 #endif
  338 
  339         FUSE_ASSERT_MS_DONE(ftick);
  340         FUSE_ASSERT_AW_DONE(ftick);
  341 
  342         counter_u64_add(fuse_ticket_count, -1);
  343 }
  344 
  345 static int
  346 fticket_init(void *mem, int size, int flags)
  347 {
  348         struct fuse_ticket *ftick = mem;
  349 
  350         bzero(ftick, sizeof(struct fuse_ticket));
  351 
  352         fiov_init(&ftick->tk_ms_fiov, sizeof(struct fuse_in_header));
  353 
  354         mtx_init(&ftick->tk_aw_mtx, "fuse answer delivery mutex", NULL, MTX_DEF);
  355         fiov_init(&ftick->tk_aw_fiov, 0);
  356 
  357         return 0;
  358 }
  359 
  360 static void
  361 fticket_fini(void *mem, int size)
  362 {
  363         struct fuse_ticket *ftick = mem;
  364 
  365         fiov_teardown(&ftick->tk_ms_fiov);
  366         fiov_teardown(&ftick->tk_aw_fiov);
  367         mtx_destroy(&ftick->tk_aw_mtx);
  368 }
  369 
  370 static inline struct fuse_ticket *
  371 fticket_alloc(struct fuse_data *data)
  372 {
  373         return uma_zalloc_arg(ticket_zone, data, M_WAITOK);
  374 }
  375 
  376 static inline void
  377 fticket_destroy(struct fuse_ticket *ftick)
  378 {
  379         return uma_zfree(ticket_zone, ftick);
  380 }
  381 
  382 /* Prepare the ticket to be reused and clear its data buffers */
  383 static inline void
  384 fticket_refresh(struct fuse_ticket *ftick)
  385 {
  386         fticket_reset(ftick);
  387 
  388         fiov_refresh(&ftick->tk_ms_fiov);
  389         fiov_refresh(&ftick->tk_aw_fiov);
  390 }
  391 
  392 /* Prepare the ticket to be reused, but don't clear its data buffers */
  393 static inline void
  394 fticket_reset(struct fuse_ticket *ftick)
  395 {
  396         struct fuse_data *data = ftick->tk_data;
  397 
  398         FUSE_ASSERT_MS_DONE(ftick);
  399         FUSE_ASSERT_AW_DONE(ftick);
  400 
  401         bzero(&ftick->tk_aw_ohead, sizeof(struct fuse_out_header));
  402 
  403         ftick->tk_aw_errno = 0;
  404         ftick->tk_flag = 0;
  405 
  406         /* May be truncated to 32 bits on LP32 arches */
  407         ftick->tk_unique = atomic_fetchadd_long(&data->ticketer, 1);
  408         if (ftick->tk_unique == 0)
  409                 ftick->tk_unique = atomic_fetchadd_long(&data->ticketer, 1);
  410 }
  411 
  412 static int
  413 fticket_wait_answer(struct fuse_ticket *ftick)
  414 {
  415         struct thread *td = curthread;
  416         sigset_t blockedset, oldset;
  417         int err = 0, stops_deferred;
  418         struct fuse_data *data = ftick->tk_data;
  419         bool interrupted = false;
  420 
  421         if (fsess_isimpl(ftick->tk_data->mp, FUSE_INTERRUPT) &&
  422             data->dataflags & FSESS_INTR) {
  423                 SIGEMPTYSET(blockedset);
  424         } else {
  425                 /* Block all signals except (implicitly) SIGKILL */
  426                 SIGFILLSET(blockedset);
  427         }
  428         stops_deferred = sigdeferstop(SIGDEFERSTOP_SILENT);
  429         kern_sigprocmask(td, SIG_BLOCK, NULL, &oldset, 0);
  430 
  431         fuse_lck_mtx_lock(ftick->tk_aw_mtx);
  432 
  433 retry:
  434         if (fticket_answered(ftick)) {
  435                 goto out;
  436         }
  437 
  438         if (fdata_get_dead(data)) {
  439                 err = ENOTCONN;
  440                 fticket_set_answered(ftick);
  441                 goto out;
  442         }
  443         kern_sigprocmask(td, SIG_BLOCK, &blockedset, NULL, 0);
  444         err = msleep(ftick, &ftick->tk_aw_mtx, PCATCH, "fu_ans",
  445             data->daemon_timeout * hz);
  446         kern_sigprocmask(td, SIG_SETMASK, &oldset, NULL, 0);
  447         if (err == EWOULDBLOCK) {
  448                 SDT_PROBE2(fusefs, , ipc, trace, 3,
  449                         "fticket_wait_answer: EWOULDBLOCK");
  450 #ifdef XXXIP                            /* die conditionally */
  451                 if (!fdata_get_dead(data)) {
  452                         fdata_set_dead(data);
  453                 }
  454 #endif
  455                 err = ETIMEDOUT;
  456                 fticket_set_answered(ftick);
  457         } else if ((err == EINTR || err == ERESTART)) {
  458                 /*
  459                  * Whether we get EINTR or ERESTART depends on whether
  460                  * SA_RESTART was set by sigaction(2).
  461                  *
  462                  * Try to interrupt the operation and wait for an EINTR response
  463                  * to the original operation.  If the file system does not
  464                  * support FUSE_INTERRUPT, then we'll just wait for it to
  465                  * complete like normal.  If it does support FUSE_INTERRUPT,
  466                  * then it will either respond EINTR to the original operation,
  467                  * or EAGAIN to the interrupt.
  468                  */
  469                 sigset_t tmpset;
  470 
  471                 SDT_PROBE2(fusefs, , ipc, trace, 4,
  472                         "fticket_wait_answer: interrupt");
  473                 fuse_lck_mtx_unlock(ftick->tk_aw_mtx);
  474                 fuse_interrupt_send(ftick, err);
  475 
  476                 PROC_LOCK(td->td_proc);
  477                 mtx_lock(&td->td_proc->p_sigacts->ps_mtx);
  478                 tmpset = td->td_proc->p_siglist;
  479                 SIGSETOR(tmpset, td->td_siglist);
  480                 mtx_unlock(&td->td_proc->p_sigacts->ps_mtx);
  481                 PROC_UNLOCK(td->td_proc);
  482 
  483                 fuse_lck_mtx_lock(ftick->tk_aw_mtx);
  484                 if (!interrupted && !SIGISMEMBER(tmpset, SIGKILL)) { 
  485                         /* 
  486                          * Block all signals while we wait for an interrupt
  487                          * response.  The protocol doesn't discriminate between
  488                          * different signals.
  489                          */
  490                         SIGFILLSET(blockedset);
  491                         interrupted = true;
  492                         goto retry;
  493                 } else {
  494                         /*
  495                          * Return immediately for fatal signals, or if this is
  496                          * the second interruption.  We should only be
  497                          * interrupted twice if the thread is stopped, for
  498                          * example during sigexit.
  499                          */
  500                 }
  501         } else if (err) {
  502                 SDT_PROBE2(fusefs, , ipc, trace, 6,
  503                         "fticket_wait_answer: other error");
  504         } else {
  505                 SDT_PROBE2(fusefs, , ipc, trace, 7, "fticket_wait_answer: OK");
  506         }
  507 out:
  508         if (!(err || fticket_answered(ftick))) {
  509                 SDT_PROBE2(fusefs, , ipc, trace, 1,
  510                         "FUSE: requester was woken up but still no answer");
  511                 err = ENXIO;
  512         }
  513         fuse_lck_mtx_unlock(ftick->tk_aw_mtx);
  514         sigallowstop(stops_deferred);
  515 
  516         return err;
  517 }
  518 
  519 static  inline
  520 int
  521 fticket_aw_pull_uio(struct fuse_ticket *ftick, struct uio *uio)
  522 {
  523         int err = 0;
  524         size_t len = uio_resid(uio);
  525 
  526         if (len) {
  527                 fiov_adjust(fticket_resp(ftick), len);
  528                 err = uiomove(fticket_resp(ftick)->base, len, uio);
  529         }
  530         return err;
  531 }
  532 
  533 int
  534 fticket_pull(struct fuse_ticket *ftick, struct uio *uio)
  535 {
  536         int err = 0;
  537 
  538         if (ftick->tk_aw_ohead.error) {
  539                 return 0;
  540         }
  541         err = fuse_body_audit(ftick, uio_resid(uio));
  542         if (!err) {
  543                 err = fticket_aw_pull_uio(ftick, uio);
  544         }
  545         return err;
  546 }
  547 
  548 struct fuse_data *
  549 fdata_alloc(struct cdev *fdev, struct ucred *cred)
  550 {
  551         struct fuse_data *data;
  552 
  553         data = malloc(sizeof(struct fuse_data), M_FUSEMSG, M_WAITOK | M_ZERO);
  554 
  555         data->fdev = fdev;
  556         mtx_init(&data->ms_mtx, "fuse message list mutex", NULL, MTX_DEF);
  557         STAILQ_INIT(&data->ms_head);
  558         data->ms_count = 0;
  559         knlist_init_mtx(&data->ks_rsel.si_note, &data->ms_mtx);
  560         mtx_init(&data->aw_mtx, "fuse answer list mutex", NULL, MTX_DEF);
  561         TAILQ_INIT(&data->aw_head);
  562         data->daemoncred = crhold(cred);
  563         data->daemon_timeout = FUSE_DEFAULT_DAEMON_TIMEOUT;
  564         sx_init(&data->rename_lock, "fuse rename lock");
  565         data->ref = 1;
  566 
  567         return data;
  568 }
  569 
  570 void
  571 fdata_trydestroy(struct fuse_data *data)
  572 {
  573         data->ref--;
  574         MPASS(data->ref >= 0);
  575         if (data->ref != 0)
  576                 return;
  577 
  578         /* Driving off stage all that stuff thrown at device... */
  579         sx_destroy(&data->rename_lock);
  580         crfree(data->daemoncred);
  581         mtx_destroy(&data->aw_mtx);
  582         knlist_delete(&data->ks_rsel.si_note, curthread, 0);
  583         knlist_destroy(&data->ks_rsel.si_note);
  584         mtx_destroy(&data->ms_mtx);
  585 
  586         free(data, M_FUSEMSG);
  587 }
  588 
  589 void
  590 fdata_set_dead(struct fuse_data *data)
  591 {
  592         FUSE_LOCK();
  593         if (fdata_get_dead(data)) {
  594                 FUSE_UNLOCK();
  595                 return;
  596         }
  597         fuse_lck_mtx_lock(data->ms_mtx);
  598         data->dataflags |= FSESS_DEAD;
  599         wakeup_one(data);
  600         selwakeuppri(&data->ks_rsel, PZERO + 1);
  601         wakeup(&data->ticketer);
  602         fuse_lck_mtx_unlock(data->ms_mtx);
  603         FUSE_UNLOCK();
  604 }
  605 
  606 struct fuse_ticket *
  607 fuse_ticket_fetch(struct fuse_data *data)
  608 {
  609         int err = 0;
  610         struct fuse_ticket *ftick;
  611 
  612         ftick = fticket_alloc(data);
  613 
  614         if (!(data->dataflags & FSESS_INITED)) {
  615                 /* Sleep until get answer for INIT messsage */
  616                 FUSE_LOCK();
  617                 if (!(data->dataflags & FSESS_INITED) && data->ticketer > 2) {
  618                         err = msleep(&data->ticketer, &fuse_mtx, PCATCH | PDROP,
  619                             "fu_ini", 0);
  620                         if (err)
  621                                 fdata_set_dead(data);
  622                 } else
  623                         FUSE_UNLOCK();
  624         }
  625         return ftick;
  626 }
  627 
  628 int
  629 fuse_ticket_drop(struct fuse_ticket *ftick)
  630 {
  631         int die;
  632 
  633         die = refcount_release(&ftick->tk_refcount);
  634         if (die)
  635                 fticket_destroy(ftick);
  636 
  637         return die;
  638 }
  639 
  640 void
  641 fuse_insert_callback(struct fuse_ticket *ftick, fuse_handler_t * handler)
  642 {
  643         if (fdata_get_dead(ftick->tk_data)) {
  644                 return;
  645         }
  646         ftick->tk_aw_handler = handler;
  647 
  648         fuse_lck_mtx_lock(ftick->tk_data->aw_mtx);
  649         fuse_aw_push(ftick);
  650         fuse_lck_mtx_unlock(ftick->tk_data->aw_mtx);
  651 }
  652 
  653 /*
  654  * Insert a new upgoing ticket into the message queue
  655  *
  656  * If urgent is true, insert at the front of the queue.  Otherwise, insert in
  657  * FIFO order.
  658  */
  659 void
  660 fuse_insert_message(struct fuse_ticket *ftick, bool urgent)
  661 {
  662         if (ftick->tk_flag & FT_DIRTY) {
  663                 panic("FUSE: ticket reused without being refreshed");
  664         }
  665         ftick->tk_flag |= FT_DIRTY;
  666 
  667         if (fdata_get_dead(ftick->tk_data)) {
  668                 return;
  669         }
  670         fuse_lck_mtx_lock(ftick->tk_data->ms_mtx);
  671         if (urgent)
  672                 fuse_ms_push_head(ftick);
  673         else
  674                 fuse_ms_push(ftick);
  675         wakeup_one(ftick->tk_data);
  676         selwakeuppri(&ftick->tk_data->ks_rsel, PZERO + 1);
  677         KNOTE_LOCKED(&ftick->tk_data->ks_rsel.si_note, 0);
  678         fuse_lck_mtx_unlock(ftick->tk_data->ms_mtx);
  679 }
  680 
  681 static int
  682 fuse_body_audit(struct fuse_ticket *ftick, size_t blen)
  683 {
  684         int err = 0;
  685         enum fuse_opcode opcode;
  686 
  687         opcode = fticket_opcode(ftick);
  688 
  689         switch (opcode) {
  690         case FUSE_BMAP:
  691                 err = (blen == sizeof(struct fuse_bmap_out)) ? 0 : EINVAL;
  692                 break;
  693 
  694         case FUSE_LINK:
  695         case FUSE_LOOKUP:
  696         case FUSE_MKDIR:
  697         case FUSE_MKNOD:
  698         case FUSE_SYMLINK:
  699                 if (fuse_libabi_geq(ftick->tk_data, 7, 9)) {
  700                         err = (blen == sizeof(struct fuse_entry_out)) ?
  701                                 0 : EINVAL;
  702                 } else {
  703                         err = (blen == FUSE_COMPAT_ENTRY_OUT_SIZE) ? 0 : EINVAL;
  704                 }
  705                 break;
  706 
  707         case FUSE_FORGET:
  708                 panic("FUSE: a handler has been intalled for FUSE_FORGET");
  709                 break;
  710 
  711         case FUSE_GETATTR:
  712         case FUSE_SETATTR:
  713                 if (fuse_libabi_geq(ftick->tk_data, 7, 9)) {
  714                         err = (blen == sizeof(struct fuse_attr_out)) ? 
  715                           0 : EINVAL;
  716                 } else {
  717                         err = (blen == FUSE_COMPAT_ATTR_OUT_SIZE) ? 0 : EINVAL;
  718                 }
  719                 break;
  720 
  721         case FUSE_READLINK:
  722                 err = (PAGE_SIZE >= blen) ? 0 : EINVAL;
  723                 break;
  724 
  725         case FUSE_UNLINK:
  726                 err = (blen == 0) ? 0 : EINVAL;
  727                 break;
  728 
  729         case FUSE_RMDIR:
  730                 err = (blen == 0) ? 0 : EINVAL;
  731                 break;
  732 
  733         case FUSE_RENAME:
  734                 err = (blen == 0) ? 0 : EINVAL;
  735                 break;
  736 
  737         case FUSE_OPEN:
  738                 err = (blen == sizeof(struct fuse_open_out)) ? 0 : EINVAL;
  739                 break;
  740 
  741         case FUSE_READ:
  742                 err = (((struct fuse_read_in *)(
  743                     (char *)ftick->tk_ms_fiov.base +
  744                     sizeof(struct fuse_in_header)
  745                     ))->size >= blen) ? 0 : EINVAL;
  746                 break;
  747 
  748         case FUSE_WRITE:
  749                 err = (blen == sizeof(struct fuse_write_out)) ? 0 : EINVAL;
  750                 break;
  751 
  752         case FUSE_STATFS:
  753                 if (fuse_libabi_geq(ftick->tk_data, 7, 4)) {
  754                         err = (blen == sizeof(struct fuse_statfs_out)) ? 
  755                           0 : EINVAL;
  756                 } else {
  757                         err = (blen == FUSE_COMPAT_STATFS_SIZE) ? 0 : EINVAL;
  758                 }
  759                 break;
  760 
  761         case FUSE_RELEASE:
  762                 err = (blen == 0) ? 0 : EINVAL;
  763                 break;
  764 
  765         case FUSE_FSYNC:
  766                 err = (blen == 0) ? 0 : EINVAL;
  767                 break;
  768 
  769         case FUSE_SETXATTR:
  770                 err = (blen == 0) ? 0 : EINVAL;
  771                 break;
  772 
  773         case FUSE_GETXATTR:
  774         case FUSE_LISTXATTR:
  775                 /*
  776                  * These can have varying response lengths, and 0 length
  777                  * isn't necessarily invalid.
  778                  */
  779                 err = 0;
  780                 break;
  781 
  782         case FUSE_REMOVEXATTR:
  783                 err = (blen == 0) ? 0 : EINVAL;
  784                 break;
  785 
  786         case FUSE_FLUSH:
  787                 err = (blen == 0) ? 0 : EINVAL;
  788                 break;
  789 
  790         case FUSE_INIT:
  791                 if (blen == sizeof(struct fuse_init_out) ||
  792                     blen == FUSE_COMPAT_INIT_OUT_SIZE ||
  793                     blen == FUSE_COMPAT_22_INIT_OUT_SIZE) {
  794                         err = 0;
  795                 } else {
  796                         err = EINVAL;
  797                 }
  798                 break;
  799 
  800         case FUSE_OPENDIR:
  801                 err = (blen == sizeof(struct fuse_open_out)) ? 0 : EINVAL;
  802                 break;
  803 
  804         case FUSE_READDIR:
  805                 err = (((struct fuse_read_in *)(
  806                     (char *)ftick->tk_ms_fiov.base +
  807                     sizeof(struct fuse_in_header)
  808                     ))->size >= blen) ? 0 : EINVAL;
  809                 break;
  810 
  811         case FUSE_RELEASEDIR:
  812                 err = (blen == 0) ? 0 : EINVAL;
  813                 break;
  814 
  815         case FUSE_FSYNCDIR:
  816                 err = (blen == 0) ? 0 : EINVAL;
  817                 break;
  818 
  819         case FUSE_GETLK:
  820                 err = (blen == sizeof(struct fuse_lk_out)) ? 0 : EINVAL;
  821                 break;
  822 
  823         case FUSE_SETLK:
  824                 err = (blen == 0) ? 0 : EINVAL;
  825                 break;
  826 
  827         case FUSE_SETLKW:
  828                 err = (blen == 0) ? 0 : EINVAL;
  829                 break;
  830 
  831         case FUSE_ACCESS:
  832                 err = (blen == 0) ? 0 : EINVAL;
  833                 break;
  834 
  835         case FUSE_CREATE:
  836                 if (fuse_libabi_geq(ftick->tk_data, 7, 9)) {
  837                         err = (blen == sizeof(struct fuse_entry_out) +
  838                             sizeof(struct fuse_open_out)) ? 0 : EINVAL;
  839                 } else {
  840                         err = (blen == FUSE_COMPAT_ENTRY_OUT_SIZE +
  841                             sizeof(struct fuse_open_out)) ? 0 : EINVAL;
  842                 }
  843                 break;
  844 
  845         case FUSE_DESTROY:
  846                 err = (blen == 0) ? 0 : EINVAL;
  847                 break;
  848 
  849         default:
  850                 panic("FUSE: opcodes out of sync (%d)\n", opcode);
  851         }
  852 
  853         return err;
  854 }
  855 
  856 static inline void
  857 fuse_setup_ihead(struct fuse_in_header *ihead, struct fuse_ticket *ftick,
  858     uint64_t nid, enum fuse_opcode op, size_t blen, pid_t pid,
  859     struct ucred *cred)
  860 {
  861         ihead->len = sizeof(*ihead) + blen;
  862         ihead->unique = ftick->tk_unique;
  863         ihead->nodeid = nid;
  864         ihead->opcode = op;
  865 
  866         ihead->pid = pid;
  867         ihead->uid = cred->cr_uid;
  868         ihead->gid = cred->cr_groups[0];
  869 }
  870 
  871 /*
  872  * fuse_standard_handler just pulls indata and wakes up pretender.
  873  * Doesn't try to interpret data, that's left for the pretender.
  874  * Though might do a basic size verification before the pull-in takes place
  875  */
  876 
  877 static int
  878 fuse_standard_handler(struct fuse_ticket *ftick, struct uio *uio)
  879 {
  880         int err = 0;
  881 
  882         err = fticket_pull(ftick, uio);
  883 
  884         fuse_lck_mtx_lock(ftick->tk_aw_mtx);
  885 
  886         if (!fticket_answered(ftick)) {
  887                 fticket_set_answered(ftick);
  888                 ftick->tk_aw_errno = err;
  889                 wakeup(ftick);
  890         }
  891         fuse_lck_mtx_unlock(ftick->tk_aw_mtx);
  892 
  893         return err;
  894 }
  895 
  896 /*
  897  * Reinitialize a dispatcher from a pid and node id, without resizing or
  898  * clearing its data buffers
  899  */
  900 static void
  901 fdisp_refresh_pid(struct fuse_dispatcher *fdip, enum fuse_opcode op,
  902     struct mount *mp, uint64_t nid, pid_t pid, struct ucred *cred)
  903 {
  904         MPASS(fdip->tick);
  905         MPASS2(sizeof(fdip->finh) + fdip->iosize <= fdip->tick->tk_ms_fiov.len,
  906                 "Must use fdisp_make_pid to increase the size of the fiov");
  907         fticket_reset(fdip->tick);
  908 
  909         FUSE_DIMALLOC(&fdip->tick->tk_ms_fiov, fdip->finh,
  910             fdip->indata, fdip->iosize);
  911 
  912         fuse_setup_ihead(fdip->finh, fdip->tick, nid, op, fdip->iosize, pid,
  913                 cred);
  914 }
  915 
  916 /* Initialize a dispatcher from a pid and node id */
  917 static void
  918 fdisp_make_pid(struct fuse_dispatcher *fdip, enum fuse_opcode op,
  919     struct fuse_data *data, uint64_t nid, pid_t pid, struct ucred *cred)
  920 {
  921         if (fdip->tick) {
  922                 fticket_refresh(fdip->tick);
  923         } else {
  924                 fdip->tick = fuse_ticket_fetch(data);
  925         }
  926 
  927         /* FUSE_DIMALLOC will bzero the fiovs when it enlarges them */
  928         FUSE_DIMALLOC(&fdip->tick->tk_ms_fiov, fdip->finh,
  929             fdip->indata, fdip->iosize);
  930 
  931         fuse_setup_ihead(fdip->finh, fdip->tick, nid, op, fdip->iosize, pid, cred);
  932 }
  933 
  934 void
  935 fdisp_make(struct fuse_dispatcher *fdip, enum fuse_opcode op, struct mount *mp,
  936     uint64_t nid, struct thread *td, struct ucred *cred)
  937 {
  938         struct fuse_data *data = fuse_get_mpdata(mp);
  939         RECTIFY_TDCR(td, cred);
  940 
  941         return fdisp_make_pid(fdip, op, data, nid, td->td_proc->p_pid, cred);
  942 }
  943 
  944 void
  945 fdisp_make_vp(struct fuse_dispatcher *fdip, enum fuse_opcode op,
  946     struct vnode *vp, struct thread *td, struct ucred *cred)
  947 {
  948         struct mount *mp = vnode_mount(vp);
  949         struct fuse_data *data = fuse_get_mpdata(mp);
  950 
  951         RECTIFY_TDCR(td, cred);
  952         return fdisp_make_pid(fdip, op, data, VTOI(vp),
  953             td->td_proc->p_pid, cred);
  954 }
  955 
  956 /* Refresh a fuse_dispatcher so it can be reused, but don't zero its data */
  957 void
  958 fdisp_refresh_vp(struct fuse_dispatcher *fdip, enum fuse_opcode op,
  959     struct vnode *vp, struct thread *td, struct ucred *cred)
  960 {
  961         RECTIFY_TDCR(td, cred);
  962         return fdisp_refresh_pid(fdip, op, vnode_mount(vp), VTOI(vp),
  963             td->td_proc->p_pid, cred);
  964 }
  965 
  966 SDT_PROBE_DEFINE2(fusefs, , ipc, fdisp_wait_answ_error, "char*", "int");
  967 
  968 int
  969 fdisp_wait_answ(struct fuse_dispatcher *fdip)
  970 {
  971         int err = 0;
  972 
  973         fdip->answ_stat = 0;
  974         fuse_insert_callback(fdip->tick, fuse_standard_handler);
  975         fuse_insert_message(fdip->tick, false);
  976 
  977         if ((err = fticket_wait_answer(fdip->tick))) {
  978                 fuse_lck_mtx_lock(fdip->tick->tk_aw_mtx);
  979 
  980                 if (fticket_answered(fdip->tick)) {
  981                         /*
  982                          * Just between noticing the interrupt and getting here,
  983                          * the standard handler has completed his job.
  984                          * So we drop the ticket and exit as usual.
  985                          */
  986                         SDT_PROBE2(fusefs, , ipc, fdisp_wait_answ_error,
  987                                 "IPC: interrupted, already answered", err);
  988                         fuse_lck_mtx_unlock(fdip->tick->tk_aw_mtx);
  989                         goto out;
  990                 } else {
  991                         /*
  992                          * So we were faster than the standard handler.
  993                          * Then by setting the answered flag we get *him*
  994                          * to drop the ticket.
  995                          */
  996                         SDT_PROBE2(fusefs, , ipc, fdisp_wait_answ_error,
  997                                 "IPC: interrupted, setting to answered", err);
  998                         fticket_set_answered(fdip->tick);
  999                         fuse_lck_mtx_unlock(fdip->tick->tk_aw_mtx);
 1000                         return err;
 1001                 }
 1002         }
 1003 
 1004         if (fdip->tick->tk_aw_errno == ENOTCONN) {
 1005                 /* The daemon died while we were waiting for a response */
 1006                 err = ENOTCONN;
 1007                 goto out;
 1008         } else if (fdip->tick->tk_aw_errno) {
 1009                 /* 
 1010                  * There was some sort of communication error with the daemon
 1011                  * that the client wouldn't understand.
 1012                  */
 1013                 SDT_PROBE2(fusefs, , ipc, fdisp_wait_answ_error,
 1014                         "IPC: explicit EIO-ing", fdip->tick->tk_aw_errno);
 1015                 err = EIO;
 1016                 goto out;
 1017         }
 1018         if ((err = fdip->tick->tk_aw_ohead.error)) {
 1019                 SDT_PROBE2(fusefs, , ipc, fdisp_wait_answ_error,
 1020                         "IPC: setting status", fdip->tick->tk_aw_ohead.error);
 1021                 /*
 1022                  * This means a "proper" fuse syscall error.
 1023                  * We record this value so the caller will
 1024                  * be able to know it's not a boring messaging
 1025                  * failure, if she wishes so (and if not, she can
 1026                  * just simply propagate the return value of this routine).
 1027                  * [XXX Maybe a bitflag would do the job too,
 1028                  * if other flags needed, this will be converted thusly.]
 1029                  */
 1030                 fdip->answ_stat = err;
 1031                 goto out;
 1032         }
 1033         fdip->answ = fticket_resp(fdip->tick)->base;
 1034         fdip->iosize = fticket_resp(fdip->tick)->len;
 1035 
 1036         return 0;
 1037 
 1038 out:
 1039         return err;
 1040 }
 1041 
 1042 void
 1043 fuse_ipc_init(void)
 1044 {
 1045         ticket_zone = uma_zcreate("fuse_ticket", sizeof(struct fuse_ticket),
 1046             fticket_ctor, fticket_dtor, fticket_init, fticket_fini,
 1047             UMA_ALIGN_PTR, 0);
 1048         fuse_ticket_count = counter_u64_alloc(M_WAITOK);
 1049 }
 1050 
 1051 void
 1052 fuse_ipc_destroy(void)
 1053 {
 1054         counter_u64_free(fuse_ticket_count);
 1055         uma_zdestroy(ticket_zone);
 1056 }
 1057 
 1058 SDT_PROBE_DEFINE3(fusefs,, ipc, warn, "struct fuse_data*", "unsigned", "char*");
 1059 void
 1060 fuse_warn(struct fuse_data *data, unsigned flag, const char *msg)
 1061 {
 1062         SDT_PROBE3(fusefs, , ipc, warn, data, flag, msg);
 1063         if (!(data->dataflags & flag)) {
 1064                 printf("WARNING: FUSE protocol violation for server mounted at "
 1065                     "%s: %s  "
 1066                     "This warning will not be repeated.\n",
 1067                     data->mp->mnt_stat.f_mntonname, msg);
 1068                 data->dataflags |= flag;
 1069         }
 1070 }

Cache object: a8383cdc802223dcd72533c48791192c


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