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

Cache object: 8fa7b1959f504f7a04445d526f44a999


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