151369649SPedro F. Giffuni /*-
251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni *
45fe58019SAttilio Rao * Copyright (c) 2007-2009 Google Inc.
55fe58019SAttilio Rao * All rights reserved.
65fe58019SAttilio Rao *
75fe58019SAttilio Rao * Redistribution and use in source and binary forms, with or without
85fe58019SAttilio Rao * modification, are permitted provided that the following conditions are
95fe58019SAttilio Rao * met:
105fe58019SAttilio Rao *
115fe58019SAttilio Rao * * Redistributions of source code must retain the above copyright
125fe58019SAttilio Rao * notice, this list of conditions and the following disclaimer.
135fe58019SAttilio Rao * * Redistributions in binary form must reproduce the above
145fe58019SAttilio Rao * copyright notice, this list of conditions and the following disclaimer
155fe58019SAttilio Rao * in the documentation and/or other materials provided with the
165fe58019SAttilio Rao * distribution.
175fe58019SAttilio Rao * * Neither the name of Google Inc. nor the names of its
185fe58019SAttilio Rao * contributors may be used to endorse or promote products derived from
195fe58019SAttilio Rao * this software without specific prior written permission.
205fe58019SAttilio Rao *
215fe58019SAttilio Rao * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
225fe58019SAttilio Rao * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
235fe58019SAttilio Rao * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
245fe58019SAttilio Rao * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
255fe58019SAttilio Rao * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
265fe58019SAttilio Rao * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
275fe58019SAttilio Rao * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
285fe58019SAttilio Rao * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
295fe58019SAttilio Rao * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
305fe58019SAttilio Rao * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
315fe58019SAttilio Rao * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
325fe58019SAttilio Rao *
335fe58019SAttilio Rao * Copyright (C) 2005 Csaba Henk.
345fe58019SAttilio Rao * All rights reserved.
355fe58019SAttilio Rao *
368aafc8c3SAlan Somers * Copyright (c) 2019 The FreeBSD Foundation
378aafc8c3SAlan Somers *
388aafc8c3SAlan Somers * Portions of this software were developed by BFF Storage Systems, LLC under
398aafc8c3SAlan Somers * sponsorship from the FreeBSD Foundation.
408aafc8c3SAlan Somers *
415fe58019SAttilio Rao * Redistribution and use in source and binary forms, with or without
425fe58019SAttilio Rao * modification, are permitted provided that the following conditions
435fe58019SAttilio Rao * are met:
445fe58019SAttilio Rao * 1. Redistributions of source code must retain the above copyright
455fe58019SAttilio Rao * notice, this list of conditions and the following disclaimer.
465fe58019SAttilio Rao * 2. Redistributions in binary form must reproduce the above copyright
475fe58019SAttilio Rao * notice, this list of conditions and the following disclaimer in the
485fe58019SAttilio Rao * documentation and/or other materials provided with the distribution.
495fe58019SAttilio Rao *
505fe58019SAttilio Rao * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
515fe58019SAttilio Rao * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
525fe58019SAttilio Rao * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
535fe58019SAttilio Rao * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
545fe58019SAttilio Rao * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
555fe58019SAttilio Rao * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
565fe58019SAttilio Rao * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
575fe58019SAttilio Rao * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
585fe58019SAttilio Rao * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
595fe58019SAttilio Rao * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
605fe58019SAttilio Rao * SUCH DAMAGE.
615fe58019SAttilio Rao */
625fe58019SAttilio Rao
635fe58019SAttilio Rao #include <sys/types.h>
64df38ada2SBjoern A. Zeeb #include <sys/param.h>
655fe58019SAttilio Rao #include <sys/module.h>
665fe58019SAttilio Rao #include <sys/systm.h>
675fe58019SAttilio Rao #include <sys/errno.h>
685fe58019SAttilio Rao #include <sys/param.h>
695fe58019SAttilio Rao #include <sys/kernel.h>
705fe58019SAttilio Rao #include <sys/conf.h>
715fe58019SAttilio Rao #include <sys/uio.h>
725fe58019SAttilio Rao #include <sys/malloc.h>
735fe58019SAttilio Rao #include <sys/queue.h>
745fe58019SAttilio Rao #include <sys/lock.h>
755fe58019SAttilio Rao #include <sys/sx.h>
765fe58019SAttilio Rao #include <sys/mutex.h>
775fe58019SAttilio Rao #include <sys/proc.h>
785fe58019SAttilio Rao #include <sys/mount.h>
79cf169498SAlan Somers #include <sys/sdt.h>
805fe58019SAttilio Rao #include <sys/stat.h>
815fe58019SAttilio Rao #include <sys/fcntl.h>
825fe58019SAttilio Rao #include <sys/sysctl.h>
835fe58019SAttilio Rao #include <sys/poll.h>
845fe58019SAttilio Rao #include <sys/selinfo.h>
855fe58019SAttilio Rao
865fe58019SAttilio Rao #include "fuse.h"
87c2d70d6eSAlan Somers #include "fuse_internal.h"
885fe58019SAttilio Rao #include "fuse_ipc.h"
895fe58019SAttilio Rao
90e3b1c847SEdward Tomasz Napierala #include <compat/linux/linux_errno.h>
91e3b1c847SEdward Tomasz Napierala #include <compat/linux/linux_errno.inc>
92e3b1c847SEdward Tomasz Napierala
93419e7ff6SAlan Somers SDT_PROVIDER_DECLARE(fusefs);
94cf169498SAlan Somers /*
95cf169498SAlan Somers * Fuse trace probe:
96cf169498SAlan Somers * arg0: verbosity. Higher numbers give more verbose messages
97cf169498SAlan Somers * arg1: Textual message
98cf169498SAlan Somers */
99419e7ff6SAlan Somers SDT_PROBE_DEFINE2(fusefs, , device, trace, "int", "char*");
1005fe58019SAttilio Rao
1015fe58019SAttilio Rao static struct cdev *fuse_dev;
1025fe58019SAttilio Rao
1033429092cSAlan Somers static d_kqfilter_t fuse_device_filter;
1045fe58019SAttilio Rao static d_open_t fuse_device_open;
1055fe58019SAttilio Rao static d_poll_t fuse_device_poll;
1065fe58019SAttilio Rao static d_read_t fuse_device_read;
1075fe58019SAttilio Rao static d_write_t fuse_device_write;
1085fe58019SAttilio Rao
1095fe58019SAttilio Rao static struct cdevsw fuse_device_cdevsw = {
1103429092cSAlan Somers .d_kqfilter = fuse_device_filter,
1115fe58019SAttilio Rao .d_open = fuse_device_open,
1125fe58019SAttilio Rao .d_name = "fuse",
1135fe58019SAttilio Rao .d_poll = fuse_device_poll,
1145fe58019SAttilio Rao .d_read = fuse_device_read,
1155fe58019SAttilio Rao .d_write = fuse_device_write,
1165fe58019SAttilio Rao .d_version = D_VERSION,
1175fe58019SAttilio Rao };
1185fe58019SAttilio Rao
1193429092cSAlan Somers static int fuse_device_filt_read(struct knote *kn, long hint);
1207b8622faSAlan Somers static int fuse_device_filt_write(struct knote *kn, long hint);
1213429092cSAlan Somers static void fuse_device_filt_detach(struct knote *kn);
1223429092cSAlan Somers
123ef9ffb85SMark Johnston static const struct filterops fuse_device_rfiltops = {
1243429092cSAlan Somers .f_isfd = 1,
1253429092cSAlan Somers .f_detach = fuse_device_filt_detach,
1263429092cSAlan Somers .f_event = fuse_device_filt_read,
1273429092cSAlan Somers };
1283429092cSAlan Somers
129ef9ffb85SMark Johnston static const struct filterops fuse_device_wfiltops = {
1307b8622faSAlan Somers .f_isfd = 1,
1317b8622faSAlan Somers .f_event = fuse_device_filt_write,
1327b8622faSAlan Somers };
1337b8622faSAlan Somers
1345fe58019SAttilio Rao /****************************
1355fe58019SAttilio Rao *
1365fe58019SAttilio Rao * >>> Fuse device op defs
1375fe58019SAttilio Rao *
1385fe58019SAttilio Rao ****************************/
1395fe58019SAttilio Rao
1405fe58019SAttilio Rao static void
fdata_dtor(void * arg)1415fe58019SAttilio Rao fdata_dtor(void *arg)
1425fe58019SAttilio Rao {
1435fe58019SAttilio Rao struct fuse_data *fdata;
1448b73a4c5SAlan Somers struct fuse_ticket *tick;
1455fe58019SAttilio Rao
1465fe58019SAttilio Rao fdata = arg;
1478b73a4c5SAlan Somers if (fdata == NULL)
1488b73a4c5SAlan Somers return;
1498b73a4c5SAlan Somers
1508b73a4c5SAlan Somers fdata_set_dead(fdata);
1518b73a4c5SAlan Somers
1528b73a4c5SAlan Somers FUSE_LOCK();
1538b73a4c5SAlan Somers fuse_lck_mtx_lock(fdata->aw_mtx);
1548b73a4c5SAlan Somers /* wakup poll()ers */
1558b73a4c5SAlan Somers selwakeuppri(&fdata->ks_rsel, PZERO + 1);
1568b73a4c5SAlan Somers /* Don't let syscall handlers wait in vain */
1578b73a4c5SAlan Somers while ((tick = fuse_aw_pop(fdata))) {
1588b73a4c5SAlan Somers fuse_lck_mtx_lock(tick->tk_aw_mtx);
1598b73a4c5SAlan Somers fticket_set_answered(tick);
1608b73a4c5SAlan Somers tick->tk_aw_errno = ENOTCONN;
1618b73a4c5SAlan Somers wakeup(tick);
1628b73a4c5SAlan Somers fuse_lck_mtx_unlock(tick->tk_aw_mtx);
1638b73a4c5SAlan Somers FUSE_ASSERT_AW_DONE(tick);
1648b73a4c5SAlan Somers fuse_ticket_drop(tick);
1658b73a4c5SAlan Somers }
1668b73a4c5SAlan Somers fuse_lck_mtx_unlock(fdata->aw_mtx);
1677e1f5432SAlan Somers
1687e1f5432SAlan Somers /* Cleanup unsent operations */
1697e1f5432SAlan Somers fuse_lck_mtx_lock(fdata->ms_mtx);
1707e1f5432SAlan Somers while ((tick = fuse_ms_pop(fdata))) {
1717e1f5432SAlan Somers fuse_ticket_drop(tick);
1727e1f5432SAlan Somers }
1737e1f5432SAlan Somers fuse_lck_mtx_unlock(fdata->ms_mtx);
1748b73a4c5SAlan Somers FUSE_UNLOCK();
1758b73a4c5SAlan Somers
1765fe58019SAttilio Rao fdata_trydestroy(fdata);
1775fe58019SAttilio Rao }
1785fe58019SAttilio Rao
1793429092cSAlan Somers static int
fuse_device_filter(struct cdev * dev,struct knote * kn)1803429092cSAlan Somers fuse_device_filter(struct cdev *dev, struct knote *kn)
1813429092cSAlan Somers {
1823429092cSAlan Somers struct fuse_data *data;
1833429092cSAlan Somers int error;
1843429092cSAlan Somers
1853429092cSAlan Somers error = devfs_get_cdevpriv((void **)&data);
1863429092cSAlan Somers
1873429092cSAlan Somers if (error == 0 && kn->kn_filter == EVFILT_READ) {
1883429092cSAlan Somers kn->kn_fop = &fuse_device_rfiltops;
1893429092cSAlan Somers kn->kn_hook = data;
1903429092cSAlan Somers knlist_add(&data->ks_rsel.si_note, kn, 0);
1913429092cSAlan Somers error = 0;
1927b8622faSAlan Somers } else if (error == 0 && kn->kn_filter == EVFILT_WRITE) {
1937b8622faSAlan Somers kn->kn_fop = &fuse_device_wfiltops;
1947b8622faSAlan Somers error = 0;
1953429092cSAlan Somers } else if (error == 0) {
1963429092cSAlan Somers error = EINVAL;
1973429092cSAlan Somers kn->kn_data = error;
1983429092cSAlan Somers }
1993429092cSAlan Somers
2003429092cSAlan Somers return (error);
2013429092cSAlan Somers }
2023429092cSAlan Somers
2033429092cSAlan Somers static void
fuse_device_filt_detach(struct knote * kn)2043429092cSAlan Somers fuse_device_filt_detach(struct knote *kn)
2053429092cSAlan Somers {
2063429092cSAlan Somers struct fuse_data *data;
2073429092cSAlan Somers
2083429092cSAlan Somers data = (struct fuse_data*)kn->kn_hook;
2093429092cSAlan Somers MPASS(data != NULL);
2103429092cSAlan Somers knlist_remove(&data->ks_rsel.si_note, kn, 0);
2113429092cSAlan Somers kn->kn_hook = NULL;
2123429092cSAlan Somers }
2133429092cSAlan Somers
2143429092cSAlan Somers static int
fuse_device_filt_read(struct knote * kn,long hint)2153429092cSAlan Somers fuse_device_filt_read(struct knote *kn, long hint)
2163429092cSAlan Somers {
2173429092cSAlan Somers struct fuse_data *data;
2183429092cSAlan Somers int ready;
2193429092cSAlan Somers
2203429092cSAlan Somers data = (struct fuse_data*)kn->kn_hook;
2213429092cSAlan Somers MPASS(data != NULL);
2223429092cSAlan Somers
2233429092cSAlan Somers mtx_assert(&data->ms_mtx, MA_OWNED);
2243429092cSAlan Somers if (fdata_get_dead(data)) {
2253429092cSAlan Somers kn->kn_flags |= EV_EOF;
2263429092cSAlan Somers kn->kn_fflags = ENODEV;
2273429092cSAlan Somers kn->kn_data = 1;
2283429092cSAlan Somers ready = 1;
2293429092cSAlan Somers } else if (STAILQ_FIRST(&data->ms_head)) {
2300a7c63e0SAlan Somers MPASS(data->ms_count >= 1);
2310a7c63e0SAlan Somers kn->kn_data = data->ms_count;
2323429092cSAlan Somers ready = 1;
2333429092cSAlan Somers } else {
2343429092cSAlan Somers ready = 0;
2353429092cSAlan Somers }
2363429092cSAlan Somers
2373429092cSAlan Somers return (ready);
2383429092cSAlan Somers }
2393429092cSAlan Somers
2407b8622faSAlan Somers static int
fuse_device_filt_write(struct knote * kn,long hint)2417b8622faSAlan Somers fuse_device_filt_write(struct knote *kn, long hint)
2427b8622faSAlan Somers {
2437b8622faSAlan Somers
2447b8622faSAlan Somers kn->kn_data = 0;
2457b8622faSAlan Somers
2469b876fbdSgAlfonso-bit /* The device is always ready to write, so we return 1*/
2479b876fbdSgAlfonso-bit return (1);
2487b8622faSAlan Somers }
2497b8622faSAlan Somers
2505fe58019SAttilio Rao /*
2515fe58019SAttilio Rao * Resources are set up on a per-open basis
2525fe58019SAttilio Rao */
2535fe58019SAttilio Rao static int
fuse_device_open(struct cdev * dev,int oflags,int devtype,struct thread * td)2545fe58019SAttilio Rao fuse_device_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
2555fe58019SAttilio Rao {
2565fe58019SAttilio Rao struct fuse_data *fdata;
2575fe58019SAttilio Rao int error;
2585fe58019SAttilio Rao
259419e7ff6SAlan Somers SDT_PROBE2(fusefs, , device, trace, 1, "device open");
2605fe58019SAttilio Rao
2615fe58019SAttilio Rao fdata = fdata_alloc(dev, td->td_ucred);
2625fe58019SAttilio Rao error = devfs_set_cdevpriv(fdata, fdata_dtor);
2635fe58019SAttilio Rao if (error != 0)
2645fe58019SAttilio Rao fdata_trydestroy(fdata);
2655fe58019SAttilio Rao else
266419e7ff6SAlan Somers SDT_PROBE2(fusefs, , device, trace, 1, "device open success");
2675fe58019SAttilio Rao return (error);
2685fe58019SAttilio Rao }
2695fe58019SAttilio Rao
2705fe58019SAttilio Rao int
fuse_device_poll(struct cdev * dev,int events,struct thread * td)2715fe58019SAttilio Rao fuse_device_poll(struct cdev *dev, int events, struct thread *td)
2725fe58019SAttilio Rao {
2735fe58019SAttilio Rao struct fuse_data *data;
2745fe58019SAttilio Rao int error, revents = 0;
2755fe58019SAttilio Rao
2765fe58019SAttilio Rao error = devfs_get_cdevpriv((void **)&data);
2775fe58019SAttilio Rao if (error != 0)
2785fe58019SAttilio Rao return (events &
2795fe58019SAttilio Rao (POLLHUP|POLLIN|POLLRDNORM|POLLOUT|POLLWRNORM));
2805fe58019SAttilio Rao
2815fe58019SAttilio Rao if (events & (POLLIN | POLLRDNORM)) {
2825fe58019SAttilio Rao fuse_lck_mtx_lock(data->ms_mtx);
2835fe58019SAttilio Rao if (fdata_get_dead(data) || STAILQ_FIRST(&data->ms_head))
2845fe58019SAttilio Rao revents |= events & (POLLIN | POLLRDNORM);
2855fe58019SAttilio Rao else
2865fe58019SAttilio Rao selrecord(td, &data->ks_rsel);
2875fe58019SAttilio Rao fuse_lck_mtx_unlock(data->ms_mtx);
2885fe58019SAttilio Rao }
2895fe58019SAttilio Rao if (events & (POLLOUT | POLLWRNORM)) {
2905fe58019SAttilio Rao revents |= events & (POLLOUT | POLLWRNORM);
2915fe58019SAttilio Rao }
2925fe58019SAttilio Rao return (revents);
2935fe58019SAttilio Rao }
2945fe58019SAttilio Rao
2955fe58019SAttilio Rao /*
2965fe58019SAttilio Rao * fuse_device_read hangs on the queue of VFS messages.
2975fe58019SAttilio Rao * When it's notified that there is a new one, it picks that and
2985fe58019SAttilio Rao * passes up to the daemon
2995fe58019SAttilio Rao */
3005fe58019SAttilio Rao int
fuse_device_read(struct cdev * dev,struct uio * uio,int ioflag)3015fe58019SAttilio Rao fuse_device_read(struct cdev *dev, struct uio *uio, int ioflag)
3025fe58019SAttilio Rao {
3035fe58019SAttilio Rao int err;
3045fe58019SAttilio Rao struct fuse_data *data;
3055fe58019SAttilio Rao struct fuse_ticket *tick;
3064f4111d2SAlan Somers void *buf;
3074f4111d2SAlan Somers int buflen;
3085fe58019SAttilio Rao
309419e7ff6SAlan Somers SDT_PROBE2(fusefs, , device, trace, 1, "fuse device read");
3105fe58019SAttilio Rao
3115fe58019SAttilio Rao err = devfs_get_cdevpriv((void **)&data);
3125fe58019SAttilio Rao if (err != 0)
3135fe58019SAttilio Rao return (err);
3145fe58019SAttilio Rao
3155fe58019SAttilio Rao fuse_lck_mtx_lock(data->ms_mtx);
3165fe58019SAttilio Rao again:
3175fe58019SAttilio Rao if (fdata_get_dead(data)) {
318419e7ff6SAlan Somers SDT_PROBE2(fusefs, , device, trace, 2,
319cf169498SAlan Somers "we know early on that reader should be kicked so we "
320cf169498SAlan Somers "don't wait for news");
3215fe58019SAttilio Rao fuse_lck_mtx_unlock(data->ms_mtx);
3225fe58019SAttilio Rao return (ENODEV);
3235fe58019SAttilio Rao }
3245fe58019SAttilio Rao if (!(tick = fuse_ms_pop(data))) {
3255fe58019SAttilio Rao /* check if we may block */
3265fe58019SAttilio Rao if (ioflag & O_NONBLOCK) {
3275fe58019SAttilio Rao /* get outa here soon */
3285fe58019SAttilio Rao fuse_lck_mtx_unlock(data->ms_mtx);
3295fe58019SAttilio Rao return (EAGAIN);
3305fe58019SAttilio Rao } else {
3315fe58019SAttilio Rao err = msleep(data, &data->ms_mtx, PCATCH, "fu_msg", 0);
3325fe58019SAttilio Rao if (err != 0) {
3335fe58019SAttilio Rao fuse_lck_mtx_unlock(data->ms_mtx);
3345fe58019SAttilio Rao return (fdata_get_dead(data) ? ENODEV : err);
3355fe58019SAttilio Rao }
3365fe58019SAttilio Rao tick = fuse_ms_pop(data);
3375fe58019SAttilio Rao }
3385fe58019SAttilio Rao }
3395fe58019SAttilio Rao if (!tick) {
3405fe58019SAttilio Rao /*
3415fe58019SAttilio Rao * We can get here if fuse daemon suddenly terminates,
3425fe58019SAttilio Rao * eg, by being hit by a SIGKILL
3435fe58019SAttilio Rao * -- and some other cases, too, tho not totally clear, when
3445fe58019SAttilio Rao * (cv_signal/wakeup_one signals the whole process ?)
3455fe58019SAttilio Rao */
346419e7ff6SAlan Somers SDT_PROBE2(fusefs, , device, trace, 1, "no message on thread");
3475fe58019SAttilio Rao goto again;
3485fe58019SAttilio Rao }
3495fe58019SAttilio Rao fuse_lck_mtx_unlock(data->ms_mtx);
3505fe58019SAttilio Rao
3515fe58019SAttilio Rao if (fdata_get_dead(data)) {
3525fe58019SAttilio Rao /*
3535fe58019SAttilio Rao * somebody somewhere -- eg., umount routine --
3545fe58019SAttilio Rao * wants this liaison finished off
3555fe58019SAttilio Rao */
356419e7ff6SAlan Somers SDT_PROBE2(fusefs, , device, trace, 2,
357419e7ff6SAlan Somers "reader is to be sacked");
3585fe58019SAttilio Rao if (tick) {
359419e7ff6SAlan Somers SDT_PROBE2(fusefs, , device, trace, 2, "weird -- "
360cf169498SAlan Somers "\"kick\" is set tho there is message");
3615fe58019SAttilio Rao FUSE_ASSERT_MS_DONE(tick);
3625fe58019SAttilio Rao fuse_ticket_drop(tick);
3635fe58019SAttilio Rao }
3645fe58019SAttilio Rao return (ENODEV); /* This should make the daemon get off
3655fe58019SAttilio Rao * of us */
3665fe58019SAttilio Rao }
367419e7ff6SAlan Somers SDT_PROBE2(fusefs, , device, trace, 1,
368cf169498SAlan Somers "fuse device read message successfully");
3695fe58019SAttilio Rao
3704f4111d2SAlan Somers buf = tick->tk_ms_fiov.base;
3714f4111d2SAlan Somers buflen = tick->tk_ms_fiov.len;
3725fe58019SAttilio Rao
3735fe58019SAttilio Rao /*
3745fe58019SAttilio Rao * Why not ban mercilessly stupid daemons who can't keep up
3755fe58019SAttilio Rao * with us? (There is no much use of a partial read here...)
3765fe58019SAttilio Rao */
3775fe58019SAttilio Rao /*
3785fe58019SAttilio Rao * XXX note that in such cases Linux FUSE throws EIO at the
3795fe58019SAttilio Rao * syscall invoker and stands back to the message queue. The
3805fe58019SAttilio Rao * rationale should be made clear (and possibly adopt that
3815fe58019SAttilio Rao * behaviour). Keeping the current scheme at least makes
3825fe58019SAttilio Rao * fallacy as loud as possible...
3835fe58019SAttilio Rao */
3844f4111d2SAlan Somers if (uio->uio_resid < buflen) {
3855fe58019SAttilio Rao fdata_set_dead(data);
386419e7ff6SAlan Somers SDT_PROBE2(fusefs, , device, trace, 2,
387cf169498SAlan Somers "daemon is stupid, kick it off...");
3885fe58019SAttilio Rao err = ENODEV;
3894f4111d2SAlan Somers } else {
3904f4111d2SAlan Somers err = uiomove(buf, buflen, uio);
3915fe58019SAttilio Rao }
3925fe58019SAttilio Rao
3935fe58019SAttilio Rao FUSE_ASSERT_MS_DONE(tick);
3945fe58019SAttilio Rao fuse_ticket_drop(tick);
3955fe58019SAttilio Rao
3965fe58019SAttilio Rao return (err);
3975fe58019SAttilio Rao }
3985fe58019SAttilio Rao
39902295cafSConrad Meyer static inline int
fuse_ohead_audit(struct fuse_out_header * ohead,struct uio * uio)4005fe58019SAttilio Rao fuse_ohead_audit(struct fuse_out_header *ohead, struct uio *uio)
4015fe58019SAttilio Rao {
4025fe58019SAttilio Rao if (uio->uio_resid + sizeof(struct fuse_out_header) != ohead->len) {
403419e7ff6SAlan Somers SDT_PROBE2(fusefs, , device, trace, 1,
404419e7ff6SAlan Somers "Format error: body size "
405cf169498SAlan Somers "differs from size claimed by header");
4065fe58019SAttilio Rao return (EINVAL);
4075fe58019SAttilio Rao }
408c2d70d6eSAlan Somers if (uio->uio_resid && ohead->unique != 0 && ohead->error) {
409419e7ff6SAlan Somers SDT_PROBE2(fusefs, , device, trace, 1,
410cf169498SAlan Somers "Format error: non zero error but message had a body");
4115fe58019SAttilio Rao return (EINVAL);
4125fe58019SAttilio Rao }
4135fe58019SAttilio Rao
4145fe58019SAttilio Rao return (0);
4155fe58019SAttilio Rao }
4165fe58019SAttilio Rao
417c2d70d6eSAlan Somers SDT_PROBE_DEFINE1(fusefs, , device, fuse_device_write_notify,
418c2d70d6eSAlan Somers "struct fuse_out_header*");
419419e7ff6SAlan Somers SDT_PROBE_DEFINE1(fusefs, , device, fuse_device_write_missing_ticket,
420419e7ff6SAlan Somers "uint64_t");
421419e7ff6SAlan Somers SDT_PROBE_DEFINE1(fusefs, , device, fuse_device_write_found,
422419e7ff6SAlan Somers "struct fuse_ticket*");
4235fe58019SAttilio Rao /*
4245fe58019SAttilio Rao * fuse_device_write first reads the header sent by the daemon.
4255fe58019SAttilio Rao * If that's OK, looks up ticket/callback node by the unique id seen in header.
4265fe58019SAttilio Rao * If the callback node contains a handler function, the uio is passed over
4275fe58019SAttilio Rao * that.
4285fe58019SAttilio Rao */
4295fe58019SAttilio Rao static int
fuse_device_write(struct cdev * dev,struct uio * uio,int ioflag)4305fe58019SAttilio Rao fuse_device_write(struct cdev *dev, struct uio *uio, int ioflag)
4315fe58019SAttilio Rao {
4325fe58019SAttilio Rao struct fuse_out_header ohead;
4335fe58019SAttilio Rao int err = 0;
4345fe58019SAttilio Rao struct fuse_data *data;
435c2d70d6eSAlan Somers struct mount *mp;
436a1542146SAlan Somers struct fuse_ticket *tick, *itick, *x_tick;
4375fe58019SAttilio Rao int found = 0;
4385fe58019SAttilio Rao
4395fe58019SAttilio Rao err = devfs_get_cdevpriv((void **)&data);
4405fe58019SAttilio Rao if (err != 0)
4415fe58019SAttilio Rao return (err);
4425fe58019SAttilio Rao
4435fe58019SAttilio Rao if (uio->uio_resid < sizeof(struct fuse_out_header)) {
444419e7ff6SAlan Somers SDT_PROBE2(fusefs, , device, trace, 1,
445cf169498SAlan Somers "fuse_device_write got less than a header!");
4465fe58019SAttilio Rao fdata_set_dead(data);
4475fe58019SAttilio Rao return (EINVAL);
4485fe58019SAttilio Rao }
4495fe58019SAttilio Rao if ((err = uiomove(&ohead, sizeof(struct fuse_out_header), uio)) != 0)
4505fe58019SAttilio Rao return (err);
4515fe58019SAttilio Rao
452e3b1c847SEdward Tomasz Napierala if (data->linux_errnos != 0 && ohead.error != 0) {
453e3b1c847SEdward Tomasz Napierala err = -ohead.error;
454e3b1c847SEdward Tomasz Napierala if (err < 0 || err >= nitems(linux_to_bsd_errtbl))
455e3b1c847SEdward Tomasz Napierala return (EINVAL);
456e3b1c847SEdward Tomasz Napierala
457e3b1c847SEdward Tomasz Napierala /* '-', because it will get flipped again below */
458e3b1c847SEdward Tomasz Napierala ohead.error = -linux_to_bsd_errtbl[err];
459e3b1c847SEdward Tomasz Napierala }
460e3b1c847SEdward Tomasz Napierala
4615fe58019SAttilio Rao /*
4625fe58019SAttilio Rao * We check header information (which is redundant) and compare it
4635fe58019SAttilio Rao * with what we see. If we see some inconsistency we discard the
4645fe58019SAttilio Rao * whole answer and proceed on as if it had never existed. In
4655fe58019SAttilio Rao * particular, no pretender will be woken up, regardless the
4665fe58019SAttilio Rao * "unique" value in the header.
4675fe58019SAttilio Rao */
4685fe58019SAttilio Rao if ((err = fuse_ohead_audit(&ohead, uio))) {
4695fe58019SAttilio Rao fdata_set_dead(data);
4705fe58019SAttilio Rao return (err);
4715fe58019SAttilio Rao }
4725fe58019SAttilio Rao /* Pass stuff over to callback if there is one installed */
4735fe58019SAttilio Rao
4745fe58019SAttilio Rao /* Looking for ticket with the unique id of header */
4755fe58019SAttilio Rao fuse_lck_mtx_lock(data->aw_mtx);
4765fe58019SAttilio Rao TAILQ_FOREACH_SAFE(tick, &data->aw_head, tk_aw_link,
4775fe58019SAttilio Rao x_tick) {
4785fe58019SAttilio Rao if (tick->tk_unique == ohead.unique) {
479419e7ff6SAlan Somers SDT_PROBE1(fusefs, , device, fuse_device_write_found,
480723c7768SAlan Somers tick);
4815fe58019SAttilio Rao found = 1;
4825fe58019SAttilio Rao fuse_aw_remove(tick);
4835fe58019SAttilio Rao break;
4845fe58019SAttilio Rao }
4855fe58019SAttilio Rao }
486a1542146SAlan Somers if (found && tick->irq_unique > 0) {
487a1542146SAlan Somers /*
488a1542146SAlan Somers * Discard the FUSE_INTERRUPT ticket that tried to interrupt
489a1542146SAlan Somers * this operation
490a1542146SAlan Somers */
491a1542146SAlan Somers TAILQ_FOREACH_SAFE(itick, &data->aw_head, tk_aw_link,
492a1542146SAlan Somers x_tick) {
493a1542146SAlan Somers if (itick->tk_unique == tick->irq_unique) {
494a1542146SAlan Somers fuse_aw_remove(itick);
495c1afff11SAlan Somers fuse_ticket_drop(itick);
496a1542146SAlan Somers break;
497a1542146SAlan Somers }
498a1542146SAlan Somers }
499a1542146SAlan Somers tick->irq_unique = 0;
500a1542146SAlan Somers }
5015fe58019SAttilio Rao fuse_lck_mtx_unlock(data->aw_mtx);
5025fe58019SAttilio Rao
5035fe58019SAttilio Rao if (found) {
5045fe58019SAttilio Rao if (tick->tk_aw_handler) {
5055fe58019SAttilio Rao /*
5065fe58019SAttilio Rao * We found a callback with proper handler. In this
5075fe58019SAttilio Rao * case the out header will be 0wnd by the callback,
5085fe58019SAttilio Rao * so the fun of freeing that is left for her.
5095fe58019SAttilio Rao * (Then, by all chance, she'll just get that's done
5105fe58019SAttilio Rao * via ticket_drop(), so no manual mucking
5115fe58019SAttilio Rao * around...)
5125fe58019SAttilio Rao */
513419e7ff6SAlan Somers SDT_PROBE2(fusefs, , device, trace, 1,
514cf169498SAlan Somers "pass ticket to a callback");
515c2d70d6eSAlan Somers /* Sanitize the linuxism of negative errnos */
516c2d70d6eSAlan Somers ohead.error *= -1;
517155ac516SAlan Somers if (ohead.error < 0 || ohead.error > ELAST) {
518155ac516SAlan Somers /* Illegal error code */
519155ac516SAlan Somers ohead.error = EIO;
520155ac516SAlan Somers memcpy(&tick->tk_aw_ohead, &ohead,
521155ac516SAlan Somers sizeof(ohead));
522155ac516SAlan Somers tick->tk_aw_handler(tick, uio);
523155ac516SAlan Somers err = EINVAL;
524155ac516SAlan Somers } else {
525155ac516SAlan Somers memcpy(&tick->tk_aw_ohead, &ohead,
526155ac516SAlan Somers sizeof(ohead));
5275fe58019SAttilio Rao err = tick->tk_aw_handler(tick, uio);
528155ac516SAlan Somers }
5295fe58019SAttilio Rao } else {
5305fe58019SAttilio Rao /* pretender doesn't wanna do anything with answer */
531419e7ff6SAlan Somers SDT_PROBE2(fusefs, , device, trace, 1,
532cf169498SAlan Somers "stuff devalidated, so we drop it");
5335fe58019SAttilio Rao }
5345fe58019SAttilio Rao
5355fe58019SAttilio Rao /*
5365fe58019SAttilio Rao * As aw_mtx was not held during the callback execution the
5375fe58019SAttilio Rao * ticket may have been inserted again. However, this is safe
5385fe58019SAttilio Rao * because fuse_ticket_drop() will deal with refcount anyway.
5395fe58019SAttilio Rao */
5405fe58019SAttilio Rao fuse_ticket_drop(tick);
541c2d70d6eSAlan Somers } else if (ohead.unique == 0){
542c2d70d6eSAlan Somers /* unique == 0 means asynchronous notification */
543c2d70d6eSAlan Somers SDT_PROBE1(fusefs, , device, fuse_device_write_notify, &ohead);
544*98999852SAlan Somers mp = data->mp;
545*98999852SAlan Somers vfs_ref(mp);
546*98999852SAlan Somers err = vfs_busy(mp, 0);
547*98999852SAlan Somers vfs_rel(mp);
548*98999852SAlan Somers if (err)
549*98999852SAlan Somers return (err);
550*98999852SAlan Somers
551c2d70d6eSAlan Somers switch (ohead.error) {
552c2d70d6eSAlan Somers case FUSE_NOTIFY_INVAL_ENTRY:
553c2d70d6eSAlan Somers err = fuse_internal_invalidate_entry(mp, uio);
554c2d70d6eSAlan Somers break;
555c2d70d6eSAlan Somers case FUSE_NOTIFY_INVAL_INODE:
556eae1ae13SAlan Somers err = fuse_internal_invalidate_inode(mp, uio);
557eae1ae13SAlan Somers break;
5587cbb8e8aSAlan Somers case FUSE_NOTIFY_RETRIEVE:
5597cbb8e8aSAlan Somers case FUSE_NOTIFY_STORE:
5607cbb8e8aSAlan Somers /*
5617cbb8e8aSAlan Somers * Unimplemented. I don't know of any file systems
5627cbb8e8aSAlan Somers * that use them, and the protocol isn't sound anyway,
5637cbb8e8aSAlan Somers * since the notification messages don't include the
5647cbb8e8aSAlan Somers * inode's generation number. Without that, it's
5657cbb8e8aSAlan Somers * possible to manipulate the cache of the wrong vnode.
5667cbb8e8aSAlan Somers * Finally, it's not defined what this message should
5677cbb8e8aSAlan Somers * do for a file with dirty cache.
5687cbb8e8aSAlan Somers */
569eae1ae13SAlan Somers case FUSE_NOTIFY_POLL:
5707cbb8e8aSAlan Somers /* Unimplemented. See comments in fuse_vnops */
571c2d70d6eSAlan Somers default:
572c2d70d6eSAlan Somers /* Not implemented */
573c2d70d6eSAlan Somers err = ENOSYS;
574c2d70d6eSAlan Somers }
575*98999852SAlan Somers vfs_unbusy(mp);
5765fe58019SAttilio Rao } else {
5775fe58019SAttilio Rao /* no callback at all! */
578419e7ff6SAlan Somers SDT_PROBE1(fusefs, , device, fuse_device_write_missing_ticket,
579723c7768SAlan Somers ohead.unique);
580c2d70d6eSAlan Somers if (ohead.error == -EAGAIN) {
581a1542146SAlan Somers /*
582a1542146SAlan Somers * This was probably a response to a FUSE_INTERRUPT
583a1542146SAlan Somers * operation whose original operation is already
584a1542146SAlan Somers * complete. We can't store FUSE_INTERRUPT tickets
585a1542146SAlan Somers * indefinitely because their responses are optional.
586a1542146SAlan Somers * So we delete them when the original operation
587a1542146SAlan Somers * completes. And sadly the fuse_header_out doesn't
588a1542146SAlan Somers * identify the opcode, so we have to guess.
589a1542146SAlan Somers */
590a1542146SAlan Somers err = 0;
591a1542146SAlan Somers } else {
5925fe58019SAttilio Rao err = EINVAL;
5935fe58019SAttilio Rao }
594a1542146SAlan Somers }
5955fe58019SAttilio Rao
5965fe58019SAttilio Rao return (err);
5975fe58019SAttilio Rao }
5985fe58019SAttilio Rao
5995fe58019SAttilio Rao int
fuse_device_init(void)6005fe58019SAttilio Rao fuse_device_init(void)
6015fe58019SAttilio Rao {
6025fe58019SAttilio Rao
6035fe58019SAttilio Rao fuse_dev = make_dev(&fuse_device_cdevsw, 0, UID_ROOT, GID_OPERATOR,
604b4227f34SAlan Somers S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, "fuse");
6055fe58019SAttilio Rao if (fuse_dev == NULL)
6065fe58019SAttilio Rao return (ENOMEM);
6075fe58019SAttilio Rao return (0);
6085fe58019SAttilio Rao }
6095fe58019SAttilio Rao
6105fe58019SAttilio Rao void
fuse_device_destroy(void)6115fe58019SAttilio Rao fuse_device_destroy(void)
6125fe58019SAttilio Rao {
6135fe58019SAttilio Rao
6145fe58019SAttilio Rao MPASS(fuse_dev != NULL);
6155fe58019SAttilio Rao destroy_dev(fuse_dev);
6165fe58019SAttilio Rao }
617