Page MenuHomeFreeBSD

D19649.1781202912.diff
No OneTemporary

Size
249 KB
Referenced Files
None
Subscribers
None

D19649.1781202912.diff

Index: UPDATING
===================================================================
--- UPDATING
+++ UPDATING
@@ -31,6 +31,12 @@
disable the most expensive debugging functionality run
"ln -s 'abort:false,junk:false' /etc/malloc.conf".)
+20190319:
+ The fuse(4) module has been renamed to fusefs(4) for consistency with
+ other filesystems. You should update any kld_load="fuse" entries in
+ /etc/rc.conf, fuse_load="YES" entries in /boot/loader.conf, and
+ "options FUSE" enties in kernel config files.
+
20190304:
Clang, llvm, lld, lldb, compiler-rt and libc++ have been upgraded to
8.0.0. Please see the 20141231 entry below for information about
Index: lib/libjail/jail.c
===================================================================
--- lib/libjail/jail.c
+++ lib/libjail/jail.c
@@ -1050,14 +1050,8 @@
kl = kldload(name);
else if (strncmp(name, "allow.mount.", 12) == 0) {
/* Load the matching filesystem */
- const char *modname;
+ const char *modname = name + 12;
- if (strcmp("fusefs", name + 12) == 0 ||
- strcmp("nofusefs", name + 12) == 0) {
- modname = "fuse";
- } else {
- modname = name + 12;
- }
kl = kldload(modname);
if (kl < 0 && errno == ENOENT &&
strncmp(modname, "no", 2) == 0)
Index: sbin/mount_fusefs/mount_fusefs.c
===================================================================
--- sbin/mount_fusefs/mount_fusefs.c
+++ sbin/mount_fusefs/mount_fusefs.c
@@ -501,7 +501,7 @@
len = sizeof(ibg);
- if (sysctlbyname("vfs.fuse.init_backgrounded", &ibg, &len, NULL, 0))
+ if (sysctlbyname("vfs.fusefs.init_backgrounded", &ibg, &len, NULL, 0))
return (0);
return (ibg);
Index: sys/conf/NOTES
===================================================================
--- sys/conf/NOTES
+++ sys/conf/NOTES
@@ -1071,7 +1071,7 @@
options AUTOFS #Automounter filesystem
options CD9660 #ISO 9660 filesystem
options FDESCFS #File descriptor filesystem
-options FUSE #FUSE support module
+options FUSEFS #FUSEFS support module
options MSDOSFS #MS DOS File System (FAT, FAT32)
options NFSLOCKD #Network Lock Manager
options NFSD #Network Filesystem Server
Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -3494,15 +3494,15 @@
fs/fdescfs/fdesc_vnops.c optional fdescfs
fs/fifofs/fifo_vnops.c standard
fs/cuse/cuse.c optional cuse
-fs/fuse/fuse_device.c optional fuse
-fs/fuse/fuse_file.c optional fuse
-fs/fuse/fuse_internal.c optional fuse
-fs/fuse/fuse_io.c optional fuse
-fs/fuse/fuse_ipc.c optional fuse
-fs/fuse/fuse_main.c optional fuse
-fs/fuse/fuse_node.c optional fuse
-fs/fuse/fuse_vfsops.c optional fuse
-fs/fuse/fuse_vnops.c optional fuse
+fs/fusefs/fuse_device.c optional fusefs
+fs/fusefs/fuse_file.c optional fusefs
+fs/fusefs/fuse_internal.c optional fusefs
+fs/fusefs/fuse_io.c optional fusefs
+fs/fusefs/fuse_ipc.c optional fusefs
+fs/fusefs/fuse_main.c optional fusefs
+fs/fusefs/fuse_node.c optional fusefs
+fs/fusefs/fuse_vfsops.c optional fusefs
+fs/fusefs/fuse_vnops.c optional fusefs
fs/msdosfs/msdosfs_conv.c optional msdosfs
fs/msdosfs/msdosfs_denode.c optional msdosfs
fs/msdosfs/msdosfs_fat.c optional msdosfs
Index: sys/conf/options
===================================================================
--- sys/conf/options
+++ sys/conf/options
@@ -253,7 +253,7 @@
EXT2FS opt_dontuse.h
FDESCFS opt_dontuse.h
FFS opt_dontuse.h
-FUSE opt_dontuse.h
+FUSEFS opt_dontuse.h
MSDOSFS opt_dontuse.h
NANDFS opt_dontuse.h
NULLFS opt_dontuse.h
Index: sys/fs/fuse/fuse.h
===================================================================
--- sys/fs/fuse/fuse.h
+++ sys/fs/fuse/fuse.h
@@ -1,226 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Copyright (c) 2007-2009 Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Copyright (C) 2005 Csaba Henk.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#include "fuse_kernel.h"
-
-#define FUSE_DEFAULT_DAEMON_TIMEOUT 60 /* s */
-#define FUSE_MIN_DAEMON_TIMEOUT 0 /* s */
-#define FUSE_MAX_DAEMON_TIMEOUT 600 /* s */
-
-#ifndef FUSE_FREEBSD_VERSION
-#define FUSE_FREEBSD_VERSION "0.4.4"
-#endif
-
-/* Mapping versions to features */
-
-#define FUSE_KERNELABI_GEQ(maj, min) \
-(FUSE_KERNEL_VERSION > (maj) || (FUSE_KERNEL_VERSION == (maj) && FUSE_KERNEL_MINOR_VERSION >= (min)))
-
-/*
- * Appearance of new FUSE operations is not always in par with version
- * numbering... At least, 7.3 is a sufficient condition for having
- * FUSE_{ACCESS,CREATE}.
- */
-#if FUSE_KERNELABI_GEQ(7, 3)
-#ifndef FUSE_HAS_ACCESS
-#define FUSE_HAS_ACCESS 1
-#endif
-#ifndef FUSE_HAS_CREATE
-#define FUSE_HAS_CREATE 1
-#endif
-#else /* FUSE_KERNELABI_GEQ(7, 3) */
-#ifndef FUSE_HAS_ACCESS
-#define FUSE_HAS_ACCESS 0
-#endif
-#ifndef FUSE_HAS_CREATE
-#define FUSE_HAS_CREATE 0
-#endif
-#endif
-
-#if FUSE_KERNELABI_GEQ(7, 7)
-#ifndef FUSE_HAS_GETLK
-#define FUSE_HAS_GETLK 1
-#endif
-#ifndef FUSE_HAS_SETLK
-#define FUSE_HAS_SETLK 1
-#endif
-#ifndef FUSE_HAS_SETLKW
-#define FUSE_HAS_SETLKW 1
-#endif
-#ifndef FUSE_HAS_INTERRUPT
-#define FUSE_HAS_INTERRUPT 1
-#endif
-#else /* FUSE_KERNELABI_GEQ(7, 7) */
-#ifndef FUSE_HAS_GETLK
-#define FUSE_HAS_GETLK 0
-#endif
-#ifndef FUSE_HAS_SETLK
-#define FUSE_HAS_SETLK 0
-#endif
-#ifndef FUSE_HAS_SETLKW
-#define FUSE_HAS_SETLKW 0
-#endif
-#ifndef FUSE_HAS_INTERRUPT
-#define FUSE_HAS_INTERRUPT 0
-#endif
-#endif
-
-#if FUSE_KERNELABI_GEQ(7, 8)
-#ifndef FUSE_HAS_FLUSH_RELEASE
-#define FUSE_HAS_FLUSH_RELEASE 1
-/*
- * "DESTROY" came in the middle of the 7.8 era,
- * so this is not completely exact...
- */
-#ifndef FUSE_HAS_DESTROY
-#define FUSE_HAS_DESTROY 1
-#endif
-#endif
-#else /* FUSE_KERNELABI_GEQ(7, 8) */
-#ifndef FUSE_HAS_FLUSH_RELEASE
-#define FUSE_HAS_FLUSH_RELEASE 0
-#ifndef FUSE_HAS_DESTROY
-#define FUSE_HAS_DESTROY 0
-#endif
-#endif
-#endif
-
-/* misc */
-
-SYSCTL_DECL(_vfs_fuse);
-
-/* Fuse locking */
-
-extern struct mtx fuse_mtx;
-#define FUSE_LOCK() fuse_lck_mtx_lock(fuse_mtx)
-#define FUSE_UNLOCK() fuse_lck_mtx_unlock(fuse_mtx)
-
-#define RECTIFY_TDCR(td, cred) \
-do { \
- if (! (td)) \
- (td) = curthread; \
- if (! (cred)) \
- (cred) = (td)->td_ucred; \
-} while (0)
-
-/* Debug related stuff */
-
-#ifndef FUSE_DEBUG_DEVICE
-#define FUSE_DEBUG_DEVICE 0
-#endif
-
-#ifndef FUSE_DEBUG_FILE
-#define FUSE_DEBUG_FILE 0
-#endif
-
-#ifndef FUSE_DEBUG_INTERNAL
-#define FUSE_DEBUG_INTERNAL 0
-#endif
-
-#ifndef FUSE_DEBUG_IO
-#define FUSE_DEBUG_IO 0
-#endif
-
-#ifndef FUSE_DEBUG_IPC
-#define FUSE_DEBUG_IPC 0
-#endif
-
-#ifndef FUSE_DEBUG_LOCK
-#define FUSE_DEBUG_LOCK 0
-#endif
-
-#ifndef FUSE_DEBUG_VFSOPS
-#define FUSE_DEBUG_VFSOPS 0
-#endif
-
-#ifndef FUSE_DEBUG_VNOPS
-#define FUSE_DEBUG_VNOPS 0
-#endif
-
-#ifndef FUSE_TRACE
-#define FUSE_TRACE 0
-#endif
-
-#define DEBUGX(cond, fmt, ...) do { \
- if (((cond))) { \
- printf("%s: " fmt, __func__, ## __VA_ARGS__); \
- } \
-} while (0)
-
-#define fuse_lck_mtx_lock(mtx) do { \
- DEBUGX(FUSE_DEBUG_LOCK, "0: lock(%s): %s@%d by %d\n", \
- __STRING(mtx), __func__, __LINE__, curthread->td_proc->p_pid); \
- mtx_lock(&(mtx)); \
- DEBUGX(FUSE_DEBUG_LOCK, "1: lock(%s): %s@%d by %d\n", \
- __STRING(mtx), __func__, __LINE__, curthread->td_proc->p_pid); \
-} while (0)
-
-#define fuse_lck_mtx_unlock(mtx) do { \
- DEBUGX(FUSE_DEBUG_LOCK, "0: unlock(%s): %s@%d by %d\n", \
- __STRING(mtx), __func__, __LINE__, curthread->td_proc->p_pid); \
- mtx_unlock(&(mtx)); \
- DEBUGX(FUSE_DEBUG_LOCK, "1: unlock(%s): %s@%d by %d\n", \
- __STRING(mtx), __func__, __LINE__, curthread->td_proc->p_pid); \
-} while (0)
-
-void fuse_ipc_init(void);
-void fuse_ipc_destroy(void);
-
-int fuse_device_init(void);
-void fuse_device_destroy(void);
Index: sys/fs/fuse/fuse_debug.h
===================================================================
--- sys/fs/fuse/fuse_debug.h
+++ sys/fs/fuse/fuse_debug.h
@@ -1,81 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Copyright (c) 2007-2009 Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Copyright (C) 2005 Csaba Henk.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#include <sys/cdefs.h>
-
-/* Debug related stuff */
-
-#ifndef FUSE_DEBUG_MODULE
-#error "FUSE_DEBUG_MODULE is not defined"
-#else
-#define FUSE_DEBUG_VAR __CONCAT(FUSE_DEBUG_,FUSE_DEBUG_MODULE)
-#endif
-
-#define FS_DEBUG(fmt, ...) DEBUGX(FUSE_DEBUG_VAR >= 1, fmt, ## __VA_ARGS__)
-#define FS_DEBUG2G(fmt, ...) DEBUGX(FUSE_DEBUG_VAR >= 2, fmt, ## __VA_ARGS__)
-
-#define debug_printf(fmt, ...) FS_DEBUG(fmt, ## __VA_ARGS__)
-#define kdebug_printf(fmt, ...) FS_DEBUG(fmt, ## __VA_ARGS__)
-
-#define fuse_trace_printf(fmt, ...) \
- DEBUGX(FUSE_DEBUG_VAR && FUSE_TRACE, fmt, ## __VA_ARGS__)
-#define fuse_trace_printf_func() \
- fuse_trace_printf("%s:%d\n", __FILE__, __LINE__)
-#define fuse_trace_printf_vfsop() fuse_trace_printf_func()
-#define fuse_trace_printf_vnop() fuse_trace_printf_func()
Index: sys/fs/fuse/fuse_device.c
===================================================================
--- sys/fs/fuse/fuse_device.c
+++ sys/fs/fuse/fuse_device.c
@@ -1,448 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Copyright (c) 2007-2009 Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Copyright (C) 2005 Csaba Henk.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/types.h>
-#include <sys/module.h>
-#include <sys/systm.h>
-#include <sys/errno.h>
-#include <sys/param.h>
-#include <sys/kernel.h>
-#include <sys/conf.h>
-#include <sys/uio.h>
-#include <sys/malloc.h>
-#include <sys/queue.h>
-#include <sys/lock.h>
-#include <sys/sx.h>
-#include <sys/mutex.h>
-#include <sys/proc.h>
-#include <sys/mount.h>
-#include <sys/stat.h>
-#include <sys/fcntl.h>
-#include <sys/sysctl.h>
-#include <sys/poll.h>
-#include <sys/selinfo.h>
-
-#include "fuse.h"
-#include "fuse_ipc.h"
-
-#define FUSE_DEBUG_MODULE DEVICE
-#include "fuse_debug.h"
-
-static struct cdev *fuse_dev;
-
-static d_open_t fuse_device_open;
-static d_close_t fuse_device_close;
-static d_poll_t fuse_device_poll;
-static d_read_t fuse_device_read;
-static d_write_t fuse_device_write;
-
-static struct cdevsw fuse_device_cdevsw = {
- .d_open = fuse_device_open,
- .d_close = fuse_device_close,
- .d_name = "fuse",
- .d_poll = fuse_device_poll,
- .d_read = fuse_device_read,
- .d_write = fuse_device_write,
- .d_version = D_VERSION,
-};
-
-/****************************
- *
- * >>> Fuse device op defs
- *
- ****************************/
-
-static void
-fdata_dtor(void *arg)
-{
- struct fuse_data *fdata;
-
- fdata = arg;
- fdata_trydestroy(fdata);
-}
-
-/*
- * Resources are set up on a per-open basis
- */
-static int
-fuse_device_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
-{
- struct fuse_data *fdata;
- int error;
-
- FS_DEBUG("device %p\n", dev);
-
- fdata = fdata_alloc(dev, td->td_ucred);
- error = devfs_set_cdevpriv(fdata, fdata_dtor);
- if (error != 0)
- fdata_trydestroy(fdata);
- else
- FS_DEBUG("%s: device opened by thread %d.\n", dev->si_name,
- td->td_tid);
- return (error);
-}
-
-static int
-fuse_device_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
-{
- struct fuse_data *data;
- struct fuse_ticket *tick;
- int error;
-
- error = devfs_get_cdevpriv((void **)&data);
- if (error != 0)
- return (error);
- if (!data)
- panic("no fuse data upon fuse device close");
- fdata_set_dead(data);
-
- FUSE_LOCK();
- fuse_lck_mtx_lock(data->aw_mtx);
- /* wakup poll()ers */
- selwakeuppri(&data->ks_rsel, PZERO + 1);
- /* Don't let syscall handlers wait in vain */
- while ((tick = fuse_aw_pop(data))) {
- fuse_lck_mtx_lock(tick->tk_aw_mtx);
- fticket_set_answered(tick);
- tick->tk_aw_errno = ENOTCONN;
- wakeup(tick);
- fuse_lck_mtx_unlock(tick->tk_aw_mtx);
- FUSE_ASSERT_AW_DONE(tick);
- fuse_ticket_drop(tick);
- }
- fuse_lck_mtx_unlock(data->aw_mtx);
- FUSE_UNLOCK();
-
- FS_DEBUG("%s: device closed by thread %d.\n", dev->si_name, td->td_tid);
- return (0);
-}
-
-int
-fuse_device_poll(struct cdev *dev, int events, struct thread *td)
-{
- struct fuse_data *data;
- int error, revents = 0;
-
- error = devfs_get_cdevpriv((void **)&data);
- if (error != 0)
- return (events &
- (POLLHUP|POLLIN|POLLRDNORM|POLLOUT|POLLWRNORM));
-
- if (events & (POLLIN | POLLRDNORM)) {
- fuse_lck_mtx_lock(data->ms_mtx);
- if (fdata_get_dead(data) || STAILQ_FIRST(&data->ms_head))
- revents |= events & (POLLIN | POLLRDNORM);
- else
- selrecord(td, &data->ks_rsel);
- fuse_lck_mtx_unlock(data->ms_mtx);
- }
- if (events & (POLLOUT | POLLWRNORM)) {
- revents |= events & (POLLOUT | POLLWRNORM);
- }
- return (revents);
-}
-
-/*
- * fuse_device_read hangs on the queue of VFS messages.
- * When it's notified that there is a new one, it picks that and
- * passes up to the daemon
- */
-int
-fuse_device_read(struct cdev *dev, struct uio *uio, int ioflag)
-{
- int err;
- struct fuse_data *data;
- struct fuse_ticket *tick;
- void *buf[] = {NULL, NULL, NULL};
- int buflen[3];
- int i;
-
- FS_DEBUG("fuse device being read on thread %d\n", uio->uio_td->td_tid);
-
- err = devfs_get_cdevpriv((void **)&data);
- if (err != 0)
- return (err);
-
- fuse_lck_mtx_lock(data->ms_mtx);
-again:
- if (fdata_get_dead(data)) {
- FS_DEBUG2G("we know early on that reader should be kicked so we don't wait for news\n");
- fuse_lck_mtx_unlock(data->ms_mtx);
- return (ENODEV);
- }
- if (!(tick = fuse_ms_pop(data))) {
- /* check if we may block */
- if (ioflag & O_NONBLOCK) {
- /* get outa here soon */
- fuse_lck_mtx_unlock(data->ms_mtx);
- return (EAGAIN);
- } else {
- err = msleep(data, &data->ms_mtx, PCATCH, "fu_msg", 0);
- if (err != 0) {
- fuse_lck_mtx_unlock(data->ms_mtx);
- return (fdata_get_dead(data) ? ENODEV : err);
- }
- tick = fuse_ms_pop(data);
- }
- }
- if (!tick) {
- /*
- * We can get here if fuse daemon suddenly terminates,
- * eg, by being hit by a SIGKILL
- * -- and some other cases, too, tho not totally clear, when
- * (cv_signal/wakeup_one signals the whole process ?)
- */
- FS_DEBUG("no message on thread #%d\n", uio->uio_td->td_tid);
- goto again;
- }
- fuse_lck_mtx_unlock(data->ms_mtx);
-
- if (fdata_get_dead(data)) {
- /*
- * somebody somewhere -- eg., umount routine --
- * wants this liaison finished off
- */
- FS_DEBUG2G("reader is to be sacked\n");
- if (tick) {
- FS_DEBUG2G("weird -- \"kick\" is set tho there is message\n");
- FUSE_ASSERT_MS_DONE(tick);
- fuse_ticket_drop(tick);
- }
- return (ENODEV); /* This should make the daemon get off
- * of us */
- }
- FS_DEBUG("message got on thread #%d\n", uio->uio_td->td_tid);
-
- KASSERT(tick->tk_ms_bufdata || tick->tk_ms_bufsize == 0,
- ("non-null buf pointer with positive size"));
-
- switch (tick->tk_ms_type) {
- case FT_M_FIOV:
- buf[0] = tick->tk_ms_fiov.base;
- buflen[0] = tick->tk_ms_fiov.len;
- break;
- case FT_M_BUF:
- buf[0] = tick->tk_ms_fiov.base;
- buflen[0] = tick->tk_ms_fiov.len;
- buf[1] = tick->tk_ms_bufdata;
- buflen[1] = tick->tk_ms_bufsize;
- break;
- default:
- panic("unknown message type for fuse_ticket %p", tick);
- }
-
- for (i = 0; buf[i]; i++) {
- /*
- * Why not ban mercilessly stupid daemons who can't keep up
- * with us? (There is no much use of a partial read here...)
- */
- /*
- * XXX note that in such cases Linux FUSE throws EIO at the
- * syscall invoker and stands back to the message queue. The
- * rationale should be made clear (and possibly adopt that
- * behaviour). Keeping the current scheme at least makes
- * fallacy as loud as possible...
- */
- if (uio->uio_resid < buflen[i]) {
- fdata_set_dead(data);
- FS_DEBUG2G("daemon is stupid, kick it off...\n");
- err = ENODEV;
- break;
- }
- err = uiomove(buf[i], buflen[i], uio);
- if (err)
- break;
- }
-
- FUSE_ASSERT_MS_DONE(tick);
- fuse_ticket_drop(tick);
-
- return (err);
-}
-
-static inline int
-fuse_ohead_audit(struct fuse_out_header *ohead, struct uio *uio)
-{
- FS_DEBUG("Out header -- len: %i, error: %i, unique: %llu; iovecs: %d\n",
- ohead->len, ohead->error, (unsigned long long)ohead->unique,
- uio->uio_iovcnt);
-
- if (uio->uio_resid + sizeof(struct fuse_out_header) != ohead->len) {
- FS_DEBUG("Format error: body size differs from size claimed by header\n");
- return (EINVAL);
- }
- if (uio->uio_resid && ohead->error) {
- FS_DEBUG("Format error: non zero error but message had a body\n");
- return (EINVAL);
- }
- /* Sanitize the linuxism of negative errnos */
- ohead->error = -(ohead->error);
-
- return (0);
-}
-
-/*
- * fuse_device_write first reads the header sent by the daemon.
- * If that's OK, looks up ticket/callback node by the unique id seen in header.
- * If the callback node contains a handler function, the uio is passed over
- * that.
- */
-static int
-fuse_device_write(struct cdev *dev, struct uio *uio, int ioflag)
-{
- struct fuse_out_header ohead;
- int err = 0;
- struct fuse_data *data;
- struct fuse_ticket *tick, *x_tick;
- int found = 0;
-
- FS_DEBUG("resid: %zd, iovcnt: %d, thread: %d\n",
- uio->uio_resid, uio->uio_iovcnt, uio->uio_td->td_tid);
-
- err = devfs_get_cdevpriv((void **)&data);
- if (err != 0)
- return (err);
-
- if (uio->uio_resid < sizeof(struct fuse_out_header)) {
- FS_DEBUG("got less than a header!\n");
- fdata_set_dead(data);
- return (EINVAL);
- }
- if ((err = uiomove(&ohead, sizeof(struct fuse_out_header), uio)) != 0)
- return (err);
-
- /*
- * We check header information (which is redundant) and compare it
- * with what we see. If we see some inconsistency we discard the
- * whole answer and proceed on as if it had never existed. In
- * particular, no pretender will be woken up, regardless the
- * "unique" value in the header.
- */
- if ((err = fuse_ohead_audit(&ohead, uio))) {
- fdata_set_dead(data);
- return (err);
- }
- /* Pass stuff over to callback if there is one installed */
-
- /* Looking for ticket with the unique id of header */
- fuse_lck_mtx_lock(data->aw_mtx);
- TAILQ_FOREACH_SAFE(tick, &data->aw_head, tk_aw_link,
- x_tick) {
- FS_DEBUG("bumped into callback #%llu\n",
- (unsigned long long)tick->tk_unique);
- if (tick->tk_unique == ohead.unique) {
- found = 1;
- fuse_aw_remove(tick);
- break;
- }
- }
- fuse_lck_mtx_unlock(data->aw_mtx);
-
- if (found) {
- if (tick->tk_aw_handler) {
- /*
- * We found a callback with proper handler. In this
- * case the out header will be 0wnd by the callback,
- * so the fun of freeing that is left for her.
- * (Then, by all chance, she'll just get that's done
- * via ticket_drop(), so no manual mucking
- * around...)
- */
- FS_DEBUG("pass ticket to a callback\n");
- memcpy(&tick->tk_aw_ohead, &ohead, sizeof(ohead));
- err = tick->tk_aw_handler(tick, uio);
- } else {
- /* pretender doesn't wanna do anything with answer */
- FS_DEBUG("stuff devalidated, so we drop it\n");
- }
-
- /*
- * As aw_mtx was not held during the callback execution the
- * ticket may have been inserted again. However, this is safe
- * because fuse_ticket_drop() will deal with refcount anyway.
- */
- fuse_ticket_drop(tick);
- } else {
- /* no callback at all! */
- FS_DEBUG("erhm, no handler for this response\n");
- err = EINVAL;
- }
-
- return (err);
-}
-
-int
-fuse_device_init(void)
-{
-
- fuse_dev = make_dev(&fuse_device_cdevsw, 0, UID_ROOT, GID_OPERATOR,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, "fuse");
- if (fuse_dev == NULL)
- return (ENOMEM);
- return (0);
-}
-
-void
-fuse_device_destroy(void)
-{
-
- MPASS(fuse_dev != NULL);
- destroy_dev(fuse_dev);
-}
Index: sys/fs/fuse/fuse_file.h
===================================================================
--- sys/fs/fuse/fuse_file.h
+++ sys/fs/fuse/fuse_file.h
@@ -1,146 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Copyright (c) 2007-2009 Google Inc. and Amit Singh
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Copyright (C) 2005 Csaba Henk.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#ifndef _FUSE_FILE_H_
-#define _FUSE_FILE_H_
-
-#include <sys/types.h>
-#include <sys/fcntl.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <sys/vnode.h>
-
-typedef enum fufh_type {
- FUFH_INVALID = -1,
- FUFH_RDONLY = 0,
- FUFH_WRONLY = 1,
- FUFH_RDWR = 2,
- FUFH_MAXTYPE = 3,
-} fufh_type_t;
-_Static_assert(FUFH_RDONLY == O_RDONLY, "RDONLY");
-_Static_assert(FUFH_WRONLY == O_WRONLY, "WRONLY");
-_Static_assert(FUFH_RDWR == O_RDWR, "RDWR");
-
-struct fuse_filehandle {
- uint64_t fh_id;
- fufh_type_t fh_type;
-};
-
-#define FUFH_IS_VALID(f) ((f)->fh_type != FUFH_INVALID)
-
-static inline fufh_type_t
-fuse_filehandle_xlate_from_mmap(int fflags)
-{
- if (fflags & (PROT_READ | PROT_WRITE))
- return FUFH_RDWR;
- else if (fflags & (PROT_WRITE))
- return FUFH_WRONLY;
- else if ((fflags & PROT_READ) || (fflags & PROT_EXEC))
- return FUFH_RDONLY;
- else
- return FUFH_INVALID;
-}
-
-static inline fufh_type_t
-fuse_filehandle_xlate_from_fflags(int fflags)
-{
- if ((fflags & FREAD) && (fflags & FWRITE))
- return FUFH_RDWR;
- else if (fflags & (FWRITE))
- return FUFH_WRONLY;
- else if (fflags & (FREAD))
- return FUFH_RDONLY;
- else
- panic("FUSE: What kind of a flag is this (%x)?", fflags);
-}
-
-static inline int
-fuse_filehandle_xlate_to_oflags(fufh_type_t type)
-{
- int oflags = -1;
-
- switch (type) {
- case FUFH_RDONLY:
- case FUFH_WRONLY:
- case FUFH_RDWR:
- oflags = type;
- break;
- default:
- break;
- }
-
- return oflags;
-}
-
-int fuse_filehandle_valid(struct vnode *vp, fufh_type_t fufh_type);
-fufh_type_t fuse_filehandle_validrw(struct vnode *vp, fufh_type_t fufh_type);
-int fuse_filehandle_get(struct vnode *vp, fufh_type_t fufh_type,
- struct fuse_filehandle **fufhp);
-int fuse_filehandle_getrw(struct vnode *vp, fufh_type_t fufh_type,
- struct fuse_filehandle **fufhp);
-
-void fuse_filehandle_init(struct vnode *vp, fufh_type_t fufh_type,
- struct fuse_filehandle **fufhp, uint64_t fh_id);
-int fuse_filehandle_open(struct vnode *vp, fufh_type_t fufh_type,
- struct fuse_filehandle **fufhp, struct thread *td,
- struct ucred *cred);
-int fuse_filehandle_close(struct vnode *vp, fufh_type_t fufh_type,
- struct thread *td, struct ucred *cred);
-
-#endif /* _FUSE_FILE_H_ */
Index: sys/fs/fuse/fuse_file.c
===================================================================
--- sys/fs/fuse/fuse_file.c
+++ sys/fs/fuse/fuse_file.c
@@ -1,281 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Copyright (c) 2007-2009 Google Inc. and Amit Singh
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Copyright (C) 2005 Csaba Henk.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/types.h>
-#include <sys/module.h>
-#include <sys/systm.h>
-#include <sys/errno.h>
-#include <sys/param.h>
-#include <sys/kernel.h>
-#include <sys/conf.h>
-#include <sys/uio.h>
-#include <sys/malloc.h>
-#include <sys/queue.h>
-#include <sys/lock.h>
-#include <sys/sx.h>
-#include <sys/mutex.h>
-#include <sys/proc.h>
-#include <sys/mount.h>
-#include <sys/vnode.h>
-#include <sys/sysctl.h>
-
-#include "fuse.h"
-#include "fuse_file.h"
-#include "fuse_internal.h"
-#include "fuse_ipc.h"
-#include "fuse_node.h"
-
-#define FUSE_DEBUG_MODULE FILE
-#include "fuse_debug.h"
-
-static int fuse_fh_count = 0;
-
-SYSCTL_INT(_vfs_fuse, OID_AUTO, filehandle_count, CTLFLAG_RD,
- &fuse_fh_count, 0, "number of open FUSE filehandles");
-
-int
-fuse_filehandle_open(struct vnode *vp, fufh_type_t fufh_type,
- struct fuse_filehandle **fufhp, struct thread *td, struct ucred *cred)
-{
- struct fuse_dispatcher fdi;
- struct fuse_open_in *foi;
- struct fuse_open_out *foo;
-
- int err = 0;
- int oflags = 0;
- int op = FUSE_OPEN;
-
- fuse_trace_printf("fuse_filehandle_open(vp=%p, fufh_type=%d)\n",
- vp, fufh_type);
-
- if (fuse_filehandle_valid(vp, fufh_type)) {
- panic("FUSE: filehandle_open called despite valid fufh (type=%d)",
- fufh_type);
- /* NOTREACHED */
- }
- /*
- * Note that this means we are effectively FILTERING OUT open() flags.
- */
- oflags = fuse_filehandle_xlate_to_oflags(fufh_type);
-
- if (vnode_isdir(vp)) {
- op = FUSE_OPENDIR;
- if (fufh_type != FUFH_RDONLY) {
- printf("FUSE:non-rdonly fh requested for a directory?\n");
- fufh_type = FUFH_RDONLY;
- }
- }
- fdisp_init(&fdi, sizeof(*foi));
- fdisp_make_vp(&fdi, op, vp, td, cred);
-
- foi = fdi.indata;
- foi->flags = oflags;
-
- if ((err = fdisp_wait_answ(&fdi))) {
- debug_printf("OUCH ... daemon didn't give fh (err = %d)\n", err);
- if (err == ENOENT) {
- fuse_internal_vnode_disappear(vp);
- }
- goto out;
- }
- foo = fdi.answ;
-
- fuse_filehandle_init(vp, fufh_type, fufhp, foo->fh);
-
- /*
- * For WRONLY opens, force DIRECT_IO. This is necessary
- * since writing a partial block through the buffer cache
- * will result in a read of the block and that read won't
- * be allowed by the WRONLY open.
- */
- if (fufh_type == FUFH_WRONLY)
- fuse_vnode_open(vp, foo->open_flags | FOPEN_DIRECT_IO, td);
- else
- fuse_vnode_open(vp, foo->open_flags, td);
-
-out:
- fdisp_destroy(&fdi);
- return err;
-}
-
-int
-fuse_filehandle_close(struct vnode *vp, fufh_type_t fufh_type,
- struct thread *td, struct ucred *cred)
-{
- struct fuse_dispatcher fdi;
- struct fuse_release_in *fri;
- struct fuse_vnode_data *fvdat = VTOFUD(vp);
- struct fuse_filehandle *fufh = NULL;
-
- int err = 0;
- int op = FUSE_RELEASE;
-
- fuse_trace_printf("fuse_filehandle_put(vp=%p, fufh_type=%d)\n",
- vp, fufh_type);
-
- fufh = &(fvdat->fufh[fufh_type]);
- if (!FUFH_IS_VALID(fufh)) {
- panic("FUSE: filehandle_put called on invalid fufh (type=%d)",
- fufh_type);
- /* NOTREACHED */
- }
- if (fuse_isdeadfs(vp)) {
- goto out;
- }
- if (vnode_isdir(vp))
- op = FUSE_RELEASEDIR;
- fdisp_init(&fdi, sizeof(*fri));
- fdisp_make_vp(&fdi, op, vp, td, cred);
- fri = fdi.indata;
- fri->fh = fufh->fh_id;
- fri->flags = fuse_filehandle_xlate_to_oflags(fufh_type);
-
- err = fdisp_wait_answ(&fdi);
- fdisp_destroy(&fdi);
-
-out:
- atomic_subtract_acq_int(&fuse_fh_count, 1);
- fufh->fh_id = (uint64_t)-1;
- fufh->fh_type = FUFH_INVALID;
-
- return err;
-}
-
-int
-fuse_filehandle_valid(struct vnode *vp, fufh_type_t fufh_type)
-{
- struct fuse_vnode_data *fvdat = VTOFUD(vp);
- struct fuse_filehandle *fufh;
-
- fufh = &(fvdat->fufh[fufh_type]);
- return FUFH_IS_VALID(fufh);
-}
-
-/*
- * Check for a valid file handle, first the type requested, but if that
- * isn't valid, try for FUFH_RDWR.
- * Return the FUFH type that is valid or FUFH_INVALID if there are none.
- * This is a variant of fuse_filehandle_vaild() analogous to
- * fuse_filehandle_getrw().
- */
-fufh_type_t
-fuse_filehandle_validrw(struct vnode *vp, fufh_type_t fufh_type)
-{
- struct fuse_vnode_data *fvdat = VTOFUD(vp);
- struct fuse_filehandle *fufh;
-
- fufh = &fvdat->fufh[fufh_type];
- if (FUFH_IS_VALID(fufh) != 0)
- return (fufh_type);
- fufh = &fvdat->fufh[FUFH_RDWR];
- if (FUFH_IS_VALID(fufh) != 0)
- return (FUFH_RDWR);
- return (FUFH_INVALID);
-}
-
-int
-fuse_filehandle_get(struct vnode *vp, fufh_type_t fufh_type,
- struct fuse_filehandle **fufhp)
-{
- struct fuse_vnode_data *fvdat = VTOFUD(vp);
- struct fuse_filehandle *fufh;
-
- fufh = &(fvdat->fufh[fufh_type]);
- if (!FUFH_IS_VALID(fufh))
- return EBADF;
- if (fufhp != NULL)
- *fufhp = fufh;
- return 0;
-}
-
-int
-fuse_filehandle_getrw(struct vnode *vp, fufh_type_t fufh_type,
- struct fuse_filehandle **fufhp)
-{
- struct fuse_vnode_data *fvdat = VTOFUD(vp);
- struct fuse_filehandle *fufh;
-
- fufh = &(fvdat->fufh[fufh_type]);
- if (!FUFH_IS_VALID(fufh)) {
- fufh_type = FUFH_RDWR;
- }
- return fuse_filehandle_get(vp, fufh_type, fufhp);
-}
-
-void
-fuse_filehandle_init(struct vnode *vp, fufh_type_t fufh_type,
- struct fuse_filehandle **fufhp, uint64_t fh_id)
-{
- struct fuse_vnode_data *fvdat = VTOFUD(vp);
- struct fuse_filehandle *fufh;
-
- FS_DEBUG("id=%jd type=%d\n", (intmax_t)fh_id, fufh_type);
- fufh = &(fvdat->fufh[fufh_type]);
- MPASS(!FUFH_IS_VALID(fufh));
- fufh->fh_id = fh_id;
- fufh->fh_type = fufh_type;
- if (!FUFH_IS_VALID(fufh)) {
- panic("FUSE: init: invalid filehandle id (type=%d)", fufh_type);
- }
- if (fufhp != NULL)
- *fufhp = fufh;
-
- atomic_add_acq_int(&fuse_fh_count, 1);
-}
Index: sys/fs/fuse/fuse_internal.h
===================================================================
--- sys/fs/fuse/fuse_internal.h
+++ sys/fs/fuse/fuse_internal.h
@@ -1,349 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Copyright (c) 2007-2009 Google Inc. and Amit Singh
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Copyright (C) 2005 Csaba Henk.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#ifndef _FUSE_INTERNAL_H_
-#define _FUSE_INTERNAL_H_
-
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <sys/stat.h>
-#include <sys/vnode.h>
-
-#include "fuse_ipc.h"
-#include "fuse_node.h"
-
-static inline bool
-vfs_isrdonly(struct mount *mp)
-{
- return ((mp->mnt_flag & MNT_RDONLY) != 0);
-}
-
-static inline struct mount *
-vnode_mount(struct vnode *vp)
-{
- return (vp->v_mount);
-}
-
-static inline bool
-vnode_mountedhere(struct vnode *vp)
-{
- return (vp->v_mountedhere != NULL);
-}
-
-static inline enum vtype
-vnode_vtype(struct vnode *vp)
-{
- return (vp->v_type);
-}
-
-static inline bool
-vnode_isvroot(struct vnode *vp)
-{
- return ((vp->v_vflag & VV_ROOT) != 0);
-}
-
-static inline bool
-vnode_isreg(struct vnode *vp)
-{
- return (vp->v_type == VREG);
-}
-
-static inline bool
-vnode_isdir(struct vnode *vp)
-{
- return (vp->v_type == VDIR);
-}
-
-static inline bool
-vnode_islnk(struct vnode *vp)
-{
- return (vp->v_type == VLNK);
-}
-
-static inline ssize_t
-uio_resid(struct uio *uio)
-{
- return (uio->uio_resid);
-}
-
-static inline off_t
-uio_offset(struct uio *uio)
-{
- return (uio->uio_offset);
-}
-
-static inline void
-uio_setoffset(struct uio *uio, off_t offset)
-{
- uio->uio_offset = offset;
-}
-
-static inline void
-uio_setresid(struct uio *uio, ssize_t resid)
-{
- uio->uio_resid = resid;
-}
-
-/* miscellaneous */
-
-static inline bool
-fuse_isdeadfs(struct vnode *vp)
-{
- struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp));
-
- return (data->dataflags & FSESS_DEAD);
-}
-
-static inline uint64_t
-fuse_iosize(struct vnode *vp)
-{
- return (vp->v_mount->mnt_stat.f_iosize);
-}
-
-/* access */
-
-#define FVP_ACCESS_NOOP 0x01
-
-#define FACCESS_VA_VALID 0x01
-#define FACCESS_DO_ACCESS 0x02
-#define FACCESS_STICKY 0x04
-#define FACCESS_CHOWN 0x08
-#define FACCESS_NOCHECKSPY 0x10
-#define FACCESS_SETGID 0x12
-
-#define FACCESS_XQUERIES (FACCESS_STICKY | FACCESS_CHOWN | FACCESS_SETGID)
-
-struct fuse_access_param {
- uid_t xuid;
- gid_t xgid;
- uint32_t facc_flags;
-};
-
-static inline int
-fuse_match_cred(struct ucred *basecred, struct ucred *usercred)
-{
- if (basecred->cr_uid == usercred->cr_uid &&
- basecred->cr_uid == usercred->cr_ruid &&
- basecred->cr_uid == usercred->cr_svuid &&
- basecred->cr_groups[0] == usercred->cr_groups[0] &&
- basecred->cr_groups[0] == usercred->cr_rgid &&
- basecred->cr_groups[0] == usercred->cr_svgid)
- return (0);
-
- return (EPERM);
-}
-
-int fuse_internal_access(struct vnode *vp, mode_t mode,
- struct fuse_access_param *facp, struct thread *td, struct ucred *cred);
-
-/* attributes */
-
-/*
- * Cache FUSE attributes 'fat', with nominal expiration
- * 'attr_valid'.'attr_valid_nsec', in attr cache associated with vnode 'vp'.
- * Optionally, if argument 'vap' is not NULL, store a copy of the converted
- * attributes there as well.
- *
- * If the nominal attribute cache TTL is zero, do not cache on the 'vp' (but do
- * return the result to the caller).
- */
-static inline void
-fuse_internal_attr_fat2vat(struct vnode *vp, struct fuse_attr *fat,
- uint64_t attr_valid, uint32_t attr_valid_nsec, struct vattr *vap)
-{
- struct mount *mp;
- struct fuse_vnode_data *fvdat;
- struct vattr *vp_cache_at;
-
- mp = vnode_mount(vp);
- fvdat = VTOFUD(vp);
-
- DEBUGX(FUSE_DEBUG_INTERNAL, "node #%ju, mode 0%o\n",
- (uintmax_t)fat->ino, fat->mode);
-
- /* Honor explicit do-not-cache requests from user filesystems. */
- if (attr_valid == 0 && attr_valid_nsec == 0)
- fvdat->valid_attr_cache = false;
- else
- fvdat->valid_attr_cache = true;
-
- vp_cache_at = VTOVA(vp);
-
- if (vap == NULL && vp_cache_at == NULL)
- return;
-
- if (vap == NULL)
- vap = vp_cache_at;
-
- vattr_null(vap);
-
- vap->va_fsid = mp->mnt_stat.f_fsid.val[0];
- vap->va_fileid = fat->ino;
- vap->va_mode = fat->mode & ~S_IFMT;
- vap->va_nlink = fat->nlink;
- vap->va_uid = fat->uid;
- vap->va_gid = fat->gid;
- vap->va_rdev = fat->rdev;
- vap->va_size = fat->size;
- /* XXX on i386, seconds are truncated to 32 bits */
- vap->va_atime.tv_sec = fat->atime;
- vap->va_atime.tv_nsec = fat->atimensec;
- vap->va_mtime.tv_sec = fat->mtime;
- vap->va_mtime.tv_nsec = fat->mtimensec;
- vap->va_ctime.tv_sec = fat->ctime;
- vap->va_ctime.tv_nsec = fat->ctimensec;
- vap->va_blocksize = PAGE_SIZE;
- vap->va_type = IFTOVT(fat->mode);
- vap->va_bytes = fat->blocks * S_BLKSIZE;
- vap->va_flags = 0;
-
- if (vap != vp_cache_at && vp_cache_at != NULL)
- memcpy(vp_cache_at, vap, sizeof(*vap));
-}
-
-
-#define cache_attrs(vp, fuse_out, vap_out) \
- fuse_internal_attr_fat2vat((vp), &(fuse_out)->attr, \
- (fuse_out)->attr_valid, (fuse_out)->attr_valid_nsec, (vap_out))
-
-/* fsync */
-
-int fuse_internal_fsync(struct vnode *vp, struct thread *td,
- struct ucred *cred, struct fuse_filehandle *fufh);
-int fuse_internal_fsync_callback(struct fuse_ticket *tick, struct uio *uio);
-
-/* readdir */
-
-struct pseudo_dirent {
- uint32_t d_namlen;
-};
-
-int fuse_internal_readdir(struct vnode *vp, struct uio *uio,
- struct fuse_filehandle *fufh, struct fuse_iov *cookediov);
-int fuse_internal_readdir_processdata(struct uio *uio, size_t reqsize,
- void *buf, size_t bufsize, void *param);
-
-/* remove */
-
-int fuse_internal_remove(struct vnode *dvp, struct vnode *vp,
- struct componentname *cnp, enum fuse_opcode op);
-
-/* rename */
-
-int fuse_internal_rename(struct vnode *fdvp, struct componentname *fcnp,
- struct vnode *tdvp, struct componentname *tcnp);
-
-/* revoke */
-
-void fuse_internal_vnode_disappear(struct vnode *vp);
-
-/* strategy */
-
-/* entity creation */
-
-static inline int
-fuse_internal_checkentry(struct fuse_entry_out *feo, enum vtype vtyp)
-{
- DEBUGX(FUSE_DEBUG_INTERNAL,
- "feo=%p, vtype=%d\n", feo, vtyp);
-
- if (vtyp != IFTOVT(feo->attr.mode)) {
- DEBUGX(FUSE_DEBUG_INTERNAL,
- "EINVAL -- %x != %x\n", vtyp, IFTOVT(feo->attr.mode));
- return (EINVAL);
- }
-
- if (feo->nodeid == FUSE_NULL_ID) {
- DEBUGX(FUSE_DEBUG_INTERNAL,
- "EINVAL -- feo->nodeid is NULL\n");
- return (EINVAL);
- }
-
- if (feo->nodeid == FUSE_ROOT_ID) {
- DEBUGX(FUSE_DEBUG_INTERNAL,
- "EINVAL -- feo->nodeid is FUSE_ROOT_ID\n");
- return (EINVAL);
- }
-
- return (0);
-}
-
-int fuse_internal_newentry(struct vnode *dvp, struct vnode **vpp,
- struct componentname *cnp, enum fuse_opcode op, void *buf, size_t bufsize,
- enum vtype vtyp);
-
-void fuse_internal_newentry_makerequest(struct mount *mp, uint64_t dnid,
- struct componentname *cnp, enum fuse_opcode op, void *buf, size_t bufsize,
- struct fuse_dispatcher *fdip);
-
-int fuse_internal_newentry_core(struct vnode *dvp, struct vnode **vpp,
- struct componentname *cnp, enum vtype vtyp, struct fuse_dispatcher *fdip);
-
-/* entity destruction */
-
-int fuse_internal_forget_callback(struct fuse_ticket *tick, struct uio *uio);
-void fuse_internal_forget_send(struct mount *mp, struct thread *td,
- struct ucred *cred, uint64_t nodeid, uint64_t nlookup);
-
-/* fuse start/stop */
-
-int fuse_internal_init_callback(struct fuse_ticket *tick, struct uio *uio);
-void fuse_internal_send_init(struct fuse_data *data, struct thread *td);
-
-#endif /* _FUSE_INTERNAL_H_ */
Index: sys/fs/fuse/fuse_internal.c
===================================================================
--- sys/fs/fuse/fuse_internal.c
+++ sys/fs/fuse/fuse_internal.c
@@ -1,640 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Copyright (c) 2007-2009 Google Inc. and Amit Singh
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Copyright (C) 2005 Csaba Henk.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/types.h>
-#include <sys/module.h>
-#include <sys/systm.h>
-#include <sys/errno.h>
-#include <sys/param.h>
-#include <sys/kernel.h>
-#include <sys/conf.h>
-#include <sys/uio.h>
-#include <sys/malloc.h>
-#include <sys/queue.h>
-#include <sys/lock.h>
-#include <sys/mutex.h>
-#include <sys/sx.h>
-#include <sys/proc.h>
-#include <sys/mount.h>
-#include <sys/vnode.h>
-#include <sys/namei.h>
-#include <sys/stat.h>
-#include <sys/unistd.h>
-#include <sys/filedesc.h>
-#include <sys/file.h>
-#include <sys/fcntl.h>
-#include <sys/dirent.h>
-#include <sys/bio.h>
-#include <sys/buf.h>
-#include <sys/sysctl.h>
-#include <sys/priv.h>
-
-#include "fuse.h"
-#include "fuse_file.h"
-#include "fuse_internal.h"
-#include "fuse_ipc.h"
-#include "fuse_node.h"
-#include "fuse_file.h"
-#include "fuse_param.h"
-
-#define FUSE_DEBUG_MODULE INTERNAL
-#include "fuse_debug.h"
-
-#ifdef ZERO_PAD_INCOMPLETE_BUFS
-static int isbzero(void *buf, size_t len);
-
-#endif
-
-/* access */
-
-int
-fuse_internal_access(struct vnode *vp,
- mode_t mode,
- struct fuse_access_param *facp,
- struct thread *td,
- struct ucred *cred)
-{
- int err = 0;
- uint32_t mask = 0;
- int dataflags;
- int vtype;
- struct mount *mp;
- struct fuse_dispatcher fdi;
- struct fuse_access_in *fai;
- struct fuse_data *data;
-
- /* NOT YET DONE */
- /*
- * If this vnop gives you trouble, just return 0 here for a lazy
- * kludge.
- */
- /* return 0;*/
-
- fuse_trace_printf_func();
-
- mp = vnode_mount(vp);
- vtype = vnode_vtype(vp);
-
- data = fuse_get_mpdata(mp);
- dataflags = data->dataflags;
-
- if ((mode & VWRITE) && vfs_isrdonly(mp)) {
- return EACCES;
- }
- /* Unless explicitly permitted, deny everyone except the fs owner. */
- if (vnode_isvroot(vp) && !(facp->facc_flags & FACCESS_NOCHECKSPY)) {
- if (!(dataflags & FSESS_DAEMON_CAN_SPY)) {
- int denied = fuse_match_cred(data->daemoncred,
- cred);
-
- if (denied) {
- return EPERM;
- }
- }
- facp->facc_flags |= FACCESS_NOCHECKSPY;
- }
- if (!(facp->facc_flags & FACCESS_DO_ACCESS)) {
- return 0;
- }
- if (((vtype == VREG) && (mode & VEXEC))) {
-#ifdef NEED_MOUNT_ARGUMENT_FOR_THIS
- /* Let the kernel handle this through open / close heuristics.*/
- return ENOTSUP;
-#else
- /* Let the kernel handle this. */
- return 0;
-#endif
- }
- if (!fsess_isimpl(mp, FUSE_ACCESS)) {
- /* Let the kernel handle this. */
- return 0;
- }
- if (dataflags & FSESS_DEFAULT_PERMISSIONS) {
- /* Let the kernel handle this. */
- return 0;
- }
- if ((mode & VADMIN) != 0) {
- err = priv_check_cred(cred, PRIV_VFS_ADMIN);
- if (err) {
- return err;
- }
- }
- if ((mode & (VWRITE | VAPPEND | VADMIN)) != 0) {
- mask |= W_OK;
- }
- if ((mode & VREAD) != 0) {
- mask |= R_OK;
- }
- if ((mode & VEXEC) != 0) {
- mask |= X_OK;
- }
- bzero(&fdi, sizeof(fdi));
-
- fdisp_init(&fdi, sizeof(*fai));
- fdisp_make_vp(&fdi, FUSE_ACCESS, vp, td, cred);
-
- fai = fdi.indata;
- fai->mask = F_OK;
- fai->mask |= mask;
-
- err = fdisp_wait_answ(&fdi);
- fdisp_destroy(&fdi);
-
- if (err == ENOSYS) {
- fsess_set_notimpl(mp, FUSE_ACCESS);
- err = 0;
- }
- return err;
-}
-
-/* fsync */
-
-int
-fuse_internal_fsync_callback(struct fuse_ticket *tick, struct uio *uio)
-{
- fuse_trace_printf_func();
-
- if (tick->tk_aw_ohead.error == ENOSYS) {
- fsess_set_notimpl(tick->tk_data->mp, fticket_opcode(tick));
- }
- return 0;
-}
-
-int
-fuse_internal_fsync(struct vnode *vp,
- struct thread *td,
- struct ucred *cred,
- struct fuse_filehandle *fufh)
-{
- int op = FUSE_FSYNC;
- struct fuse_fsync_in *ffsi;
- struct fuse_dispatcher fdi;
-
- fuse_trace_printf_func();
-
- if (vnode_isdir(vp)) {
- op = FUSE_FSYNCDIR;
- }
- fdisp_init(&fdi, sizeof(*ffsi));
- fdisp_make_vp(&fdi, op, vp, td, cred);
- ffsi = fdi.indata;
- ffsi->fh = fufh->fh_id;
-
- ffsi->fsync_flags = 1; /* datasync */
-
- fuse_insert_callback(fdi.tick, fuse_internal_fsync_callback);
- fuse_insert_message(fdi.tick);
-
- fdisp_destroy(&fdi);
-
- return 0;
-
-}
-
-/* readdir */
-
-int
-fuse_internal_readdir(struct vnode *vp,
- struct uio *uio,
- struct fuse_filehandle *fufh,
- struct fuse_iov *cookediov)
-{
- int err = 0;
- struct fuse_dispatcher fdi;
- struct fuse_read_in *fri;
-
- if (uio_resid(uio) == 0) {
- return 0;
- }
- fdisp_init(&fdi, 0);
-
- /*
- * Note that we DO NOT have a UIO_SYSSPACE here (so no need for p2p
- * I/O).
- */
-
- while (uio_resid(uio) > 0) {
-
- fdi.iosize = sizeof(*fri);
- fdisp_make_vp(&fdi, FUSE_READDIR, vp, NULL, NULL);
-
- fri = fdi.indata;
- fri->fh = fufh->fh_id;
- fri->offset = uio_offset(uio);
- fri->size = min(uio_resid(uio), FUSE_DEFAULT_IOSIZE);
- /* mp->max_read */
-
- if ((err = fdisp_wait_answ(&fdi))) {
- break;
- }
- if ((err = fuse_internal_readdir_processdata(uio, fri->size, fdi.answ,
- fdi.iosize, cookediov))) {
- break;
- }
- }
-
- fdisp_destroy(&fdi);
- return ((err == -1) ? 0 : err);
-}
-
-int
-fuse_internal_readdir_processdata(struct uio *uio,
- size_t reqsize,
- void *buf,
- size_t bufsize,
- void *param)
-{
- int err = 0;
- int cou = 0;
- int bytesavail;
- size_t freclen;
-
- struct dirent *de;
- struct fuse_dirent *fudge;
- struct fuse_iov *cookediov = param;
-
- if (bufsize < FUSE_NAME_OFFSET) {
- return -1;
- }
- for (;;) {
-
- if (bufsize < FUSE_NAME_OFFSET) {
- err = -1;
- break;
- }
- fudge = (struct fuse_dirent *)buf;
- freclen = FUSE_DIRENT_SIZE(fudge);
-
- cou++;
-
- if (bufsize < freclen) {
- err = ((cou == 1) ? -1 : 0);
- break;
- }
-#ifdef ZERO_PAD_INCOMPLETE_BUFS
- if (isbzero(buf, FUSE_NAME_OFFSET)) {
- err = -1;
- break;
- }
-#endif
-
- if (!fudge->namelen || fudge->namelen > MAXNAMLEN) {
- err = EINVAL;
- break;
- }
- bytesavail = GENERIC_DIRSIZ((struct pseudo_dirent *)
- &fudge->namelen);
-
- if (bytesavail > uio_resid(uio)) {
- err = -1;
- break;
- }
- fiov_refresh(cookediov);
- fiov_adjust(cookediov, bytesavail);
-
- de = (struct dirent *)cookediov->base;
- de->d_fileno = fudge->ino;
- de->d_reclen = bytesavail;
- de->d_type = fudge->type;
- de->d_namlen = fudge->namelen;
- memcpy((char *)cookediov->base + sizeof(struct dirent) -
- MAXNAMLEN - 1,
- (char *)buf + FUSE_NAME_OFFSET, fudge->namelen);
- dirent_terminate(de);
-
- err = uiomove(cookediov->base, cookediov->len, uio);
- if (err) {
- break;
- }
- buf = (char *)buf + freclen;
- bufsize -= freclen;
- uio_setoffset(uio, fudge->off);
- }
-
- return err;
-}
-
-/* remove */
-
-int
-fuse_internal_remove(struct vnode *dvp,
- struct vnode *vp,
- struct componentname *cnp,
- enum fuse_opcode op)
-{
- struct fuse_dispatcher fdi;
- struct fuse_vnode_data *fvdat;
- int err;
-
- err = 0;
- fvdat = VTOFUD(vp);
-
- debug_printf("dvp=%p, cnp=%p, op=%d\n", vp, cnp, op);
-
- fdisp_init(&fdi, cnp->cn_namelen + 1);
- fdisp_make_vp(&fdi, op, dvp, cnp->cn_thread, cnp->cn_cred);
-
- memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
- ((char *)fdi.indata)[cnp->cn_namelen] = '\0';
-
- err = fdisp_wait_answ(&fdi);
- fdisp_destroy(&fdi);
- return err;
-}
-
-/* rename */
-
-int
-fuse_internal_rename(struct vnode *fdvp,
- struct componentname *fcnp,
- struct vnode *tdvp,
- struct componentname *tcnp)
-{
- struct fuse_dispatcher fdi;
- struct fuse_rename_in *fri;
- int err = 0;
-
- fdisp_init(&fdi, sizeof(*fri) + fcnp->cn_namelen + tcnp->cn_namelen + 2);
- fdisp_make_vp(&fdi, FUSE_RENAME, fdvp, tcnp->cn_thread, tcnp->cn_cred);
-
- fri = fdi.indata;
- fri->newdir = VTOI(tdvp);
- memcpy((char *)fdi.indata + sizeof(*fri), fcnp->cn_nameptr,
- fcnp->cn_namelen);
- ((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen] = '\0';
- memcpy((char *)fdi.indata + sizeof(*fri) + fcnp->cn_namelen + 1,
- tcnp->cn_nameptr, tcnp->cn_namelen);
- ((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen +
- tcnp->cn_namelen + 1] = '\0';
-
- err = fdisp_wait_answ(&fdi);
- fdisp_destroy(&fdi);
- return err;
-}
-
-/* strategy */
-
-/* entity creation */
-
-void
-fuse_internal_newentry_makerequest(struct mount *mp,
- uint64_t dnid,
- struct componentname *cnp,
- enum fuse_opcode op,
- void *buf,
- size_t bufsize,
- struct fuse_dispatcher *fdip)
-{
- debug_printf("fdip=%p\n", fdip);
-
- fdip->iosize = bufsize + cnp->cn_namelen + 1;
-
- fdisp_make(fdip, op, mp, dnid, cnp->cn_thread, cnp->cn_cred);
- memcpy(fdip->indata, buf, bufsize);
- memcpy((char *)fdip->indata + bufsize, cnp->cn_nameptr, cnp->cn_namelen);
- ((char *)fdip->indata)[bufsize + cnp->cn_namelen] = '\0';
-}
-
-int
-fuse_internal_newentry_core(struct vnode *dvp,
- struct vnode **vpp,
- struct componentname *cnp,
- enum vtype vtyp,
- struct fuse_dispatcher *fdip)
-{
- int err = 0;
- struct fuse_entry_out *feo;
- struct mount *mp = vnode_mount(dvp);
-
- if ((err = fdisp_wait_answ(fdip))) {
- return err;
- }
- feo = fdip->answ;
-
- if ((err = fuse_internal_checkentry(feo, vtyp))) {
- return err;
- }
- err = fuse_vnode_get(mp, feo, feo->nodeid, dvp, vpp, cnp, vtyp);
- if (err) {
- fuse_internal_forget_send(mp, cnp->cn_thread, cnp->cn_cred,
- feo->nodeid, 1);
- return err;
- }
- cache_attrs(*vpp, feo, NULL);
-
- return err;
-}
-
-int
-fuse_internal_newentry(struct vnode *dvp,
- struct vnode **vpp,
- struct componentname *cnp,
- enum fuse_opcode op,
- void *buf,
- size_t bufsize,
- enum vtype vtype)
-{
- int err;
- struct fuse_dispatcher fdi;
- struct mount *mp = vnode_mount(dvp);
-
- fdisp_init(&fdi, 0);
- fuse_internal_newentry_makerequest(mp, VTOI(dvp), cnp, op, buf,
- bufsize, &fdi);
- err = fuse_internal_newentry_core(dvp, vpp, cnp, vtype, &fdi);
- fdisp_destroy(&fdi);
-
- return err;
-}
-
-/* entity destruction */
-
-int
-fuse_internal_forget_callback(struct fuse_ticket *ftick, struct uio *uio)
-{
- fuse_internal_forget_send(ftick->tk_data->mp, curthread, NULL,
- ((struct fuse_in_header *)ftick->tk_ms_fiov.base)->nodeid, 1);
-
- return 0;
-}
-
-void
-fuse_internal_forget_send(struct mount *mp,
- struct thread *td,
- struct ucred *cred,
- uint64_t nodeid,
- uint64_t nlookup)
-{
-
- struct fuse_dispatcher fdi;
- struct fuse_forget_in *ffi;
-
- debug_printf("mp=%p, nodeid=%ju, nlookup=%ju\n",
- mp, (uintmax_t)nodeid, (uintmax_t)nlookup);
-
- /*
- * KASSERT(nlookup > 0, ("zero-times forget for vp #%llu",
- * (long long unsigned) nodeid));
- */
-
- fdisp_init(&fdi, sizeof(*ffi));
- fdisp_make(&fdi, FUSE_FORGET, mp, nodeid, td, cred);
-
- ffi = fdi.indata;
- ffi->nlookup = nlookup;
-
- fuse_insert_message(fdi.tick);
- fdisp_destroy(&fdi);
-}
-
-void
-fuse_internal_vnode_disappear(struct vnode *vp)
-{
- struct fuse_vnode_data *fvdat = VTOFUD(vp);
-
- ASSERT_VOP_ELOCKED(vp, "fuse_internal_vnode_disappear");
- fvdat->flag |= FN_REVOKED;
- fvdat->valid_attr_cache = false;
- cache_purge(vp);
-}
-
-/* fuse start/stop */
-
-int
-fuse_internal_init_callback(struct fuse_ticket *tick, struct uio *uio)
-{
- int err = 0;
- struct fuse_data *data = tick->tk_data;
- struct fuse_init_out *fiio;
-
- if ((err = tick->tk_aw_ohead.error)) {
- goto out;
- }
- if ((err = fticket_pull(tick, uio))) {
- goto out;
- }
- fiio = fticket_resp(tick)->base;
-
- /* XXX: Do we want to check anything further besides this? */
- if (fiio->major < 7) {
- debug_printf("userpace version too low\n");
- err = EPROTONOSUPPORT;
- goto out;
- }
- data->fuse_libabi_major = fiio->major;
- data->fuse_libabi_minor = fiio->minor;
-
- if (fuse_libabi_geq(data, 7, 5)) {
- if (fticket_resp(tick)->len == sizeof(struct fuse_init_out)) {
- data->max_write = fiio->max_write;
- } else {
- err = EINVAL;
- }
- } else {
- /* Old fix values */
- data->max_write = 4096;
- }
-
-out:
- if (err) {
- fdata_set_dead(data);
- }
- FUSE_LOCK();
- data->dataflags |= FSESS_INITED;
- wakeup(&data->ticketer);
- FUSE_UNLOCK();
-
- return 0;
-}
-
-void
-fuse_internal_send_init(struct fuse_data *data, struct thread *td)
-{
- struct fuse_init_in *fiii;
- struct fuse_dispatcher fdi;
-
- fdisp_init(&fdi, sizeof(*fiii));
- fdisp_make(&fdi, FUSE_INIT, data->mp, 0, td, NULL);
- fiii = fdi.indata;
- fiii->major = FUSE_KERNEL_VERSION;
- fiii->minor = FUSE_KERNEL_MINOR_VERSION;
- fiii->max_readahead = FUSE_DEFAULT_IOSIZE * 16;
- fiii->flags = 0;
-
- fuse_insert_callback(fdi.tick, fuse_internal_init_callback);
- fuse_insert_message(fdi.tick);
- fdisp_destroy(&fdi);
-}
-
-#ifdef ZERO_PAD_INCOMPLETE_BUFS
-static int
-isbzero(void *buf, size_t len)
-{
- int i;
-
- for (i = 0; i < len; i++) {
- if (((char *)buf)[i])
- return (0);
- }
-
- return (1);
-}
-
-#endif
Index: sys/fs/fuse/fuse_io.h
===================================================================
--- sys/fs/fuse/fuse_io.h
+++ sys/fs/fuse/fuse_io.h
@@ -1,69 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Copyright (c) 2007-2009 Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Copyright (C) 2005 Csaba Henk.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#ifndef _FUSE_IO_H_
-#define _FUSE_IO_H_
-
-int fuse_io_dispatch(struct vnode *vp, struct uio *uio, int ioflag,
- struct ucred *cred);
-int fuse_io_strategy(struct vnode *vp, struct buf *bp);
-int fuse_io_flushbuf(struct vnode *vp, int waitfor, struct thread *td);
-int fuse_io_invalbuf(struct vnode *vp, struct thread *td);
-
-#endif /* _FUSE_IO_H_ */
Index: sys/fs/fuse/fuse_io.c
===================================================================
--- sys/fs/fuse/fuse_io.c
+++ sys/fs/fuse/fuse_io.c
@@ -1,824 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Copyright (c) 2007-2009 Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Copyright (C) 2005 Csaba Henk.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/types.h>
-#include <sys/module.h>
-#include <sys/systm.h>
-#include <sys/errno.h>
-#include <sys/param.h>
-#include <sys/kernel.h>
-#include <sys/conf.h>
-#include <sys/uio.h>
-#include <sys/malloc.h>
-#include <sys/queue.h>
-#include <sys/lock.h>
-#include <sys/sx.h>
-#include <sys/mutex.h>
-#include <sys/rwlock.h>
-#include <sys/proc.h>
-#include <sys/mount.h>
-#include <sys/vnode.h>
-#include <sys/stat.h>
-#include <sys/unistd.h>
-#include <sys/filedesc.h>
-#include <sys/file.h>
-#include <sys/fcntl.h>
-#include <sys/bio.h>
-#include <sys/buf.h>
-#include <sys/sysctl.h>
-
-#include <vm/vm.h>
-#include <vm/vm_extern.h>
-#include <vm/pmap.h>
-#include <vm/vm_map.h>
-#include <vm/vm_page.h>
-#include <vm/vm_object.h>
-
-#include "fuse.h"
-#include "fuse_file.h"
-#include "fuse_node.h"
-#include "fuse_internal.h"
-#include "fuse_ipc.h"
-#include "fuse_io.h"
-
-#define FUSE_DEBUG_MODULE IO
-#include "fuse_debug.h"
-
-
-static int
-fuse_read_directbackend(struct vnode *vp, struct uio *uio,
- struct ucred *cred, struct fuse_filehandle *fufh);
-static int
-fuse_read_biobackend(struct vnode *vp, struct uio *uio,
- struct ucred *cred, struct fuse_filehandle *fufh);
-static int
-fuse_write_directbackend(struct vnode *vp, struct uio *uio,
- struct ucred *cred, struct fuse_filehandle *fufh, int ioflag);
-static int
-fuse_write_biobackend(struct vnode *vp, struct uio *uio,
- struct ucred *cred, struct fuse_filehandle *fufh, int ioflag);
-
-int
-fuse_io_dispatch(struct vnode *vp, struct uio *uio, int ioflag,
- struct ucred *cred)
-{
- struct fuse_filehandle *fufh;
- int err, directio;
-
- MPASS(vp->v_type == VREG || vp->v_type == VDIR);
-
- err = fuse_filehandle_getrw(vp,
- (uio->uio_rw == UIO_READ) ? FUFH_RDONLY : FUFH_WRONLY, &fufh);
- if (err) {
- printf("FUSE: io dispatch: filehandles are closed\n");
- return err;
- }
- /*
- * Ideally, when the daemon asks for direct io at open time, the
- * standard file flag should be set according to this, so that would
- * just change the default mode, which later on could be changed via
- * fcntl(2).
- * But this doesn't work, the O_DIRECT flag gets cleared at some point
- * (don't know where). So to make any use of the Fuse direct_io option,
- * we hardwire it into the file's private data (similarly to Linux,
- * btw.).
- */
- directio = (ioflag & IO_DIRECT) || !fsess_opt_datacache(vnode_mount(vp));
-
- switch (uio->uio_rw) {
- case UIO_READ:
- if (directio) {
- FS_DEBUG("direct read of vnode %ju via file handle %ju\n",
- (uintmax_t)VTOILLU(vp), (uintmax_t)fufh->fh_id);
- err = fuse_read_directbackend(vp, uio, cred, fufh);
- } else {
- FS_DEBUG("buffered read of vnode %ju\n",
- (uintmax_t)VTOILLU(vp));
- err = fuse_read_biobackend(vp, uio, cred, fufh);
- }
- break;
- case UIO_WRITE:
- /*
- * Kludge: simulate write-through caching via write-around
- * caching. Same effect, as far as never caching dirty data,
- * but slightly pessimal in that newly written data is not
- * cached.
- */
- if (directio || fuse_data_cache_mode == FUSE_CACHE_WT) {
- FS_DEBUG("direct write of vnode %ju via file handle %ju\n",
- (uintmax_t)VTOILLU(vp), (uintmax_t)fufh->fh_id);
- err = fuse_write_directbackend(vp, uio, cred, fufh, ioflag);
- } else {
- FS_DEBUG("buffered write of vnode %ju\n",
- (uintmax_t)VTOILLU(vp));
- err = fuse_write_biobackend(vp, uio, cred, fufh, ioflag);
- }
- break;
- default:
- panic("uninterpreted mode passed to fuse_io_dispatch");
- }
-
- return (err);
-}
-
-static int
-fuse_read_biobackend(struct vnode *vp, struct uio *uio,
- struct ucred *cred, struct fuse_filehandle *fufh)
-{
- struct buf *bp;
- daddr_t lbn;
- int bcount;
- int err = 0, n = 0, on = 0;
- off_t filesize;
-
- const int biosize = fuse_iosize(vp);
-
- FS_DEBUG("resid=%zx offset=%jx fsize=%jx\n",
- uio->uio_resid, uio->uio_offset, VTOFUD(vp)->filesize);
-
- if (uio->uio_resid == 0)
- return (0);
- if (uio->uio_offset < 0)
- return (EINVAL);
-
- bcount = biosize;
- filesize = VTOFUD(vp)->filesize;
-
- do {
- if (fuse_isdeadfs(vp)) {
- err = ENXIO;
- break;
- }
- lbn = uio->uio_offset / biosize;
- on = uio->uio_offset & (biosize - 1);
-
- FS_DEBUG2G("biosize %d, lbn %d, on %d\n", biosize, (int)lbn, on);
-
- /*
- * Obtain the buffer cache block. Figure out the buffer size
- * when we are at EOF. If we are modifying the size of the
- * buffer based on an EOF condition we need to hold
- * nfs_rslock() through obtaining the buffer to prevent
- * a potential writer-appender from messing with n_size.
- * Otherwise we may accidentally truncate the buffer and
- * lose dirty data.
- *
- * Note that bcount is *not* DEV_BSIZE aligned.
- */
- if ((off_t)lbn * biosize >= filesize) {
- bcount = 0;
- } else if ((off_t)(lbn + 1) * biosize > filesize) {
- bcount = filesize - (off_t)lbn *biosize;
- }
- bp = getblk(vp, lbn, bcount, PCATCH, 0, 0);
-
- if (!bp)
- return (EINTR);
-
- /*
- * If B_CACHE is not set, we must issue the read. If this
- * fails, we return an error.
- */
-
- if ((bp->b_flags & B_CACHE) == 0) {
- bp->b_iocmd = BIO_READ;
- vfs_busy_pages(bp, 0);
- err = fuse_io_strategy(vp, bp);
- if (err) {
- brelse(bp);
- return (err);
- }
- }
- /*
- * on is the offset into the current bp. Figure out how many
- * bytes we can copy out of the bp. Note that bcount is
- * NOT DEV_BSIZE aligned.
- *
- * Then figure out how many bytes we can copy into the uio.
- */
-
- n = 0;
- if (on < bcount)
- n = MIN((unsigned)(bcount - on), uio->uio_resid);
- if (n > 0) {
- FS_DEBUG2G("feeding buffeater with %d bytes of buffer %p,"
- " saying %d was asked for\n",
- n, bp->b_data + on, n + (int)bp->b_resid);
- err = uiomove(bp->b_data + on, n, uio);
- }
- brelse(bp);
- FS_DEBUG2G("end of turn, err %d, uio->uio_resid %zd, n %d\n",
- err, uio->uio_resid, n);
- } while (err == 0 && uio->uio_resid > 0 && n > 0);
-
- return (err);
-}
-
-static int
-fuse_read_directbackend(struct vnode *vp, struct uio *uio,
- struct ucred *cred, struct fuse_filehandle *fufh)
-{
- struct fuse_dispatcher fdi;
- struct fuse_read_in *fri;
- int err = 0;
-
- if (uio->uio_resid == 0)
- return (0);
-
- fdisp_init(&fdi, 0);
-
- /*
- * XXX In "normal" case we use an intermediate kernel buffer for
- * transmitting data from daemon's context to ours. Eventually, we should
- * get rid of this. Anyway, if the target uio lives in sysspace (we are
- * called from pageops), and the input data doesn't need kernel-side
- * processing (we are not called from readdir) we can already invoke
- * an optimized, "peer-to-peer" I/O routine.
- */
- while (uio->uio_resid > 0) {
- fdi.iosize = sizeof(*fri);
- fdisp_make_vp(&fdi, FUSE_READ, vp, uio->uio_td, cred);
- fri = fdi.indata;
- fri->fh = fufh->fh_id;
- fri->offset = uio->uio_offset;
- fri->size = MIN(uio->uio_resid,
- fuse_get_mpdata(vp->v_mount)->max_read);
-
- FS_DEBUG2G("fri->fh %ju, fri->offset %ju, fri->size %ju\n",
- (uintmax_t)fri->fh, (uintmax_t)fri->offset,
- (uintmax_t)fri->size);
-
- if ((err = fdisp_wait_answ(&fdi)))
- goto out;
-
- FS_DEBUG2G("complete: got iosize=%d, requested fri.size=%zd; "
- "resid=%zd offset=%ju\n",
- fri->size, fdi.iosize, uio->uio_resid,
- (uintmax_t)uio->uio_offset);
-
- if ((err = uiomove(fdi.answ, MIN(fri->size, fdi.iosize), uio)))
- break;
- if (fdi.iosize < fri->size)
- break;
- }
-
-out:
- fdisp_destroy(&fdi);
- return (err);
-}
-
-static int
-fuse_write_directbackend(struct vnode *vp, struct uio *uio,
- struct ucred *cred, struct fuse_filehandle *fufh, int ioflag)
-{
- struct fuse_vnode_data *fvdat = VTOFUD(vp);
- struct fuse_write_in *fwi;
- struct fuse_dispatcher fdi;
- size_t chunksize;
- int diff;
- int err = 0;
-
- if (uio->uio_resid == 0)
- return (0);
- if (ioflag & IO_APPEND)
- uio_setoffset(uio, fvdat->filesize);
-
- fdisp_init(&fdi, 0);
-
- while (uio->uio_resid > 0) {
- chunksize = MIN(uio->uio_resid,
- fuse_get_mpdata(vp->v_mount)->max_write);
-
- fdi.iosize = sizeof(*fwi) + chunksize;
- fdisp_make_vp(&fdi, FUSE_WRITE, vp, uio->uio_td, cred);
-
- fwi = fdi.indata;
- fwi->fh = fufh->fh_id;
- fwi->offset = uio->uio_offset;
- fwi->size = chunksize;
-
- if ((err = uiomove((char *)fdi.indata + sizeof(*fwi),
- chunksize, uio)))
- break;
-
- if ((err = fdisp_wait_answ(&fdi)))
- break;
-
- diff = chunksize - ((struct fuse_write_out *)fdi.answ)->size;
- if (diff < 0) {
- err = EINVAL;
- break;
- }
- uio->uio_resid += diff;
- uio->uio_offset -= diff;
- if (uio->uio_offset > fvdat->filesize &&
- fuse_data_cache_mode != FUSE_CACHE_UC) {
- fuse_vnode_setsize(vp, cred, uio->uio_offset);
- fvdat->flag &= ~FN_SIZECHANGE;
- }
- }
-
- fdisp_destroy(&fdi);
-
- return (err);
-}
-
-static int
-fuse_write_biobackend(struct vnode *vp, struct uio *uio,
- struct ucred *cred, struct fuse_filehandle *fufh, int ioflag)
-{
- struct fuse_vnode_data *fvdat = VTOFUD(vp);
- struct buf *bp;
- daddr_t lbn;
- int bcount;
- int n, on, err = 0;
-
- const int biosize = fuse_iosize(vp);
-
- KASSERT(uio->uio_rw == UIO_WRITE, ("ncl_write mode"));
- FS_DEBUG("resid=%zx offset=%jx fsize=%jx\n",
- uio->uio_resid, uio->uio_offset, fvdat->filesize);
- if (vp->v_type != VREG)
- return (EIO);
- if (uio->uio_offset < 0)
- return (EINVAL);
- if (uio->uio_resid == 0)
- return (0);
- if (ioflag & IO_APPEND)
- uio_setoffset(uio, fvdat->filesize);
-
- /*
- * Find all of this file's B_NEEDCOMMIT buffers. If our writes
- * would exceed the local maximum per-file write commit size when
- * combined with those, we must decide whether to flush,
- * go synchronous, or return err. We don't bother checking
- * IO_UNIT -- we just make all writes atomic anyway, as there's
- * no point optimizing for something that really won't ever happen.
- */
- do {
- if (fuse_isdeadfs(vp)) {
- err = ENXIO;
- break;
- }
- lbn = uio->uio_offset / biosize;
- on = uio->uio_offset & (biosize - 1);
- n = MIN((unsigned)(biosize - on), uio->uio_resid);
-
- FS_DEBUG2G("lbn %ju, on %d, n %d, uio offset %ju, uio resid %zd\n",
- (uintmax_t)lbn, on, n,
- (uintmax_t)uio->uio_offset, uio->uio_resid);
-
-again:
- /*
- * Handle direct append and file extension cases, calculate
- * unaligned buffer size.
- */
- if (uio->uio_offset == fvdat->filesize && n) {
- /*
- * Get the buffer (in its pre-append state to maintain
- * B_CACHE if it was previously set). Resize the
- * nfsnode after we have locked the buffer to prevent
- * readers from reading garbage.
- */
- bcount = on;
- FS_DEBUG("getting block from OS, bcount %d\n", bcount);
- bp = getblk(vp, lbn, bcount, PCATCH, 0, 0);
-
- if (bp != NULL) {
- long save;
-
- err = fuse_vnode_setsize(vp, cred,
- uio->uio_offset + n);
- if (err) {
- brelse(bp);
- break;
- }
- save = bp->b_flags & B_CACHE;
- bcount += n;
- allocbuf(bp, bcount);
- bp->b_flags |= save;
- }
- } else {
- /*
- * Obtain the locked cache block first, and then
- * adjust the file's size as appropriate.
- */
- bcount = on + n;
- if ((off_t)lbn * biosize + bcount < fvdat->filesize) {
- if ((off_t)(lbn + 1) * biosize < fvdat->filesize)
- bcount = biosize;
- else
- bcount = fvdat->filesize -
- (off_t)lbn *biosize;
- }
- FS_DEBUG("getting block from OS, bcount %d\n", bcount);
- bp = getblk(vp, lbn, bcount, PCATCH, 0, 0);
- if (bp && uio->uio_offset + n > fvdat->filesize) {
- err = fuse_vnode_setsize(vp, cred,
- uio->uio_offset + n);
- if (err) {
- brelse(bp);
- break;
- }
- }
- }
-
- if (!bp) {
- err = EINTR;
- break;
- }
- /*
- * Issue a READ if B_CACHE is not set. In special-append
- * mode, B_CACHE is based on the buffer prior to the write
- * op and is typically set, avoiding the read. If a read
- * is required in special append mode, the server will
- * probably send us a short-read since we extended the file
- * on our end, resulting in b_resid == 0 and, thusly,
- * B_CACHE getting set.
- *
- * We can also avoid issuing the read if the write covers
- * the entire buffer. We have to make sure the buffer state
- * is reasonable in this case since we will not be initiating
- * I/O. See the comments in kern/vfs_bio.c's getblk() for
- * more information.
- *
- * B_CACHE may also be set due to the buffer being cached
- * normally.
- */
-
- if (on == 0 && n == bcount) {
- bp->b_flags |= B_CACHE;
- bp->b_flags &= ~B_INVAL;
- bp->b_ioflags &= ~BIO_ERROR;
- }
- if ((bp->b_flags & B_CACHE) == 0) {
- bp->b_iocmd = BIO_READ;
- vfs_busy_pages(bp, 0);
- fuse_io_strategy(vp, bp);
- if ((err = bp->b_error)) {
- brelse(bp);
- break;
- }
- }
- if (bp->b_wcred == NOCRED)
- bp->b_wcred = crhold(cred);
-
- /*
- * If dirtyend exceeds file size, chop it down. This should
- * not normally occur but there is an append race where it
- * might occur XXX, so we log it.
- *
- * If the chopping creates a reverse-indexed or degenerate
- * situation with dirtyoff/end, we 0 both of them.
- */
-
- if (bp->b_dirtyend > bcount) {
- FS_DEBUG("FUSE append race @%lx:%d\n",
- (long)bp->b_blkno * biosize,
- bp->b_dirtyend - bcount);
- bp->b_dirtyend = bcount;
- }
- if (bp->b_dirtyoff >= bp->b_dirtyend)
- bp->b_dirtyoff = bp->b_dirtyend = 0;
-
- /*
- * If the new write will leave a contiguous dirty
- * area, just update the b_dirtyoff and b_dirtyend,
- * otherwise force a write rpc of the old dirty area.
- *
- * While it is possible to merge discontiguous writes due to
- * our having a B_CACHE buffer ( and thus valid read data
- * for the hole), we don't because it could lead to
- * significant cache coherency problems with multiple clients,
- * especially if locking is implemented later on.
- *
- * as an optimization we could theoretically maintain
- * a linked list of discontinuous areas, but we would still
- * have to commit them separately so there isn't much
- * advantage to it except perhaps a bit of asynchronization.
- */
-
- if (bp->b_dirtyend > 0 &&
- (on > bp->b_dirtyend || (on + n) < bp->b_dirtyoff)) {
- /*
- * Yes, we mean it. Write out everything to "storage"
- * immediately, without hesitation. (Apart from other
- * reasons: the only way to know if a write is valid
- * if its actually written out.)
- */
- bwrite(bp);
- if (bp->b_error == EINTR) {
- err = EINTR;
- break;
- }
- goto again;
- }
- err = uiomove((char *)bp->b_data + on, n, uio);
-
- /*
- * Since this block is being modified, it must be written
- * again and not just committed. Since write clustering does
- * not work for the stage 1 data write, only the stage 2
- * commit rpc, we have to clear B_CLUSTEROK as well.
- */
- bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK);
-
- if (err) {
- bp->b_ioflags |= BIO_ERROR;
- bp->b_error = err;
- brelse(bp);
- break;
- }
- /*
- * Only update dirtyoff/dirtyend if not a degenerate
- * condition.
- */
- if (n) {
- if (bp->b_dirtyend > 0) {
- bp->b_dirtyoff = MIN(on, bp->b_dirtyoff);
- bp->b_dirtyend = MAX((on + n), bp->b_dirtyend);
- } else {
- bp->b_dirtyoff = on;
- bp->b_dirtyend = on + n;
- }
- vfs_bio_set_valid(bp, on, n);
- }
- err = bwrite(bp);
- if (err)
- break;
- } while (uio->uio_resid > 0 && n > 0);
-
- if (fuse_sync_resize && (fvdat->flag & FN_SIZECHANGE) != 0)
- fuse_vnode_savesize(vp, cred);
-
- return (err);
-}
-
-int
-fuse_io_strategy(struct vnode *vp, struct buf *bp)
-{
- struct fuse_filehandle *fufh;
- struct fuse_vnode_data *fvdat = VTOFUD(vp);
- struct ucred *cred;
- struct uio *uiop;
- struct uio uio;
- struct iovec io;
- int error = 0;
-
- const int biosize = fuse_iosize(vp);
-
- MPASS(vp->v_type == VREG || vp->v_type == VDIR);
- MPASS(bp->b_iocmd == BIO_READ || bp->b_iocmd == BIO_WRITE);
- FS_DEBUG("inode=%ju offset=%jd resid=%ld\n",
- (uintmax_t)VTOI(vp), (intmax_t)(((off_t)bp->b_blkno) * biosize),
- bp->b_bcount);
-
- error = fuse_filehandle_getrw(vp,
- (bp->b_iocmd == BIO_READ) ? FUFH_RDONLY : FUFH_WRONLY, &fufh);
- if (error) {
- printf("FUSE: strategy: filehandles are closed\n");
- bp->b_ioflags |= BIO_ERROR;
- bp->b_error = error;
- return (error);
- }
- cred = bp->b_iocmd == BIO_READ ? bp->b_rcred : bp->b_wcred;
-
- uiop = &uio;
- uiop->uio_iov = &io;
- uiop->uio_iovcnt = 1;
- uiop->uio_segflg = UIO_SYSSPACE;
- uiop->uio_td = curthread;
-
- /*
- * clear BIO_ERROR and B_INVAL state prior to initiating the I/O. We
- * do this here so we do not have to do it in all the code that
- * calls us.
- */
- bp->b_flags &= ~B_INVAL;
- bp->b_ioflags &= ~BIO_ERROR;
-
- KASSERT(!(bp->b_flags & B_DONE),
- ("fuse_io_strategy: bp %p already marked done", bp));
- if (bp->b_iocmd == BIO_READ) {
- io.iov_len = uiop->uio_resid = bp->b_bcount;
- io.iov_base = bp->b_data;
- uiop->uio_rw = UIO_READ;
-
- uiop->uio_offset = ((off_t)bp->b_blkno) * biosize;
- error = fuse_read_directbackend(vp, uiop, cred, fufh);
-
- /* XXXCEM: Potentially invalid access to cached_attrs here */
- if ((!error && uiop->uio_resid) ||
- (fsess_opt_brokenio(vnode_mount(vp)) && error == EIO &&
- uiop->uio_offset < fvdat->filesize && fvdat->filesize > 0 &&
- uiop->uio_offset >= fvdat->cached_attrs.va_size)) {
- /*
- * If we had a short read with no error, we must have
- * hit a file hole. We should zero-fill the remainder.
- * This can also occur if the server hits the file EOF.
- *
- * Holes used to be able to occur due to pending
- * writes, but that is not possible any longer.
- */
- int nread = bp->b_bcount - uiop->uio_resid;
- int left = uiop->uio_resid;
-
- if (error != 0) {
- printf("FUSE: Fix broken io: offset %ju, "
- " resid %zd, file size %ju/%ju\n",
- (uintmax_t)uiop->uio_offset,
- uiop->uio_resid, fvdat->filesize,
- fvdat->cached_attrs.va_size);
- error = 0;
- }
- if (left > 0)
- bzero((char *)bp->b_data + nread, left);
- uiop->uio_resid = 0;
- }
- if (error) {
- bp->b_ioflags |= BIO_ERROR;
- bp->b_error = error;
- }
- } else {
- /*
- * If we only need to commit, try to commit
- */
- if (bp->b_flags & B_NEEDCOMMIT) {
- FS_DEBUG("write: B_NEEDCOMMIT flags set\n");
- }
- /*
- * Setup for actual write
- */
- if ((off_t)bp->b_blkno * biosize + bp->b_dirtyend >
- fvdat->filesize)
- bp->b_dirtyend = fvdat->filesize -
- (off_t)bp->b_blkno * biosize;
-
- if (bp->b_dirtyend > bp->b_dirtyoff) {
- io.iov_len = uiop->uio_resid = bp->b_dirtyend
- - bp->b_dirtyoff;
- uiop->uio_offset = (off_t)bp->b_blkno * biosize
- + bp->b_dirtyoff;
- io.iov_base = (char *)bp->b_data + bp->b_dirtyoff;
- uiop->uio_rw = UIO_WRITE;
-
- error = fuse_write_directbackend(vp, uiop, cred, fufh, 0);
-
- if (error == EINTR || error == ETIMEDOUT
- || (!error && (bp->b_flags & B_NEEDCOMMIT))) {
-
- bp->b_flags &= ~(B_INVAL | B_NOCACHE);
- if ((bp->b_flags & B_PAGING) == 0) {
- bdirty(bp);
- bp->b_flags &= ~B_DONE;
- }
- if ((error == EINTR || error == ETIMEDOUT) &&
- (bp->b_flags & B_ASYNC) == 0)
- bp->b_flags |= B_EINTR;
- } else {
- if (error) {
- bp->b_ioflags |= BIO_ERROR;
- bp->b_flags |= B_INVAL;
- bp->b_error = error;
- }
- bp->b_dirtyoff = bp->b_dirtyend = 0;
- }
- } else {
- bp->b_resid = 0;
- bufdone(bp);
- return (0);
- }
- }
- bp->b_resid = uiop->uio_resid;
- bufdone(bp);
- return (error);
-}
-
-int
-fuse_io_flushbuf(struct vnode *vp, int waitfor, struct thread *td)
-{
- struct vop_fsync_args a = {
- .a_vp = vp,
- .a_waitfor = waitfor,
- .a_td = td,
- };
-
- return (vop_stdfsync(&a));
-}
-
-/*
- * Flush and invalidate all dirty buffers. If another process is already
- * doing the flush, just wait for completion.
- */
-int
-fuse_io_invalbuf(struct vnode *vp, struct thread *td)
-{
- struct fuse_vnode_data *fvdat = VTOFUD(vp);
- int error = 0;
-
- if (vp->v_iflag & VI_DOOMED)
- return 0;
-
- ASSERT_VOP_ELOCKED(vp, "fuse_io_invalbuf");
-
- while (fvdat->flag & FN_FLUSHINPROG) {
- struct proc *p = td->td_proc;
-
- if (vp->v_mount->mnt_kern_flag & MNTK_UNMOUNTF)
- return EIO;
- fvdat->flag |= FN_FLUSHWANT;
- tsleep(&fvdat->flag, PRIBIO + 2, "fusevinv", 2 * hz);
- error = 0;
- if (p != NULL) {
- PROC_LOCK(p);
- if (SIGNOTEMPTY(p->p_siglist) ||
- SIGNOTEMPTY(td->td_siglist))
- error = EINTR;
- PROC_UNLOCK(p);
- }
- if (error == EINTR)
- return EINTR;
- }
- fvdat->flag |= FN_FLUSHINPROG;
-
- if (vp->v_bufobj.bo_object != NULL) {
- VM_OBJECT_WLOCK(vp->v_bufobj.bo_object);
- vm_object_page_clean(vp->v_bufobj.bo_object, 0, 0, OBJPC_SYNC);
- VM_OBJECT_WUNLOCK(vp->v_bufobj.bo_object);
- }
- error = vinvalbuf(vp, V_SAVE, PCATCH, 0);
- while (error) {
- if (error == ERESTART || error == EINTR) {
- fvdat->flag &= ~FN_FLUSHINPROG;
- if (fvdat->flag & FN_FLUSHWANT) {
- fvdat->flag &= ~FN_FLUSHWANT;
- wakeup(&fvdat->flag);
- }
- return EINTR;
- }
- error = vinvalbuf(vp, V_SAVE, PCATCH, 0);
- }
- fvdat->flag &= ~FN_FLUSHINPROG;
- if (fvdat->flag & FN_FLUSHWANT) {
- fvdat->flag &= ~FN_FLUSHWANT;
- wakeup(&fvdat->flag);
- }
- return (error);
-}
Index: sys/fs/fuse/fuse_ipc.h
===================================================================
--- sys/fs/fuse/fuse_ipc.h
+++ sys/fs/fuse/fuse_ipc.h
@@ -1,412 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Copyright (c) 2007-2009 Google Inc. and Amit Singh
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Copyright (C) 2005 Csaba Henk.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#ifndef _FUSE_IPC_H_
-#define _FUSE_IPC_H_
-
-#include <sys/param.h>
-#include <sys/refcount.h>
-
-struct fuse_iov {
- void *base;
- size_t len;
- size_t allocated_size;
- int credit;
-};
-
-void fiov_init(struct fuse_iov *fiov, size_t size);
-void fiov_teardown(struct fuse_iov *fiov);
-void fiov_refresh(struct fuse_iov *fiov);
-void fiov_adjust(struct fuse_iov *fiov, size_t size);
-
-#define FUSE_DIMALLOC(fiov, spc1, spc2, amnt) do { \
- fiov_adjust(fiov, (sizeof(*(spc1)) + (amnt))); \
- (spc1) = (fiov)->base; \
- (spc2) = (char *)(fiov)->base + (sizeof(*(spc1))); \
-} while (0)
-
-#define FU_AT_LEAST(siz) max((siz), 160)
-
-#define FUSE_ASSERT_AW_DONE(ftick) \
- KASSERT((ftick)->tk_aw_link.tqe_next == NULL && \
- (ftick)->tk_aw_link.tqe_prev == NULL, \
- ("FUSE: ticket still on answer delivery list %p", (ftick)))
-
-#define FUSE_ASSERT_MS_DONE(ftick) \
- KASSERT((ftick)->tk_ms_link.stqe_next == NULL, \
- ("FUSE: ticket still on message list %p", (ftick)))
-
-struct fuse_ticket;
-struct fuse_data;
-
-typedef int fuse_handler_t(struct fuse_ticket *ftick, struct uio *uio);
-
-struct fuse_ticket {
- /* fields giving the identity of the ticket */
- uint64_t tk_unique;
- struct fuse_data *tk_data;
- int tk_flag;
- u_int tk_refcount;
-
- /* fields for initiating an upgoing message */
- struct fuse_iov tk_ms_fiov;
- void *tk_ms_bufdata;
- size_t tk_ms_bufsize;
- enum { FT_M_FIOV, FT_M_BUF } tk_ms_type;
- STAILQ_ENTRY(fuse_ticket) tk_ms_link;
-
- /* fields for handling answers coming from userspace */
- struct fuse_iov tk_aw_fiov;
- void *tk_aw_bufdata;
- size_t tk_aw_bufsize;
- enum { FT_A_FIOV, FT_A_BUF } tk_aw_type;
-
- struct fuse_out_header tk_aw_ohead;
- int tk_aw_errno;
- struct mtx tk_aw_mtx;
- fuse_handler_t *tk_aw_handler;
- TAILQ_ENTRY(fuse_ticket) tk_aw_link;
-};
-
-#define FT_ANSW 0x01 /* request of ticket has already been answered */
-#define FT_DIRTY 0x04 /* ticket has been used */
-
-static inline struct fuse_iov *
-fticket_resp(struct fuse_ticket *ftick)
-{
- return (&ftick->tk_aw_fiov);
-}
-
-static inline bool
-fticket_answered(struct fuse_ticket *ftick)
-{
- DEBUGX(FUSE_DEBUG_IPC, "-> ftick=%p\n", ftick);
- mtx_assert(&ftick->tk_aw_mtx, MA_OWNED);
- return (ftick->tk_flag & FT_ANSW);
-}
-
-static inline void
-fticket_set_answered(struct fuse_ticket *ftick)
-{
- DEBUGX(FUSE_DEBUG_IPC, "-> ftick=%p\n", ftick);
- mtx_assert(&ftick->tk_aw_mtx, MA_OWNED);
- ftick->tk_flag |= FT_ANSW;
-}
-
-static inline enum fuse_opcode
-fticket_opcode(struct fuse_ticket *ftick)
-{
- DEBUGX(FUSE_DEBUG_IPC, "-> ftick=%p\n", ftick);
- return (((struct fuse_in_header *)(ftick->tk_ms_fiov.base))->opcode);
-}
-
-int fticket_pull(struct fuse_ticket *ftick, struct uio *uio);
-
-enum mountpri { FM_NOMOUNTED, FM_PRIMARY, FM_SECONDARY };
-
-/*
- * The data representing a FUSE session.
- */
-struct fuse_data {
- struct cdev *fdev;
- struct mount *mp;
- struct vnode *vroot;
- struct ucred *daemoncred;
- int dataflags;
- int ref;
-
- struct mtx ms_mtx;
- STAILQ_HEAD(, fuse_ticket) ms_head;
-
- struct mtx aw_mtx;
- TAILQ_HEAD(, fuse_ticket) aw_head;
-
- u_long ticketer;
-
- struct sx rename_lock;
-
- uint32_t fuse_libabi_major;
- uint32_t fuse_libabi_minor;
-
- uint32_t max_write;
- uint32_t max_read;
- uint32_t subtype;
- char volname[MAXPATHLEN];
-
- struct selinfo ks_rsel;
-
- int daemon_timeout;
- uint64_t notimpl;
-};
-
-#define FSESS_DEAD 0x0001 /* session is to be closed */
-#define FSESS_UNUSED0 0x0002 /* unused */
-#define FSESS_INITED 0x0004 /* session has been inited */
-#define FSESS_DAEMON_CAN_SPY 0x0010 /* let non-owners access this fs */
- /* (and being observed by the daemon) */
-#define FSESS_PUSH_SYMLINKS_IN 0x0020 /* prefix absolute symlinks with mp */
-#define FSESS_DEFAULT_PERMISSIONS 0x0040 /* kernel does permission checking */
-#define FSESS_NO_ATTRCACHE 0x0080 /* no attribute caching */
-#define FSESS_NO_READAHEAD 0x0100 /* no readaheads */
-#define FSESS_NO_DATACACHE 0x0200 /* disable buffer cache */
-#define FSESS_NO_NAMECACHE 0x0400 /* disable name cache */
-#define FSESS_NO_MMAP 0x0800 /* disable mmap */
-#define FSESS_BROKENIO 0x1000 /* fix broken io */
-
-enum fuse_data_cache_mode {
- FUSE_CACHE_UC,
- FUSE_CACHE_WT,
- FUSE_CACHE_WB,
-};
-
-extern int fuse_data_cache_mode;
-extern int fuse_data_cache_invalidate;
-extern int fuse_mmap_enable;
-extern int fuse_sync_resize;
-extern int fuse_fix_broken_io;
-
-static inline struct fuse_data *
-fuse_get_mpdata(struct mount *mp)
-{
- return mp->mnt_data;
-}
-
-static inline bool
-fsess_isimpl(struct mount *mp, int opcode)
-{
- struct fuse_data *data = fuse_get_mpdata(mp);
-
- return ((data->notimpl & (1ULL << opcode)) == 0);
-
-}
-static inline void
-fsess_set_notimpl(struct mount *mp, int opcode)
-{
- struct fuse_data *data = fuse_get_mpdata(mp);
-
- data->notimpl |= (1ULL << opcode);
-}
-
-static inline bool
-fsess_opt_datacache(struct mount *mp)
-{
- struct fuse_data *data = fuse_get_mpdata(mp);
-
- return (fuse_data_cache_mode != FUSE_CACHE_UC &&
- (data->dataflags & FSESS_NO_DATACACHE) == 0);
-}
-
-static inline bool
-fsess_opt_mmap(struct mount *mp)
-{
- struct fuse_data *data = fuse_get_mpdata(mp);
-
- if (!fuse_mmap_enable || fuse_data_cache_mode == FUSE_CACHE_UC)
- return (false);
- return ((data->dataflags & (FSESS_NO_DATACACHE | FSESS_NO_MMAP)) == 0);
-}
-
-static inline bool
-fsess_opt_brokenio(struct mount *mp)
-{
- struct fuse_data *data = fuse_get_mpdata(mp);
-
- return (fuse_fix_broken_io || (data->dataflags & FSESS_BROKENIO));
-}
-
-static inline void
-fuse_ms_push(struct fuse_ticket *ftick)
-{
- DEBUGX(FUSE_DEBUG_IPC, "ftick=%p refcount=%d\n", ftick,
- ftick->tk_refcount + 1);
- mtx_assert(&ftick->tk_data->ms_mtx, MA_OWNED);
- refcount_acquire(&ftick->tk_refcount);
- STAILQ_INSERT_TAIL(&ftick->tk_data->ms_head, ftick, tk_ms_link);
-}
-
-static inline struct fuse_ticket *
-fuse_ms_pop(struct fuse_data *data)
-{
- struct fuse_ticket *ftick = NULL;
-
- mtx_assert(&data->ms_mtx, MA_OWNED);
-
- if ((ftick = STAILQ_FIRST(&data->ms_head))) {
- STAILQ_REMOVE_HEAD(&data->ms_head, tk_ms_link);
-#ifdef INVARIANTS
- ftick->tk_ms_link.stqe_next = NULL;
-#endif
- }
- DEBUGX(FUSE_DEBUG_IPC, "ftick=%p refcount=%d\n", ftick,
- ftick ? ftick->tk_refcount : -1);
-
- return (ftick);
-}
-
-static inline void
-fuse_aw_push(struct fuse_ticket *ftick)
-{
- DEBUGX(FUSE_DEBUG_IPC, "ftick=%p refcount=%d\n", ftick,
- ftick->tk_refcount + 1);
- mtx_assert(&ftick->tk_data->aw_mtx, MA_OWNED);
- refcount_acquire(&ftick->tk_refcount);
- TAILQ_INSERT_TAIL(&ftick->tk_data->aw_head, ftick, tk_aw_link);
-}
-
-static inline void
-fuse_aw_remove(struct fuse_ticket *ftick)
-{
- DEBUGX(FUSE_DEBUG_IPC, "ftick=%p refcount=%d\n",
- ftick, ftick->tk_refcount);
- mtx_assert(&ftick->tk_data->aw_mtx, MA_OWNED);
- TAILQ_REMOVE(&ftick->tk_data->aw_head, ftick, tk_aw_link);
-#ifdef INVARIANTS
- ftick->tk_aw_link.tqe_next = NULL;
- ftick->tk_aw_link.tqe_prev = NULL;
-#endif
-}
-
-static inline struct fuse_ticket *
-fuse_aw_pop(struct fuse_data *data)
-{
- struct fuse_ticket *ftick;
-
- mtx_assert(&data->aw_mtx, MA_OWNED);
-
- if ((ftick = TAILQ_FIRST(&data->aw_head)) != NULL)
- fuse_aw_remove(ftick);
- DEBUGX(FUSE_DEBUG_IPC, "ftick=%p refcount=%d\n", ftick,
- ftick ? ftick->tk_refcount : -1);
-
- return (ftick);
-}
-
-struct fuse_ticket *fuse_ticket_fetch(struct fuse_data *data);
-int fuse_ticket_drop(struct fuse_ticket *ftick);
-void fuse_insert_callback(struct fuse_ticket *ftick, fuse_handler_t *handler);
-void fuse_insert_message(struct fuse_ticket *ftick);
-
-static inline bool
-fuse_libabi_geq(struct fuse_data *data, uint32_t abi_maj, uint32_t abi_min)
-{
- return (data->fuse_libabi_major > abi_maj ||
- (data->fuse_libabi_major == abi_maj &&
- data->fuse_libabi_minor >= abi_min));
-}
-
-struct fuse_data *fdata_alloc(struct cdev *dev, struct ucred *cred);
-void fdata_trydestroy(struct fuse_data *data);
-void fdata_set_dead(struct fuse_data *data);
-
-static inline bool
-fdata_get_dead(struct fuse_data *data)
-{
- return (data->dataflags & FSESS_DEAD);
-}
-
-struct fuse_dispatcher {
- struct fuse_ticket *tick;
- struct fuse_in_header *finh;
-
- void *indata;
- size_t iosize;
- uint64_t nodeid;
- int answ_stat;
- void *answ;
-};
-
-static inline void
-fdisp_init(struct fuse_dispatcher *fdisp, size_t iosize)
-{
- DEBUGX(FUSE_DEBUG_IPC, "-> fdisp=%p, iosize=%zx\n", fdisp, iosize);
- fdisp->iosize = iosize;
- fdisp->tick = NULL;
-}
-
-static inline void
-fdisp_destroy(struct fuse_dispatcher *fdisp)
-{
- DEBUGX(FUSE_DEBUG_IPC, "-> fdisp=%p, ftick=%p\n", fdisp, fdisp->tick);
- fuse_ticket_drop(fdisp->tick);
-#ifdef INVARIANTS
- fdisp->tick = NULL;
-#endif
-}
-
-void fdisp_make(struct fuse_dispatcher *fdip, enum fuse_opcode op,
- struct mount *mp, uint64_t nid, struct thread *td, struct ucred *cred);
-
-void fdisp_make_pid(struct fuse_dispatcher *fdip, enum fuse_opcode op,
- struct mount *mp, uint64_t nid, pid_t pid, struct ucred *cred);
-
-void fdisp_make_vp(struct fuse_dispatcher *fdip, enum fuse_opcode op,
- struct vnode *vp, struct thread *td, struct ucred *cred);
-
-int fdisp_wait_answ(struct fuse_dispatcher *fdip);
-
-static inline int
-fdisp_simple_putget_vp(struct fuse_dispatcher *fdip, enum fuse_opcode op,
- struct vnode *vp, struct thread *td, struct ucred *cred)
-{
- DEBUGX(FUSE_DEBUG_IPC, "-> fdip=%p, opcode=%d, vp=%p\n", fdip, op, vp);
- fdisp_make_vp(fdip, op, vp, td, cred);
- return (fdisp_wait_answ(fdip));
-}
-
-#endif /* _FUSE_IPC_H_ */
Index: sys/fs/fuse/fuse_ipc.c
===================================================================
--- sys/fs/fuse/fuse_ipc.c
+++ sys/fs/fuse/fuse_ipc.c
@@ -1,880 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Copyright (c) 2007-2009 Google Inc. and Amit Singh
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Copyright (C) 2005 Csaba Henk.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/types.h>
-#include <sys/module.h>
-#include <sys/systm.h>
-#include <sys/errno.h>
-#include <sys/param.h>
-#include <sys/kernel.h>
-#include <sys/conf.h>
-#include <sys/uio.h>
-#include <sys/malloc.h>
-#include <sys/queue.h>
-#include <sys/lock.h>
-#include <sys/sx.h>
-#include <sys/mutex.h>
-#include <sys/proc.h>
-#include <sys/mount.h>
-#include <sys/vnode.h>
-#include <sys/signalvar.h>
-#include <sys/syscallsubr.h>
-#include <sys/sysctl.h>
-#include <vm/uma.h>
-
-#include "fuse.h"
-#include "fuse_node.h"
-#include "fuse_ipc.h"
-#include "fuse_internal.h"
-
-#define FUSE_DEBUG_MODULE IPC
-#include "fuse_debug.h"
-
-static struct fuse_ticket *fticket_alloc(struct fuse_data *data);
-static void fticket_refresh(struct fuse_ticket *ftick);
-static void fticket_destroy(struct fuse_ticket *ftick);
-static int fticket_wait_answer(struct fuse_ticket *ftick);
-static inline int
-fticket_aw_pull_uio(struct fuse_ticket *ftick,
- struct uio *uio);
-
-static int fuse_body_audit(struct fuse_ticket *ftick, size_t blen);
-
-static fuse_handler_t fuse_standard_handler;
-
-SYSCTL_NODE(_vfs, OID_AUTO, fuse, CTLFLAG_RW, 0, "FUSE tunables");
-SYSCTL_STRING(_vfs_fuse, OID_AUTO, version, CTLFLAG_RD,
- FUSE_FREEBSD_VERSION, 0, "fuse-freebsd version");
-static int fuse_ticket_count = 0;
-
-SYSCTL_INT(_vfs_fuse, OID_AUTO, ticket_count, CTLFLAG_RW,
- &fuse_ticket_count, 0, "number of allocated tickets");
-static long fuse_iov_permanent_bufsize = 1 << 19;
-
-SYSCTL_LONG(_vfs_fuse, OID_AUTO, iov_permanent_bufsize, CTLFLAG_RW,
- &fuse_iov_permanent_bufsize, 0,
- "limit for permanently stored buffer size for fuse_iovs");
-static int fuse_iov_credit = 16;
-
-SYSCTL_INT(_vfs_fuse, OID_AUTO, iov_credit, CTLFLAG_RW,
- &fuse_iov_credit, 0,
- "how many times is an oversized fuse_iov tolerated");
-
-MALLOC_DEFINE(M_FUSEMSG, "fuse_msgbuf", "fuse message buffer");
-static uma_zone_t ticket_zone;
-
-static void
-fuse_block_sigs(sigset_t *oldset)
-{
- sigset_t newset;
-
- SIGFILLSET(newset);
- SIGDELSET(newset, SIGKILL);
- if (kern_sigprocmask(curthread, SIG_BLOCK, &newset, oldset, 0))
- panic("%s: Invalid operation for kern_sigprocmask()",
- __func__);
-}
-
-static void
-fuse_restore_sigs(sigset_t *oldset)
-{
-
- if (kern_sigprocmask(curthread, SIG_SETMASK, oldset, NULL, 0))
- panic("%s: Invalid operation for kern_sigprocmask()",
- __func__);
-}
-
-void
-fiov_init(struct fuse_iov *fiov, size_t size)
-{
- uint32_t msize = FU_AT_LEAST(size);
-
- debug_printf("fiov=%p, size=%zd\n", fiov, size);
-
- fiov->len = 0;
-
- fiov->base = malloc(msize, M_FUSEMSG, M_WAITOK | M_ZERO);
-
- fiov->allocated_size = msize;
- fiov->credit = fuse_iov_credit;
-}
-
-void
-fiov_teardown(struct fuse_iov *fiov)
-{
- debug_printf("fiov=%p\n", fiov);
-
- MPASS(fiov->base != NULL);
- free(fiov->base, M_FUSEMSG);
-}
-
-void
-fiov_adjust(struct fuse_iov *fiov, size_t size)
-{
- debug_printf("fiov=%p, size=%zd\n", fiov, size);
-
- if (fiov->allocated_size < size ||
- (fuse_iov_permanent_bufsize >= 0 &&
- fiov->allocated_size - size > fuse_iov_permanent_bufsize &&
- --fiov->credit < 0)) {
-
- fiov->base = realloc(fiov->base, FU_AT_LEAST(size), M_FUSEMSG,
- M_WAITOK | M_ZERO);
- if (!fiov->base) {
- panic("FUSE: realloc failed");
- }
- fiov->allocated_size = FU_AT_LEAST(size);
- fiov->credit = fuse_iov_credit;
- }
- fiov->len = size;
-}
-
-void
-fiov_refresh(struct fuse_iov *fiov)
-{
- debug_printf("fiov=%p\n", fiov);
-
- bzero(fiov->base, fiov->len);
- fiov_adjust(fiov, 0);
-}
-
-static int
-fticket_ctor(void *mem, int size, void *arg, int flags)
-{
- struct fuse_ticket *ftick = mem;
- struct fuse_data *data = arg;
-
- debug_printf("ftick=%p data=%p\n", ftick, data);
-
- FUSE_ASSERT_MS_DONE(ftick);
- FUSE_ASSERT_AW_DONE(ftick);
-
- ftick->tk_data = data;
-
- if (ftick->tk_unique != 0)
- fticket_refresh(ftick);
-
- /* May be truncated to 32 bits */
- ftick->tk_unique = atomic_fetchadd_long(&data->ticketer, 1);
- if (ftick->tk_unique == 0)
- ftick->tk_unique = atomic_fetchadd_long(&data->ticketer, 1);
-
- refcount_init(&ftick->tk_refcount, 1);
- atomic_add_acq_int(&fuse_ticket_count, 1);
-
- return 0;
-}
-
-static void
-fticket_dtor(void *mem, int size, void *arg)
-{
- struct fuse_ticket *ftick = mem;
-
- debug_printf("ftick=%p\n", ftick);
-
- FUSE_ASSERT_MS_DONE(ftick);
- FUSE_ASSERT_AW_DONE(ftick);
-
- atomic_subtract_acq_int(&fuse_ticket_count, 1);
-}
-
-static int
-fticket_init(void *mem, int size, int flags)
-{
- struct fuse_ticket *ftick = mem;
-
- FS_DEBUG("ftick=%p\n", ftick);
-
- bzero(ftick, sizeof(struct fuse_ticket));
-
- fiov_init(&ftick->tk_ms_fiov, sizeof(struct fuse_in_header));
- ftick->tk_ms_type = FT_M_FIOV;
-
- mtx_init(&ftick->tk_aw_mtx, "fuse answer delivery mutex", NULL, MTX_DEF);
- fiov_init(&ftick->tk_aw_fiov, 0);
- ftick->tk_aw_type = FT_A_FIOV;
-
- return 0;
-}
-
-static void
-fticket_fini(void *mem, int size)
-{
- struct fuse_ticket *ftick = mem;
-
- FS_DEBUG("ftick=%p\n", ftick);
-
- fiov_teardown(&ftick->tk_ms_fiov);
- fiov_teardown(&ftick->tk_aw_fiov);
- mtx_destroy(&ftick->tk_aw_mtx);
-}
-
-static inline struct fuse_ticket *
-fticket_alloc(struct fuse_data *data)
-{
- return uma_zalloc_arg(ticket_zone, data, M_WAITOK);
-}
-
-static inline void
-fticket_destroy(struct fuse_ticket *ftick)
-{
- return uma_zfree(ticket_zone, ftick);
-}
-
-static inline
-void
-fticket_refresh(struct fuse_ticket *ftick)
-{
- debug_printf("ftick=%p\n", ftick);
-
- FUSE_ASSERT_MS_DONE(ftick);
- FUSE_ASSERT_AW_DONE(ftick);
-
- fiov_refresh(&ftick->tk_ms_fiov);
- ftick->tk_ms_bufdata = NULL;
- ftick->tk_ms_bufsize = 0;
- ftick->tk_ms_type = FT_M_FIOV;
-
- bzero(&ftick->tk_aw_ohead, sizeof(struct fuse_out_header));
-
- fiov_refresh(&ftick->tk_aw_fiov);
- ftick->tk_aw_errno = 0;
- ftick->tk_aw_bufdata = NULL;
- ftick->tk_aw_bufsize = 0;
- ftick->tk_aw_type = FT_A_FIOV;
-
- ftick->tk_flag = 0;
-}
-
-static int
-fticket_wait_answer(struct fuse_ticket *ftick)
-{
- sigset_t tset;
- int err = 0;
- struct fuse_data *data;
-
- debug_printf("ftick=%p\n", ftick);
- fuse_lck_mtx_lock(ftick->tk_aw_mtx);
-
- if (fticket_answered(ftick)) {
- goto out;
- }
- data = ftick->tk_data;
-
- if (fdata_get_dead(data)) {
- err = ENOTCONN;
- fticket_set_answered(ftick);
- goto out;
- }
- fuse_block_sigs(&tset);
- err = msleep(ftick, &ftick->tk_aw_mtx, PCATCH, "fu_ans",
- data->daemon_timeout * hz);
- fuse_restore_sigs(&tset);
- if (err == EAGAIN) { /* same as EWOULDBLOCK */
-#ifdef XXXIP /* die conditionally */
- if (!fdata_get_dead(data)) {
- fdata_set_dead(data);
- }
-#endif
- err = ETIMEDOUT;
- fticket_set_answered(ftick);
- }
-out:
- if (!(err || fticket_answered(ftick))) {
- debug_printf("FUSE: requester was woken up but still no answer");
- err = ENXIO;
- }
- fuse_lck_mtx_unlock(ftick->tk_aw_mtx);
-
- return err;
-}
-
-static inline
-int
-fticket_aw_pull_uio(struct fuse_ticket *ftick, struct uio *uio)
-{
- int err = 0;
- size_t len = uio_resid(uio);
-
- debug_printf("ftick=%p, uio=%p\n", ftick, uio);
-
- if (len) {
- switch (ftick->tk_aw_type) {
- case FT_A_FIOV:
- fiov_adjust(fticket_resp(ftick), len);
- err = uiomove(fticket_resp(ftick)->base, len, uio);
- if (err) {
- debug_printf("FUSE: FT_A_FIOV: error is %d"
- " (%p, %zd, %p)\n",
- err, fticket_resp(ftick)->base,
- len, uio);
- }
- break;
-
- case FT_A_BUF:
- ftick->tk_aw_bufsize = len;
- err = uiomove(ftick->tk_aw_bufdata, len, uio);
- if (err) {
- debug_printf("FUSE: FT_A_BUF: error is %d"
- " (%p, %zd, %p)\n",
- err, ftick->tk_aw_bufdata, len, uio);
- }
- break;
-
- default:
- panic("FUSE: unknown answer type for ticket %p", ftick);
- }
- }
- return err;
-}
-
-int
-fticket_pull(struct fuse_ticket *ftick, struct uio *uio)
-{
- int err = 0;
-
- debug_printf("ftick=%p, uio=%p\n", ftick, uio);
-
- if (ftick->tk_aw_ohead.error) {
- return 0;
- }
- err = fuse_body_audit(ftick, uio_resid(uio));
- if (!err) {
- err = fticket_aw_pull_uio(ftick, uio);
- }
- return err;
-}
-
-struct fuse_data *
-fdata_alloc(struct cdev *fdev, struct ucred *cred)
-{
- struct fuse_data *data;
-
- debug_printf("fdev=%p\n", fdev);
-
- data = malloc(sizeof(struct fuse_data), M_FUSEMSG, M_WAITOK | M_ZERO);
-
- data->fdev = fdev;
- mtx_init(&data->ms_mtx, "fuse message list mutex", NULL, MTX_DEF);
- STAILQ_INIT(&data->ms_head);
- mtx_init(&data->aw_mtx, "fuse answer list mutex", NULL, MTX_DEF);
- TAILQ_INIT(&data->aw_head);
- data->daemoncred = crhold(cred);
- data->daemon_timeout = FUSE_DEFAULT_DAEMON_TIMEOUT;
- sx_init(&data->rename_lock, "fuse rename lock");
- data->ref = 1;
-
- return data;
-}
-
-void
-fdata_trydestroy(struct fuse_data *data)
-{
- FS_DEBUG("data=%p data.mp=%p data.fdev=%p data.flags=%04x\n",
- data, data->mp, data->fdev, data->dataflags);
-
- FS_DEBUG("destroy: data=%p\n", data);
- data->ref--;
- MPASS(data->ref >= 0);
- if (data->ref != 0)
- return;
-
- /* Driving off stage all that stuff thrown at device... */
- mtx_destroy(&data->ms_mtx);
- mtx_destroy(&data->aw_mtx);
- sx_destroy(&data->rename_lock);
-
- crfree(data->daemoncred);
-
- free(data, M_FUSEMSG);
-}
-
-void
-fdata_set_dead(struct fuse_data *data)
-{
- debug_printf("data=%p\n", data);
-
- FUSE_LOCK();
- if (fdata_get_dead(data)) {
- FUSE_UNLOCK();
- return;
- }
- fuse_lck_mtx_lock(data->ms_mtx);
- data->dataflags |= FSESS_DEAD;
- wakeup_one(data);
- selwakeuppri(&data->ks_rsel, PZERO + 1);
- wakeup(&data->ticketer);
- fuse_lck_mtx_unlock(data->ms_mtx);
- FUSE_UNLOCK();
-}
-
-struct fuse_ticket *
-fuse_ticket_fetch(struct fuse_data *data)
-{
- int err = 0;
- struct fuse_ticket *ftick;
-
- debug_printf("data=%p\n", data);
-
- ftick = fticket_alloc(data);
-
- if (!(data->dataflags & FSESS_INITED)) {
- /* Sleep until get answer for INIT messsage */
- FUSE_LOCK();
- if (!(data->dataflags & FSESS_INITED) && data->ticketer > 2) {
- err = msleep(&data->ticketer, &fuse_mtx, PCATCH | PDROP,
- "fu_ini", 0);
- if (err)
- fdata_set_dead(data);
- } else
- FUSE_UNLOCK();
- }
- return ftick;
-}
-
-int
-fuse_ticket_drop(struct fuse_ticket *ftick)
-{
- int die;
-
- die = refcount_release(&ftick->tk_refcount);
- debug_printf("ftick=%p refcount=%d\n", ftick, ftick->tk_refcount);
- if (die)
- fticket_destroy(ftick);
-
- return die;
-}
-
-void
-fuse_insert_callback(struct fuse_ticket *ftick, fuse_handler_t * handler)
-{
- debug_printf("ftick=%p, handler=%p data=%p\n", ftick, ftick->tk_data,
- handler);
-
- if (fdata_get_dead(ftick->tk_data)) {
- return;
- }
- ftick->tk_aw_handler = handler;
-
- fuse_lck_mtx_lock(ftick->tk_data->aw_mtx);
- fuse_aw_push(ftick);
- fuse_lck_mtx_unlock(ftick->tk_data->aw_mtx);
-}
-
-void
-fuse_insert_message(struct fuse_ticket *ftick)
-{
- debug_printf("ftick=%p\n", ftick);
-
- if (ftick->tk_flag & FT_DIRTY) {
- panic("FUSE: ticket reused without being refreshed");
- }
- ftick->tk_flag |= FT_DIRTY;
-
- if (fdata_get_dead(ftick->tk_data)) {
- return;
- }
- fuse_lck_mtx_lock(ftick->tk_data->ms_mtx);
- fuse_ms_push(ftick);
- wakeup_one(ftick->tk_data);
- selwakeuppri(&ftick->tk_data->ks_rsel, PZERO + 1);
- fuse_lck_mtx_unlock(ftick->tk_data->ms_mtx);
-}
-
-static int
-fuse_body_audit(struct fuse_ticket *ftick, size_t blen)
-{
- int err = 0;
- enum fuse_opcode opcode;
-
- debug_printf("ftick=%p, blen = %zu\n", ftick, blen);
-
- opcode = fticket_opcode(ftick);
-
- switch (opcode) {
- case FUSE_LOOKUP:
- err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL;
- break;
-
- case FUSE_FORGET:
- panic("FUSE: a handler has been intalled for FUSE_FORGET");
- break;
-
- case FUSE_GETATTR:
- err = (blen == sizeof(struct fuse_attr_out)) ? 0 : EINVAL;
- break;
-
- case FUSE_SETATTR:
- err = (blen == sizeof(struct fuse_attr_out)) ? 0 : EINVAL;
- break;
-
- case FUSE_READLINK:
- err = (PAGE_SIZE >= blen) ? 0 : EINVAL;
- break;
-
- case FUSE_SYMLINK:
- err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL;
- break;
-
- case FUSE_MKNOD:
- err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL;
- break;
-
- case FUSE_MKDIR:
- err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL;
- break;
-
- case FUSE_UNLINK:
- err = (blen == 0) ? 0 : EINVAL;
- break;
-
- case FUSE_RMDIR:
- err = (blen == 0) ? 0 : EINVAL;
- break;
-
- case FUSE_RENAME:
- err = (blen == 0) ? 0 : EINVAL;
- break;
-
- case FUSE_LINK:
- err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL;
- break;
-
- case FUSE_OPEN:
- err = (blen == sizeof(struct fuse_open_out)) ? 0 : EINVAL;
- break;
-
- case FUSE_READ:
- err = (((struct fuse_read_in *)(
- (char *)ftick->tk_ms_fiov.base +
- sizeof(struct fuse_in_header)
- ))->size >= blen) ? 0 : EINVAL;
- break;
-
- case FUSE_WRITE:
- err = (blen == sizeof(struct fuse_write_out)) ? 0 : EINVAL;
- break;
-
- case FUSE_STATFS:
- if (fuse_libabi_geq(ftick->tk_data, 7, 4)) {
- err = (blen == sizeof(struct fuse_statfs_out)) ?
- 0 : EINVAL;
- } else {
- err = (blen == FUSE_COMPAT_STATFS_SIZE) ? 0 : EINVAL;
- }
- break;
-
- case FUSE_RELEASE:
- err = (blen == 0) ? 0 : EINVAL;
- break;
-
- case FUSE_FSYNC:
- err = (blen == 0) ? 0 : EINVAL;
- break;
-
- case FUSE_SETXATTR:
- err = (blen == 0) ? 0 : EINVAL;
- break;
-
- case FUSE_GETXATTR:
- case FUSE_LISTXATTR:
- /*
- * These can have varying response lengths, and 0 length
- * isn't necessarily invalid.
- */
- err = 0;
- break;
-
- case FUSE_REMOVEXATTR:
- err = (blen == 0) ? 0 : EINVAL;
- break;
-
- case FUSE_FLUSH:
- err = (blen == 0) ? 0 : EINVAL;
- break;
-
- case FUSE_INIT:
- if (blen == sizeof(struct fuse_init_out) || blen == 8) {
- err = 0;
- } else {
- err = EINVAL;
- }
- break;
-
- case FUSE_OPENDIR:
- err = (blen == sizeof(struct fuse_open_out)) ? 0 : EINVAL;
- break;
-
- case FUSE_READDIR:
- err = (((struct fuse_read_in *)(
- (char *)ftick->tk_ms_fiov.base +
- sizeof(struct fuse_in_header)
- ))->size >= blen) ? 0 : EINVAL;
- break;
-
- case FUSE_RELEASEDIR:
- err = (blen == 0) ? 0 : EINVAL;
- break;
-
- case FUSE_FSYNCDIR:
- err = (blen == 0) ? 0 : EINVAL;
- break;
-
- case FUSE_GETLK:
- panic("FUSE: no response body format check for FUSE_GETLK");
- break;
-
- case FUSE_SETLK:
- panic("FUSE: no response body format check for FUSE_SETLK");
- break;
-
- case FUSE_SETLKW:
- panic("FUSE: no response body format check for FUSE_SETLKW");
- break;
-
- case FUSE_ACCESS:
- err = (blen == 0) ? 0 : EINVAL;
- break;
-
- case FUSE_CREATE:
- err = (blen == sizeof(struct fuse_entry_out) +
- sizeof(struct fuse_open_out)) ? 0 : EINVAL;
- break;
-
- case FUSE_DESTROY:
- err = (blen == 0) ? 0 : EINVAL;
- break;
-
- default:
- panic("FUSE: opcodes out of sync (%d)\n", opcode);
- }
-
- return err;
-}
-
-static inline void
-fuse_setup_ihead(struct fuse_in_header *ihead, struct fuse_ticket *ftick,
- uint64_t nid, enum fuse_opcode op, size_t blen, pid_t pid,
- struct ucred *cred)
-{
- ihead->len = sizeof(*ihead) + blen;
- ihead->unique = ftick->tk_unique;
- ihead->nodeid = nid;
- ihead->opcode = op;
-
- debug_printf("ihead=%p, ftick=%p, nid=%ju, op=%d, blen=%zu\n",
- ihead, ftick, (uintmax_t)nid, op, blen);
-
- ihead->pid = pid;
- ihead->uid = cred->cr_uid;
- ihead->gid = cred->cr_rgid;
-}
-
-/*
- * fuse_standard_handler just pulls indata and wakes up pretender.
- * Doesn't try to interpret data, that's left for the pretender.
- * Though might do a basic size verification before the pull-in takes place
- */
-
-static int
-fuse_standard_handler(struct fuse_ticket *ftick, struct uio *uio)
-{
- int err = 0;
-
- debug_printf("ftick=%p, uio=%p\n", ftick, uio);
-
- err = fticket_pull(ftick, uio);
-
- fuse_lck_mtx_lock(ftick->tk_aw_mtx);
-
- if (!fticket_answered(ftick)) {
- fticket_set_answered(ftick);
- ftick->tk_aw_errno = err;
- wakeup(ftick);
- }
- fuse_lck_mtx_unlock(ftick->tk_aw_mtx);
-
- return err;
-}
-
-void
-fdisp_make_pid(struct fuse_dispatcher *fdip, enum fuse_opcode op,
- struct mount *mp, uint64_t nid, pid_t pid, struct ucred *cred)
-{
- struct fuse_data *data = fuse_get_mpdata(mp);
-
- debug_printf("fdip=%p, op=%d, mp=%p, nid=%ju\n",
- fdip, op, mp, (uintmax_t)nid);
-
- if (fdip->tick) {
- fticket_refresh(fdip->tick);
- } else {
- fdip->tick = fuse_ticket_fetch(data);
- }
-
- FUSE_DIMALLOC(&fdip->tick->tk_ms_fiov, fdip->finh,
- fdip->indata, fdip->iosize);
-
- fuse_setup_ihead(fdip->finh, fdip->tick, nid, op, fdip->iosize, pid, cred);
-}
-
-void
-fdisp_make(struct fuse_dispatcher *fdip, enum fuse_opcode op, struct mount *mp,
- uint64_t nid, struct thread *td, struct ucred *cred)
-{
- RECTIFY_TDCR(td, cred);
-
- return fdisp_make_pid(fdip, op, mp, nid, td->td_proc->p_pid, cred);
-}
-
-void
-fdisp_make_vp(struct fuse_dispatcher *fdip, enum fuse_opcode op,
- struct vnode *vp, struct thread *td, struct ucred *cred)
-{
- debug_printf("fdip=%p, op=%d, vp=%p\n", fdip, op, vp);
- RECTIFY_TDCR(td, cred);
- return fdisp_make_pid(fdip, op, vnode_mount(vp), VTOI(vp),
- td->td_proc->p_pid, cred);
-}
-
-int
-fdisp_wait_answ(struct fuse_dispatcher *fdip)
-{
- int err = 0;
-
- fdip->answ_stat = 0;
- fuse_insert_callback(fdip->tick, fuse_standard_handler);
- fuse_insert_message(fdip->tick);
-
- if ((err = fticket_wait_answer(fdip->tick))) {
- debug_printf("IPC: interrupted, err = %d\n", err);
-
- fuse_lck_mtx_lock(fdip->tick->tk_aw_mtx);
-
- if (fticket_answered(fdip->tick)) {
- /*
- * Just between noticing the interrupt and getting here,
- * the standard handler has completed his job.
- * So we drop the ticket and exit as usual.
- */
- debug_printf("IPC: already answered\n");
- fuse_lck_mtx_unlock(fdip->tick->tk_aw_mtx);
- goto out;
- } else {
- /*
- * So we were faster than the standard handler.
- * Then by setting the answered flag we get *him*
- * to drop the ticket.
- */
- debug_printf("IPC: setting to answered\n");
- fticket_set_answered(fdip->tick);
- fuse_lck_mtx_unlock(fdip->tick->tk_aw_mtx);
- return err;
- }
- }
- debug_printf("IPC: not interrupted, err = %d\n", err);
-
- if (fdip->tick->tk_aw_errno) {
- debug_printf("IPC: explicit EIO-ing, tk_aw_errno = %d\n",
- fdip->tick->tk_aw_errno);
- err = EIO;
- goto out;
- }
- if ((err = fdip->tick->tk_aw_ohead.error)) {
- debug_printf("IPC: setting status to %d\n",
- fdip->tick->tk_aw_ohead.error);
- /*
- * This means a "proper" fuse syscall error.
- * We record this value so the caller will
- * be able to know it's not a boring messaging
- * failure, if she wishes so (and if not, she can
- * just simply propagate the return value of this routine).
- * [XXX Maybe a bitflag would do the job too,
- * if other flags needed, this will be converted thusly.]
- */
- fdip->answ_stat = err;
- goto out;
- }
- fdip->answ = fticket_resp(fdip->tick)->base;
- fdip->iosize = fticket_resp(fdip->tick)->len;
-
- debug_printf("IPC: all is well\n");
-
- return 0;
-
-out:
- debug_printf("IPC: dropping ticket, err = %d\n", err);
-
- return err;
-}
-
-void
-fuse_ipc_init(void)
-{
- ticket_zone = uma_zcreate("fuse_ticket", sizeof(struct fuse_ticket),
- fticket_ctor, fticket_dtor, fticket_init, fticket_fini,
- UMA_ALIGN_PTR, 0);
-}
-
-void
-fuse_ipc_destroy(void)
-{
- uma_zdestroy(ticket_zone);
-}
Index: sys/fs/fuse/fuse_kernel.h
===================================================================
--- sys/fs/fuse/fuse_kernel.h
+++ sys/fs/fuse/fuse_kernel.h
@@ -1,383 +0,0 @@
-/*--
- * This file defines the kernel interface of FUSE
- * Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
- *
- * This program can be distributed under the terms of the GNU GPL.
- * See the file COPYING.
- *
- * This -- and only this -- header file may also be distributed under
- * the terms of the BSD Licence as follows:
- *
- * Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#ifndef linux
-#include <sys/types.h>
-#define __u64 uint64_t
-#define __u32 uint32_t
-#define __s32 int32_t
-#else
-#include <asm/types.h>
-#include <linux/major.h>
-#endif
-
-/** Version number of this interface */
-#define FUSE_KERNEL_VERSION 7
-
-/** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 8
-
-/** The node ID of the root inode */
-#define FUSE_ROOT_ID 1
-
-/** The major number of the fuse character device */
-#define FUSE_MAJOR MISC_MAJOR
-
-/** The minor number of the fuse character device */
-#define FUSE_MINOR 229
-
-/* Make sure all structures are padded to 64bit boundary, so 32bit
- userspace works under 64bit kernels */
-
-struct fuse_attr {
- __u64 ino;
- __u64 size;
- __u64 blocks;
- __u64 atime;
- __u64 mtime;
- __u64 ctime;
- __u32 atimensec;
- __u32 mtimensec;
- __u32 ctimensec;
- __u32 mode;
- __u32 nlink;
- __u32 uid;
- __u32 gid;
- __u32 rdev;
-};
-
-struct fuse_kstatfs {
- __u64 blocks;
- __u64 bfree;
- __u64 bavail;
- __u64 files;
- __u64 ffree;
- __u32 bsize;
- __u32 namelen;
- __u32 frsize;
- __u32 padding;
- __u32 spare[6];
-};
-
-struct fuse_file_lock {
- __u64 start;
- __u64 end;
- __u32 type;
- __u32 pid; /* tgid */
-};
-
-/**
- * Bitmasks for fuse_setattr_in.valid
- */
-#define FATTR_MODE (1 << 0)
-#define FATTR_UID (1 << 1)
-#define FATTR_GID (1 << 2)
-#define FATTR_SIZE (1 << 3)
-#define FATTR_ATIME (1 << 4)
-#define FATTR_MTIME (1 << 5)
-#define FATTR_FH (1 << 6)
-
-/**
- * Flags returned by the OPEN request
- *
- * FOPEN_DIRECT_IO: bypass page cache for this open file
- * FOPEN_KEEP_CACHE: don't invalidate the data cache on open
- */
-#define FOPEN_DIRECT_IO (1 << 0)
-#define FOPEN_KEEP_CACHE (1 << 1)
-
-/**
- * INIT request/reply flags
- */
-#define FUSE_ASYNC_READ (1 << 0)
-#define FUSE_POSIX_LOCKS (1 << 1)
-
-/**
- * Release flags
- */
-#define FUSE_RELEASE_FLUSH (1 << 0)
-
-enum fuse_opcode {
- FUSE_LOOKUP = 1,
- FUSE_FORGET = 2, /* no reply */
- FUSE_GETATTR = 3,
- FUSE_SETATTR = 4,
- FUSE_READLINK = 5,
- FUSE_SYMLINK = 6,
- FUSE_MKNOD = 8,
- FUSE_MKDIR = 9,
- FUSE_UNLINK = 10,
- FUSE_RMDIR = 11,
- FUSE_RENAME = 12,
- FUSE_LINK = 13,
- FUSE_OPEN = 14,
- FUSE_READ = 15,
- FUSE_WRITE = 16,
- FUSE_STATFS = 17,
- FUSE_RELEASE = 18,
- FUSE_FSYNC = 20,
- FUSE_SETXATTR = 21,
- FUSE_GETXATTR = 22,
- FUSE_LISTXATTR = 23,
- FUSE_REMOVEXATTR = 24,
- FUSE_FLUSH = 25,
- FUSE_INIT = 26,
- FUSE_OPENDIR = 27,
- FUSE_READDIR = 28,
- FUSE_RELEASEDIR = 29,
- FUSE_FSYNCDIR = 30,
- FUSE_GETLK = 31,
- FUSE_SETLK = 32,
- FUSE_SETLKW = 33,
- FUSE_ACCESS = 34,
- FUSE_CREATE = 35,
- FUSE_INTERRUPT = 36,
- FUSE_BMAP = 37,
- FUSE_DESTROY = 38,
-};
-
-/* The read buffer is required to be at least 8k, but may be much larger */
-#define FUSE_MIN_READ_BUFFER 8192
-
-struct fuse_entry_out {
- __u64 nodeid; /* Inode ID */
- __u64 generation; /* Inode generation: nodeid:gen must
- be unique for the fs's lifetime */
- __u64 entry_valid; /* Cache timeout for the name */
- __u64 attr_valid; /* Cache timeout for the attributes */
- __u32 entry_valid_nsec;
- __u32 attr_valid_nsec;
- struct fuse_attr attr;
-};
-
-struct fuse_forget_in {
- __u64 nlookup;
-};
-
-struct fuse_attr_out {
- __u64 attr_valid; /* Cache timeout for the attributes */
- __u32 attr_valid_nsec;
- __u32 dummy;
- struct fuse_attr attr;
-};
-
-struct fuse_mkdir_in {
- __u32 mode;
- __u32 padding;
-};
-
-struct fuse_rename_in {
- __u64 newdir;
-};
-
-struct fuse_link_in {
- __u64 oldnodeid;
-};
-
-struct fuse_setattr_in {
- __u32 valid;
- __u32 padding;
- __u64 fh;
- __u64 size;
- __u64 unused1;
- __u64 atime;
- __u64 mtime;
- __u64 unused2;
- __u32 atimensec;
- __u32 mtimensec;
- __u32 unused3;
- __u32 mode;
- __u32 unused4;
- __u32 uid;
- __u32 gid;
- __u32 unused5;
-};
-
-struct fuse_open_in {
- __u32 flags;
- __u32 mode;
-};
-
-struct fuse_open_out {
- __u64 fh;
- __u32 open_flags;
- __u32 padding;
-};
-
-struct fuse_release_in {
- __u64 fh;
- __u32 flags;
- __u32 release_flags;
- __u64 lock_owner;
-};
-
-struct fuse_flush_in {
- __u64 fh;
- __u32 unused;
- __u32 padding;
- __u64 lock_owner;
-};
-
-struct fuse_read_in {
- __u64 fh;
- __u64 offset;
- __u32 size;
- __u32 padding;
-};
-
-struct fuse_write_in {
- __u64 fh;
- __u64 offset;
- __u32 size;
- __u32 write_flags;
-};
-
-struct fuse_write_out {
- __u32 size;
- __u32 padding;
-};
-
-#define FUSE_COMPAT_STATFS_SIZE 48
-
-struct fuse_statfs_out {
- struct fuse_kstatfs st;
-};
-
-struct fuse_fsync_in {
- __u64 fh;
- __u32 fsync_flags;
- __u32 padding;
-};
-
-struct fuse_listxattr_in {
- __u32 size;
- __u32 flags;
-};
-
-struct fuse_listxattr_out {
- __u32 size;
- __u32 flags;
-};
-
-struct fuse_getxattr_in {
- __u32 size;
- __u32 padding;
-};
-
-struct fuse_getxattr_out {
- __u32 size;
- __u32 padding;
-};
-
-struct fuse_setxattr_in {
- __u32 size;
- __u32 flags;
-};
-
-struct fuse_lk_in {
- __u64 fh;
- __u64 owner;
- struct fuse_file_lock lk;
-};
-
-struct fuse_lk_out {
- struct fuse_file_lock lk;
-};
-
-struct fuse_access_in {
- __u32 mask;
- __u32 padding;
-};
-
-struct fuse_init_in {
- __u32 major;
- __u32 minor;
- __u32 max_readahead;
- __u32 flags;
-};
-
-struct fuse_init_out {
- __u32 major;
- __u32 minor;
- __u32 max_readahead;
- __u32 flags;
- __u32 unused;
- __u32 max_write;
-};
-
-struct fuse_interrupt_in {
- __u64 unique;
-};
-
-struct fuse_bmap_in {
- __u64 block;
- __u32 blocksize;
- __u32 padding;
-};
-
-struct fuse_bmap_out {
- __u64 block;
-};
-
-struct fuse_in_header {
- __u32 len;
- __u32 opcode;
- __u64 unique;
- __u64 nodeid;
- __u32 uid;
- __u32 gid;
- __u32 pid;
- __u32 padding;
-};
-
-struct fuse_out_header {
- __u32 len;
- __s32 error;
- __u64 unique;
-};
-
-struct fuse_dirent {
- __u64 ino;
- __u64 off;
- __u32 namelen;
- __u32 type;
- char name[0];
-};
-
-#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)
-#define FUSE_DIRENT_ALIGN(x) (((x) + sizeof(__u64) - 1) & ~(sizeof(__u64) - 1))
-#define FUSE_DIRENT_SIZE(d) \
- FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
Index: sys/fs/fuse/fuse_main.c
===================================================================
--- sys/fs/fuse/fuse_main.c
+++ sys/fs/fuse/fuse_main.c
@@ -1,165 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Copyright (c) 2007-2009 Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Copyright (C) 2005 Csaba Henk.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/types.h>
-#include <sys/module.h>
-#include <sys/systm.h>
-#include <sys/errno.h>
-#include <sys/param.h>
-#include <sys/kernel.h>
-#include <sys/conf.h>
-#include <sys/mutex.h>
-#include <sys/proc.h>
-#include <sys/mount.h>
-#include <sys/vnode.h>
-#include <sys/stat.h>
-#include <sys/file.h>
-#include <sys/buf.h>
-#include <sys/sysctl.h>
-
-#include "fuse.h"
-
-static void fuse_bringdown(eventhandler_tag eh_tag);
-static int fuse_loader(struct module *m, int what, void *arg);
-
-struct mtx fuse_mtx;
-
-extern struct vfsops fuse_vfsops;
-extern struct cdevsw fuse_cdevsw;
-extern struct vop_vector fuse_vnops;
-extern uma_zone_t fuse_pbuf_zone;
-
-static struct vfsconf fuse_vfsconf = {
- .vfc_version = VFS_VERSION,
- .vfc_name = "fusefs",
- .vfc_vfsops = &fuse_vfsops,
- .vfc_typenum = -1,
- .vfc_flags = VFCF_JAIL | VFCF_SYNTHETIC
-};
-
-SYSCTL_INT(_vfs_fuse, OID_AUTO, kernelabi_major, CTLFLAG_RD,
- SYSCTL_NULL_INT_PTR, FUSE_KERNEL_VERSION, "FUSE kernel abi major version");
-SYSCTL_INT(_vfs_fuse, OID_AUTO, kernelabi_minor, CTLFLAG_RD,
- SYSCTL_NULL_INT_PTR, FUSE_KERNEL_MINOR_VERSION, "FUSE kernel abi minor version");
-
-/******************************
- *
- * >>> Module management stuff
- *
- ******************************/
-
-static void
-fuse_bringdown(eventhandler_tag eh_tag)
-{
-
- fuse_ipc_destroy();
- fuse_device_destroy();
- mtx_destroy(&fuse_mtx);
-}
-
-static int
-fuse_loader(struct module *m, int what, void *arg)
-{
- static eventhandler_tag eh_tag = NULL;
- int err = 0;
-
- switch (what) {
- case MOD_LOAD: /* kldload */
- mtx_init(&fuse_mtx, "fuse_mtx", NULL, MTX_DEF);
- err = fuse_device_init();
- if (err) {
- mtx_destroy(&fuse_mtx);
- return (err);
- }
- fuse_ipc_init();
- fuse_pbuf_zone = pbuf_zsecond_create("fusepbuf", nswbuf / 2);
-
- /* vfs_modevent ignores its first arg */
- if ((err = vfs_modevent(NULL, what, &fuse_vfsconf)))
- fuse_bringdown(eh_tag);
- else
- printf("fuse-freebsd: version %s, FUSE ABI %d.%d\n",
- FUSE_FREEBSD_VERSION,
- FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
-
- break;
- case MOD_UNLOAD:
- if ((err = vfs_modevent(NULL, what, &fuse_vfsconf)))
- return (err);
- fuse_bringdown(eh_tag);
- uma_zdestroy(fuse_pbuf_zone);
- break;
- default:
- return (EINVAL);
- }
-
- return (err);
-}
-
-/* Registering the module */
-
-static moduledata_t fuse_moddata = {
- "fuse",
- fuse_loader,
- &fuse_vfsconf
-};
-
-DECLARE_MODULE(fuse, fuse_moddata, SI_SUB_VFS, SI_ORDER_MIDDLE);
-MODULE_VERSION(fuse, 1);
Index: sys/fs/fuse/fuse_node.h
===================================================================
--- sys/fs/fuse/fuse_node.h
+++ sys/fs/fuse/fuse_node.h
@@ -1,132 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Copyright (c) 2007-2009 Google Inc. and Amit Singh
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Copyright (C) 2005 Csaba Henk.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#ifndef _FUSE_NODE_H_
-#define _FUSE_NODE_H_
-
-#include <sys/types.h>
-#include <sys/mutex.h>
-
-#include "fuse_file.h"
-
-#define FN_REVOKED 0x00000020
-#define FN_FLUSHINPROG 0x00000040
-#define FN_FLUSHWANT 0x00000080
-#define FN_SIZECHANGE 0x00000100
-#define FN_DIRECTIO 0x00000200
-
-struct fuse_vnode_data {
- /** self **/
- uint64_t nid;
-
- /** parent **/
- /* XXXIP very likely to be stale, it's not updated in rename() */
- uint64_t parent_nid;
-
- /** I/O **/
- struct fuse_filehandle fufh[FUFH_MAXTYPE];
-
- /** flags **/
- uint32_t flag;
-
- /** meta **/
- bool valid_attr_cache;
- struct vattr cached_attrs;
- off_t filesize;
- uint64_t nlookup;
- enum vtype vtype;
-};
-
-#define VTOFUD(vp) \
- ((struct fuse_vnode_data *)((vp)->v_data))
-#define VTOI(vp) (VTOFUD(vp)->nid)
-#define VTOVA(vp) \
- (VTOFUD(vp)->valid_attr_cache ? \
- &(VTOFUD(vp)->cached_attrs) : NULL)
-#define VTOILLU(vp) ((uint64_t)(VTOFUD(vp) ? VTOI(vp) : 0))
-
-#define FUSE_NULL_ID 0
-
-extern struct vop_vector fuse_vnops;
-
-static inline void
-fuse_vnode_setparent(struct vnode *vp, struct vnode *dvp)
-{
- if (dvp != NULL && vp->v_type == VDIR) {
- MPASS(dvp->v_type == VDIR);
- VTOFUD(vp)->parent_nid = VTOI(dvp);
- }
-}
-
-void fuse_vnode_destroy(struct vnode *vp);
-
-int fuse_vnode_get(struct mount *mp, struct fuse_entry_out *feo,
- uint64_t nodeid, struct vnode *dvp, struct vnode **vpp,
- struct componentname *cnp, enum vtype vtyp);
-
-void fuse_vnode_open(struct vnode *vp, int32_t fuse_open_flags,
- struct thread *td);
-
-void fuse_vnode_refreshsize(struct vnode *vp, struct ucred *cred);
-
-int fuse_vnode_savesize(struct vnode *vp, struct ucred *cred);
-
-int fuse_vnode_setsize(struct vnode *vp, struct ucred *cred, off_t newsize);
-
-#endif /* _FUSE_NODE_H_ */
Index: sys/fs/fuse/fuse_node.c
===================================================================
--- sys/fs/fuse/fuse_node.c
+++ sys/fs/fuse/fuse_node.c
@@ -1,432 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Copyright (c) 2007-2009 Google Inc. and Amit Singh
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Copyright (C) 2005 Csaba Henk.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/types.h>
-#include <sys/module.h>
-#include <sys/systm.h>
-#include <sys/errno.h>
-#include <sys/param.h>
-#include <sys/kernel.h>
-#include <sys/conf.h>
-#include <sys/uio.h>
-#include <sys/malloc.h>
-#include <sys/queue.h>
-#include <sys/lock.h>
-#include <sys/sx.h>
-#include <sys/mutex.h>
-#include <sys/proc.h>
-#include <sys/vnode.h>
-#include <sys/namei.h>
-#include <sys/mount.h>
-#include <sys/sysctl.h>
-#include <sys/fcntl.h>
-#include <sys/fnv_hash.h>
-#include <sys/priv.h>
-#include <security/mac/mac_framework.h>
-#include <vm/vm.h>
-#include <vm/vm_extern.h>
-
-#include "fuse.h"
-#include "fuse_node.h"
-#include "fuse_internal.h"
-#include "fuse_io.h"
-#include "fuse_ipc.h"
-
-#define FUSE_DEBUG_MODULE VNOPS
-#include "fuse_debug.h"
-
-MALLOC_DEFINE(M_FUSEVN, "fuse_vnode", "fuse vnode private data");
-
-static int sysctl_fuse_cache_mode(SYSCTL_HANDLER_ARGS);
-
-static int fuse_node_count = 0;
-
-SYSCTL_INT(_vfs_fuse, OID_AUTO, node_count, CTLFLAG_RD,
- &fuse_node_count, 0, "Count of FUSE vnodes");
-
-int fuse_data_cache_mode = FUSE_CACHE_WT;
-
-SYSCTL_PROC(_vfs_fuse, OID_AUTO, data_cache_mode, CTLTYPE_INT|CTLFLAG_RW,
- &fuse_data_cache_mode, 0, sysctl_fuse_cache_mode, "I",
- "Zero: disable caching of FUSE file data; One: write-through caching "
- "(default); Two: write-back caching (generally unsafe)");
-
-int fuse_data_cache_invalidate = 0;
-
-SYSCTL_INT(_vfs_fuse, OID_AUTO, data_cache_invalidate, CTLFLAG_RW,
- &fuse_data_cache_invalidate, 0,
- "If non-zero, discard cached clean file data when there are no active file"
- " users");
-
-int fuse_mmap_enable = 1;
-
-SYSCTL_INT(_vfs_fuse, OID_AUTO, mmap_enable, CTLFLAG_RW,
- &fuse_mmap_enable, 0,
- "If non-zero, and data_cache_mode is also non-zero, enable mmap(2) of "
- "FUSE files");
-
-int fuse_refresh_size = 0;
-
-SYSCTL_INT(_vfs_fuse, OID_AUTO, refresh_size, CTLFLAG_RW,
- &fuse_refresh_size, 0,
- "If non-zero, and no dirty file extension data is buffered, fetch file "
- "size before write operations");
-
-int fuse_sync_resize = 1;
-
-SYSCTL_INT(_vfs_fuse, OID_AUTO, sync_resize, CTLFLAG_RW,
- &fuse_sync_resize, 0,
- "If a cached write extended a file, inform FUSE filesystem of the changed"
- "size immediately subsequent to the issued writes");
-
-int fuse_fix_broken_io = 0;
-
-SYSCTL_INT(_vfs_fuse, OID_AUTO, fix_broken_io, CTLFLAG_RW,
- &fuse_fix_broken_io, 0,
- "If non-zero, print a diagnostic warning if a userspace filesystem returns"
- " EIO on reads of recently extended portions of files");
-
-static int
-sysctl_fuse_cache_mode(SYSCTL_HANDLER_ARGS)
-{
- int val, error;
-
- val = *(int *)arg1;
- error = sysctl_handle_int(oidp, &val, 0, req);
- if (error || !req->newptr)
- return (error);
-
- switch (val) {
- case FUSE_CACHE_UC:
- case FUSE_CACHE_WT:
- case FUSE_CACHE_WB:
- *(int *)arg1 = val;
- break;
- default:
- return (EDOM);
- }
- return (0);
-}
-
-static void
-fuse_vnode_init(struct vnode *vp, struct fuse_vnode_data *fvdat,
- uint64_t nodeid, enum vtype vtyp)
-{
- int i;
-
- fvdat->nid = nodeid;
- vattr_null(&fvdat->cached_attrs);
- if (nodeid == FUSE_ROOT_ID) {
- vp->v_vflag |= VV_ROOT;
- }
- vp->v_type = vtyp;
- vp->v_data = fvdat;
-
- for (i = 0; i < FUFH_MAXTYPE; i++)
- fvdat->fufh[i].fh_type = FUFH_INVALID;
-
- atomic_add_acq_int(&fuse_node_count, 1);
-}
-
-void
-fuse_vnode_destroy(struct vnode *vp)
-{
- struct fuse_vnode_data *fvdat = vp->v_data;
-
- vp->v_data = NULL;
- free(fvdat, M_FUSEVN);
-
- atomic_subtract_acq_int(&fuse_node_count, 1);
-}
-
-static int
-fuse_vnode_cmp(struct vnode *vp, void *nidp)
-{
- return (VTOI(vp) != *((uint64_t *)nidp));
-}
-
-static uint32_t inline
-fuse_vnode_hash(uint64_t id)
-{
- return (fnv_32_buf(&id, sizeof(id), FNV1_32_INIT));
-}
-
-static int
-fuse_vnode_alloc(struct mount *mp,
- struct thread *td,
- uint64_t nodeid,
- enum vtype vtyp,
- struct vnode **vpp)
-{
- struct fuse_vnode_data *fvdat;
- struct vnode *vp2;
- int err = 0;
-
- FS_DEBUG("been asked for vno #%ju\n", (uintmax_t)nodeid);
-
- if (vtyp == VNON) {
- return EINVAL;
- }
- *vpp = NULL;
- err = vfs_hash_get(mp, fuse_vnode_hash(nodeid), LK_EXCLUSIVE, td, vpp,
- fuse_vnode_cmp, &nodeid);
- if (err)
- return (err);
-
- if (*vpp) {
- MPASS((*vpp)->v_type == vtyp && (*vpp)->v_data != NULL);
- FS_DEBUG("vnode taken from hash\n");
- return (0);
- }
- fvdat = malloc(sizeof(*fvdat), M_FUSEVN, M_WAITOK | M_ZERO);
- err = getnewvnode("fuse", mp, &fuse_vnops, vpp);
- if (err) {
- free(fvdat, M_FUSEVN);
- return (err);
- }
- lockmgr((*vpp)->v_vnlock, LK_EXCLUSIVE, NULL);
- fuse_vnode_init(*vpp, fvdat, nodeid, vtyp);
- err = insmntque(*vpp, mp);
- ASSERT_VOP_ELOCKED(*vpp, "fuse_vnode_alloc");
- if (err) {
- free(fvdat, M_FUSEVN);
- *vpp = NULL;
- return (err);
- }
- err = vfs_hash_insert(*vpp, fuse_vnode_hash(nodeid), LK_EXCLUSIVE,
- td, &vp2, fuse_vnode_cmp, &nodeid);
- if (err)
- return (err);
- if (vp2 != NULL) {
- *vpp = vp2;
- return (0);
- }
-
- ASSERT_VOP_ELOCKED(*vpp, "fuse_vnode_alloc");
-
- return (0);
-}
-
-int
-fuse_vnode_get(struct mount *mp,
- struct fuse_entry_out *feo,
- uint64_t nodeid,
- struct vnode *dvp,
- struct vnode **vpp,
- struct componentname *cnp,
- enum vtype vtyp)
-{
- struct thread *td = (cnp != NULL ? cnp->cn_thread : curthread);
- int err = 0;
-
- debug_printf("dvp=%p\n", dvp);
-
- err = fuse_vnode_alloc(mp, td, nodeid, vtyp, vpp);
- if (err) {
- return err;
- }
- if (dvp != NULL) {
- MPASS((cnp->cn_flags & ISDOTDOT) == 0);
- MPASS(!(cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.'));
- fuse_vnode_setparent(*vpp, dvp);
- }
- if (dvp != NULL && cnp != NULL && (cnp->cn_flags & MAKEENTRY) != 0 &&
- feo != NULL &&
- (feo->entry_valid != 0 || feo->entry_valid_nsec != 0)) {
- ASSERT_VOP_LOCKED(*vpp, "fuse_vnode_get");
- ASSERT_VOP_LOCKED(dvp, "fuse_vnode_get");
- cache_enter(dvp, *vpp, cnp);
- }
-
- /*
- * In userland, libfuse uses cached lookups for dot and dotdot entries,
- * thus it does not really bump the nlookup counter for forget.
- * Follow the same semantic and avoid tu bump it in order to keep
- * nlookup counters consistent.
- */
- if (cnp == NULL || ((cnp->cn_flags & ISDOTDOT) == 0 &&
- (cnp->cn_namelen != 1 || cnp->cn_nameptr[0] != '.')))
- VTOFUD(*vpp)->nlookup++;
-
- return 0;
-}
-
-void
-fuse_vnode_open(struct vnode *vp, int32_t fuse_open_flags, struct thread *td)
-{
- /*
- * Funcation is called for every vnode open.
- * Merge fuse_open_flags it may be 0
- */
- /*
- * Ideally speaking, direct io should be enabled on
- * fd's but do not see of any way of providing that
- * this implementation.
- *
- * Also cannot think of a reason why would two
- * different fd's on same vnode would like
- * have DIRECT_IO turned on and off. But linux
- * based implementation works on an fd not an
- * inode and provides such a feature.
- *
- * XXXIP: Handle fd based DIRECT_IO
- */
- if (fuse_open_flags & FOPEN_DIRECT_IO) {
- ASSERT_VOP_ELOCKED(vp, __func__);
- VTOFUD(vp)->flag |= FN_DIRECTIO;
- fuse_io_invalbuf(vp, td);
- } else {
- if ((fuse_open_flags & FOPEN_KEEP_CACHE) == 0)
- fuse_io_invalbuf(vp, td);
- VTOFUD(vp)->flag &= ~FN_DIRECTIO;
- }
-
- if (vnode_vtype(vp) == VREG) {
- /* XXXIP prevent getattr, by using cached node size */
- vnode_create_vobject(vp, 0, td);
- }
-}
-
-int
-fuse_vnode_savesize(struct vnode *vp, struct ucred *cred)
-{
- struct fuse_vnode_data *fvdat = VTOFUD(vp);
- struct thread *td = curthread;
- struct fuse_filehandle *fufh = NULL;
- struct fuse_dispatcher fdi;
- struct fuse_setattr_in *fsai;
- int err = 0;
-
- FS_DEBUG("inode=%ju size=%ju\n", (uintmax_t)VTOI(vp),
- (uintmax_t)fvdat->filesize);
- ASSERT_VOP_ELOCKED(vp, "fuse_io_extend");
-
- if (fuse_isdeadfs(vp)) {
- return EBADF;
- }
- if (vnode_vtype(vp) == VDIR) {
- return EISDIR;
- }
- if (vfs_isrdonly(vnode_mount(vp))) {
- return EROFS;
- }
- if (cred == NULL) {
- cred = td->td_ucred;
- }
- fdisp_init(&fdi, sizeof(*fsai));
- fdisp_make_vp(&fdi, FUSE_SETATTR, vp, td, cred);
- fsai = fdi.indata;
- fsai->valid = 0;
-
- /* Truncate to a new value. */
- fsai->size = fvdat->filesize;
- fsai->valid |= FATTR_SIZE;
-
- fuse_filehandle_getrw(vp, FUFH_WRONLY, &fufh);
- if (fufh) {
- fsai->fh = fufh->fh_id;
- fsai->valid |= FATTR_FH;
- }
- err = fdisp_wait_answ(&fdi);
- fdisp_destroy(&fdi);
- if (err == 0)
- fvdat->flag &= ~FN_SIZECHANGE;
-
- return err;
-}
-
-void
-fuse_vnode_refreshsize(struct vnode *vp, struct ucred *cred)
-{
-
- struct fuse_vnode_data *fvdat = VTOFUD(vp);
- struct vattr va;
-
- if ((fvdat->flag & FN_SIZECHANGE) != 0 ||
- fuse_data_cache_mode == FUSE_CACHE_UC ||
- (fuse_refresh_size == 0 && fvdat->filesize != 0))
- return;
-
- VOP_GETATTR(vp, &va, cred);
- FS_DEBUG("refreshed file size: %jd\n", (intmax_t)VTOFUD(vp)->filesize);
-}
-
-int
-fuse_vnode_setsize(struct vnode *vp, struct ucred *cred, off_t newsize)
-{
- struct fuse_vnode_data *fvdat = VTOFUD(vp);
- off_t oldsize;
- int err = 0;
-
- FS_DEBUG("inode=%ju oldsize=%ju newsize=%ju\n",
- (uintmax_t)VTOI(vp), (uintmax_t)fvdat->filesize,
- (uintmax_t)newsize);
- ASSERT_VOP_ELOCKED(vp, "fuse_vnode_setsize");
-
- oldsize = fvdat->filesize;
- fvdat->filesize = newsize;
- fvdat->flag |= FN_SIZECHANGE;
-
- if (newsize < oldsize) {
- err = vtruncbuf(vp, cred, newsize, fuse_iosize(vp));
- }
- vnode_pager_setsize(vp, newsize);
- return err;
-}
Index: sys/fs/fuse/fuse_param.h
===================================================================
--- sys/fs/fuse/fuse_param.h
+++ sys/fs/fuse/fuse_param.h
@@ -1,82 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Copyright (c) 2007-2009 Google Inc. and Amit Singh
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#ifndef _FUSE_PARAM_H_
-#define _FUSE_PARAM_H_
-
-/*
- * This is the prefix ("fuse" by default) of the name of a FUSE device node
- * in devfs. The suffix is the device number. "/dev/fuse0" is the first FUSE
- * device by default. If you change the prefix from the default to something
- * else, the user-space FUSE library will need to know about it too.
- */
-#define FUSE_DEVICE_BASENAME "fuse"
-
-/*
- * This is the number of /dev/fuse<n> nodes we will create. <n> goes from
- * 0 to (FUSE_NDEVICES - 1).
- */
-#define FUSE_NDEVICES 16
-
-/*
- * This is the default block size of the virtual storage devices that are
- * implicitly implemented by the FUSE kernel extension. This can be changed
- * on a per-mount basis (there's one such virtual device for each mount).
- */
-#define FUSE_DEFAULT_BLOCKSIZE 4096
-
-/*
- * This is default I/O size used while accessing the virtual storage devices.
- * This can be changed on a per-mount basis.
- */
-#define FUSE_DEFAULT_IOSIZE 4096
-
-#ifdef KERNEL
-
-/*
- * This is the soft upper limit on the number of "request tickets" FUSE's
- * user-kernel IPC layer can have for a given mount. This can be modified
- * through the fuse.* sysctl interface.
- */
-#define FUSE_DEFAULT_MAX_FREE_TICKETS 1024
-
-#define FUSE_DEFAULT_IOV_PERMANENT_BUFSIZE (1L << 19)
-#define FUSE_DEFAULT_IOV_CREDIT 16
-
-#endif
-
-#define FUSE_LINK_MAX UINT32_MAX
-
-#endif /* _FUSE_PARAM_H_ */
Index: sys/fs/fuse/fuse_vfsops.c
===================================================================
--- sys/fs/fuse/fuse_vfsops.c
+++ sys/fs/fuse/fuse_vfsops.c
@@ -1,533 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Copyright (c) 2007-2009 Google Inc. and Amit Singh
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Copyright (C) 2005 Csaba Henk.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/buf.h>
-#include <sys/module.h>
-#include <sys/systm.h>
-#include <sys/errno.h>
-#include <sys/kernel.h>
-#include <sys/capsicum.h>
-#include <sys/conf.h>
-#include <sys/filedesc.h>
-#include <sys/uio.h>
-#include <sys/malloc.h>
-#include <sys/queue.h>
-#include <sys/lock.h>
-#include <sys/sx.h>
-#include <sys/mutex.h>
-#include <sys/proc.h>
-#include <sys/vnode.h>
-#include <sys/namei.h>
-#include <sys/mount.h>
-#include <sys/sysctl.h>
-#include <sys/fcntl.h>
-
-#include "fuse.h"
-#include "fuse_param.h"
-#include "fuse_node.h"
-#include "fuse_ipc.h"
-#include "fuse_internal.h"
-
-#include <sys/priv.h>
-#include <security/mac/mac_framework.h>
-
-#define FUSE_DEBUG_MODULE VFSOPS
-#include "fuse_debug.h"
-
-/* This will do for privilege types for now */
-#ifndef PRIV_VFS_FUSE_ALLOWOTHER
-#define PRIV_VFS_FUSE_ALLOWOTHER PRIV_VFS_MOUNT_NONUSER
-#endif
-#ifndef PRIV_VFS_FUSE_MOUNT_NONUSER
-#define PRIV_VFS_FUSE_MOUNT_NONUSER PRIV_VFS_MOUNT_NONUSER
-#endif
-#ifndef PRIV_VFS_FUSE_SYNC_UNMOUNT
-#define PRIV_VFS_FUSE_SYNC_UNMOUNT PRIV_VFS_MOUNT_NONUSER
-#endif
-
-static vfs_mount_t fuse_vfsop_mount;
-static vfs_unmount_t fuse_vfsop_unmount;
-static vfs_root_t fuse_vfsop_root;
-static vfs_statfs_t fuse_vfsop_statfs;
-
-struct vfsops fuse_vfsops = {
- .vfs_mount = fuse_vfsop_mount,
- .vfs_unmount = fuse_vfsop_unmount,
- .vfs_root = fuse_vfsop_root,
- .vfs_statfs = fuse_vfsop_statfs,
-};
-
-SYSCTL_INT(_vfs_fuse, OID_AUTO, init_backgrounded, CTLFLAG_RD,
- SYSCTL_NULL_INT_PTR, 1, "indicate async handshake");
-static int fuse_enforce_dev_perms = 0;
-
-SYSCTL_INT(_vfs_fuse, OID_AUTO, enforce_dev_perms, CTLFLAG_RW,
- &fuse_enforce_dev_perms, 0,
- "enforce fuse device permissions for secondary mounts");
-static unsigned sync_unmount = 1;
-
-SYSCTL_UINT(_vfs_fuse, OID_AUTO, sync_unmount, CTLFLAG_RW,
- &sync_unmount, 0, "specify when to use synchronous unmount");
-
-MALLOC_DEFINE(M_FUSEVFS, "fuse_filesystem", "buffer for fuse vfs layer");
-
-static int
-fuse_getdevice(const char *fspec, struct thread *td, struct cdev **fdevp)
-{
- struct nameidata nd, *ndp = &nd;
- struct vnode *devvp;
- struct cdev *fdev;
- int err;
-
- /*
- * Not an update, or updating the name: look up the name
- * and verify that it refers to a sensible disk device.
- */
-
- NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fspec, td);
- if ((err = namei(ndp)) != 0)
- return err;
- NDFREE(ndp, NDF_ONLY_PNBUF);
- devvp = ndp->ni_vp;
-
- if (devvp->v_type != VCHR) {
- vrele(devvp);
- return ENXIO;
- }
- fdev = devvp->v_rdev;
- dev_ref(fdev);
-
- if (fuse_enforce_dev_perms) {
- /*
- * Check if mounter can open the fuse device.
- *
- * This has significance only if we are doing a secondary mount
- * which doesn't involve actually opening fuse devices, but we
- * still want to enforce the permissions of the device (in
- * order to keep control over the circle of fuse users).
- *
- * (In case of primary mounts, we are either the superuser so
- * we can do anything anyway, or we can mount only if the
- * device is already opened by us, ie. we are permitted to open
- * the device.)
- */
-#if 0
-#ifdef MAC
- err = mac_check_vnode_open(td->td_ucred, devvp, VREAD | VWRITE);
- if (!err)
-#endif
-#endif /* 0 */
- err = VOP_ACCESS(devvp, VREAD | VWRITE, td->td_ucred, td);
- if (err) {
- vrele(devvp);
- dev_rel(fdev);
- return err;
- }
- }
- /*
- * according to coda code, no extra lock is needed --
- * although in sys/vnode.h this field is marked "v"
- */
- vrele(devvp);
-
- if (!fdev->si_devsw ||
- strcmp("fuse", fdev->si_devsw->d_name)) {
- dev_rel(fdev);
- return ENXIO;
- }
- *fdevp = fdev;
-
- return 0;
-}
-
-#define FUSE_FLAGOPT(fnam, fval) do { \
- vfs_flagopt(opts, #fnam, &mntopts, fval); \
- vfs_flagopt(opts, "__" #fnam, &__mntopts, fval); \
-} while (0)
-
-static int
-fuse_vfsop_mount(struct mount *mp)
-{
- int err;
-
- uint64_t mntopts, __mntopts;
- uint32_t max_read;
- int daemon_timeout;
- int fd;
-
- size_t len;
-
- struct cdev *fdev;
- struct fuse_data *data;
- struct thread *td;
- struct file *fp, *fptmp;
- char *fspec, *subtype;
- struct vfsoptlist *opts;
-
- subtype = NULL;
- max_read = ~0;
- err = 0;
- mntopts = 0;
- __mntopts = 0;
- td = curthread;
-
- fuse_trace_printf_vfsop();
-
- if (mp->mnt_flag & MNT_UPDATE)
- return EOPNOTSUPP;
-
- MNT_ILOCK(mp);
- mp->mnt_flag |= MNT_SYNCHRONOUS;
- mp->mnt_data = NULL;
- MNT_IUNLOCK(mp);
- /* Get the new options passed to mount */
- opts = mp->mnt_optnew;
-
- if (!opts)
- return EINVAL;
-
- /* `fspath' contains the mount point (eg. /mnt/fuse/sshfs); REQUIRED */
- if (!vfs_getopts(opts, "fspath", &err))
- return err;
-
- /* `from' contains the device name (eg. /dev/fuse0); REQUIRED */
- fspec = vfs_getopts(opts, "from", &err);
- if (!fspec)
- return err;
-
- /* `fd' contains the filedescriptor for this session; REQUIRED */
- if (vfs_scanopt(opts, "fd", "%d", &fd) != 1)
- return EINVAL;
-
- err = fuse_getdevice(fspec, td, &fdev);
- if (err != 0)
- return err;
-
- /*
- * With the help of underscored options the mount program
- * can inform us from the flags it sets by default
- */
- FUSE_FLAGOPT(allow_other, FSESS_DAEMON_CAN_SPY);
- FUSE_FLAGOPT(push_symlinks_in, FSESS_PUSH_SYMLINKS_IN);
- FUSE_FLAGOPT(default_permissions, FSESS_DEFAULT_PERMISSIONS);
- FUSE_FLAGOPT(no_attrcache, FSESS_NO_ATTRCACHE);
- FUSE_FLAGOPT(no_readahed, FSESS_NO_READAHEAD);
- FUSE_FLAGOPT(no_datacache, FSESS_NO_DATACACHE);
- FUSE_FLAGOPT(no_namecache, FSESS_NO_NAMECACHE);
- FUSE_FLAGOPT(no_mmap, FSESS_NO_MMAP);
- FUSE_FLAGOPT(brokenio, FSESS_BROKENIO);
-
- (void)vfs_scanopt(opts, "max_read=", "%u", &max_read);
- if (vfs_scanopt(opts, "timeout=", "%u", &daemon_timeout) == 1) {
- if (daemon_timeout < FUSE_MIN_DAEMON_TIMEOUT)
- daemon_timeout = FUSE_MIN_DAEMON_TIMEOUT;
- else if (daemon_timeout > FUSE_MAX_DAEMON_TIMEOUT)
- daemon_timeout = FUSE_MAX_DAEMON_TIMEOUT;
- } else {
- daemon_timeout = FUSE_DEFAULT_DAEMON_TIMEOUT;
- }
- subtype = vfs_getopts(opts, "subtype=", &err);
-
- FS_DEBUG2G("mntopts 0x%jx\n", (uintmax_t)mntopts);
-
- err = fget(td, fd, &cap_read_rights, &fp);
- if (err != 0) {
- FS_DEBUG("invalid or not opened device: data=%p\n", data);
- goto out;
- }
- fptmp = td->td_fpop;
- td->td_fpop = fp;
- err = devfs_get_cdevpriv((void **)&data);
- td->td_fpop = fptmp;
- fdrop(fp, td);
- FUSE_LOCK();
- if (err != 0 || data == NULL || data->mp != NULL) {
- FS_DEBUG("invalid or not opened device: data=%p data.mp=%p\n",
- data, data != NULL ? data->mp : NULL);
- err = ENXIO;
- FUSE_UNLOCK();
- goto out;
- }
- if (fdata_get_dead(data)) {
- FS_DEBUG("device is dead during mount: data=%p\n", data);
- err = ENOTCONN;
- FUSE_UNLOCK();
- goto out;
- }
- /* Sanity + permission checks */
- if (!data->daemoncred)
- panic("fuse daemon found, but identity unknown");
- if (mntopts & FSESS_DAEMON_CAN_SPY)
- err = priv_check(td, PRIV_VFS_FUSE_ALLOWOTHER);
- if (err == 0 && td->td_ucred->cr_uid != data->daemoncred->cr_uid)
- /* are we allowed to do the first mount? */
- err = priv_check(td, PRIV_VFS_FUSE_MOUNT_NONUSER);
- if (err) {
- FUSE_UNLOCK();
- goto out;
- }
- data->ref++;
- data->mp = mp;
- data->dataflags |= mntopts;
- data->max_read = max_read;
- data->daemon_timeout = daemon_timeout;
- FUSE_UNLOCK();
-
- vfs_getnewfsid(mp);
- MNT_ILOCK(mp);
- mp->mnt_data = data;
- mp->mnt_flag |= MNT_LOCAL;
- mp->mnt_kern_flag |= MNTK_USES_BCACHE;
- MNT_IUNLOCK(mp);
- /* We need this here as this slot is used by getnewvnode() */
- mp->mnt_stat.f_iosize = maxbcachebuf;
- if (subtype) {
- strlcat(mp->mnt_stat.f_fstypename, ".", MFSNAMELEN);
- strlcat(mp->mnt_stat.f_fstypename, subtype, MFSNAMELEN);
- }
- copystr(fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &len);
- bzero(mp->mnt_stat.f_mntfromname + len, MNAMELEN - len);
- FS_DEBUG2G("mp %p: %s\n", mp, mp->mnt_stat.f_mntfromname);
-
- /* Now handshaking with daemon */
- fuse_internal_send_init(data, td);
-
-out:
- if (err) {
- FUSE_LOCK();
- if (data->mp == mp) {
- /*
- * Destroy device only if we acquired reference to
- * it
- */
- FS_DEBUG("mount failed, destroy device: data=%p mp=%p"
- " err=%d\n",
- data, mp, err);
- data->mp = NULL;
- fdata_trydestroy(data);
- }
- FUSE_UNLOCK();
- dev_rel(fdev);
- }
- return err;
-}
-
-static int
-fuse_vfsop_unmount(struct mount *mp, int mntflags)
-{
- int err = 0;
- int flags = 0;
-
- struct cdev *fdev;
- struct fuse_data *data;
- struct fuse_dispatcher fdi;
- struct thread *td = curthread;
-
- fuse_trace_printf_vfsop();
-
- if (mntflags & MNT_FORCE) {
- flags |= FORCECLOSE;
- }
- data = fuse_get_mpdata(mp);
- if (!data) {
- panic("no private data for mount point?");
- }
- /* There is 1 extra root vnode reference (mp->mnt_data). */
- FUSE_LOCK();
- if (data->vroot != NULL) {
- struct vnode *vroot = data->vroot;
-
- data->vroot = NULL;
- FUSE_UNLOCK();
- vrele(vroot);
- } else
- FUSE_UNLOCK();
- err = vflush(mp, 0, flags, td);
- if (err) {
- debug_printf("vflush failed");
- return err;
- }
- if (fdata_get_dead(data)) {
- goto alreadydead;
- }
- fdisp_init(&fdi, 0);
- fdisp_make(&fdi, FUSE_DESTROY, mp, 0, td, NULL);
-
- err = fdisp_wait_answ(&fdi);
- fdisp_destroy(&fdi);
-
- fdata_set_dead(data);
-
-alreadydead:
- FUSE_LOCK();
- data->mp = NULL;
- fdev = data->fdev;
- fdata_trydestroy(data);
- FUSE_UNLOCK();
-
- MNT_ILOCK(mp);
- mp->mnt_data = NULL;
- mp->mnt_flag &= ~MNT_LOCAL;
- MNT_IUNLOCK(mp);
-
- dev_rel(fdev);
-
- return 0;
-}
-
-static int
-fuse_vfsop_root(struct mount *mp, int lkflags, struct vnode **vpp)
-{
- struct fuse_data *data = fuse_get_mpdata(mp);
- int err = 0;
-
- if (data->vroot != NULL) {
- err = vget(data->vroot, lkflags, curthread);
- if (err == 0)
- *vpp = data->vroot;
- } else {
- err = fuse_vnode_get(mp, NULL, FUSE_ROOT_ID, NULL, vpp, NULL,
- VDIR);
- if (err == 0) {
- FUSE_LOCK();
- MPASS(data->vroot == NULL || data->vroot == *vpp);
- if (data->vroot == NULL) {
- FS_DEBUG("new root vnode\n");
- data->vroot = *vpp;
- FUSE_UNLOCK();
- vref(*vpp);
- } else if (data->vroot != *vpp) {
- FS_DEBUG("root vnode race\n");
- FUSE_UNLOCK();
- VOP_UNLOCK(*vpp, 0);
- vrele(*vpp);
- vrecycle(*vpp);
- *vpp = data->vroot;
- } else
- FUSE_UNLOCK();
- }
- }
- return err;
-}
-
-static int
-fuse_vfsop_statfs(struct mount *mp, struct statfs *sbp)
-{
- struct fuse_dispatcher fdi;
- int err = 0;
-
- struct fuse_statfs_out *fsfo;
- struct fuse_data *data;
-
- FS_DEBUG2G("mp %p: %s\n", mp, mp->mnt_stat.f_mntfromname);
- data = fuse_get_mpdata(mp);
-
- if (!(data->dataflags & FSESS_INITED))
- goto fake;
-
- fdisp_init(&fdi, 0);
- fdisp_make(&fdi, FUSE_STATFS, mp, FUSE_ROOT_ID, NULL, NULL);
- err = fdisp_wait_answ(&fdi);
- if (err) {
- fdisp_destroy(&fdi);
- if (err == ENOTCONN) {
- /*
- * We want to seem a legitimate fs even if the daemon
- * is stiff dead... (so that, eg., we can still do path
- * based unmounting after the daemon dies).
- */
- goto fake;
- }
- return err;
- }
- fsfo = fdi.answ;
-
- sbp->f_blocks = fsfo->st.blocks;
- sbp->f_bfree = fsfo->st.bfree;
- sbp->f_bavail = fsfo->st.bavail;
- sbp->f_files = fsfo->st.files;
- sbp->f_ffree = fsfo->st.ffree; /* cast from uint64_t to int64_t */
- sbp->f_namemax = fsfo->st.namelen;
- sbp->f_bsize = fsfo->st.frsize; /* cast from uint32_t to uint64_t */
-
- FS_DEBUG("fuse_statfs_out -- blocks: %llu, bfree: %llu, bavail: %llu, "
- "fil es: %llu, ffree: %llu, bsize: %i, namelen: %i\n",
- (unsigned long long)fsfo->st.blocks,
- (unsigned long long)fsfo->st.bfree,
- (unsigned long long)fsfo->st.bavail,
- (unsigned long long)fsfo->st.files,
- (unsigned long long)fsfo->st.ffree, fsfo->st.bsize,
- fsfo->st.namelen);
-
- fdisp_destroy(&fdi);
- return 0;
-
-fake:
- sbp->f_blocks = 0;
- sbp->f_bfree = 0;
- sbp->f_bavail = 0;
- sbp->f_files = 0;
- sbp->f_ffree = 0;
- sbp->f_namemax = 0;
- sbp->f_bsize = FUSE_DEFAULT_BLOCKSIZE;
-
- return 0;
-}
Index: sys/fs/fuse/fuse_vnops.c
===================================================================
--- sys/fs/fuse/fuse_vnops.c
+++ sys/fs/fuse/fuse_vnops.c
@@ -1,2422 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Copyright (c) 2007-2009 Google Inc. and Amit Singh
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Copyright (C) 2005 Csaba Henk.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/types.h>
-#include <sys/module.h>
-#include <sys/systm.h>
-#include <sys/errno.h>
-#include <sys/param.h>
-#include <sys/kernel.h>
-#include <sys/conf.h>
-#include <sys/uio.h>
-#include <sys/malloc.h>
-#include <sys/queue.h>
-#include <sys/lock.h>
-#include <sys/rwlock.h>
-#include <sys/sx.h>
-#include <sys/proc.h>
-#include <sys/mount.h>
-#include <sys/vnode.h>
-#include <sys/namei.h>
-#include <sys/extattr.h>
-#include <sys/stat.h>
-#include <sys/unistd.h>
-#include <sys/filedesc.h>
-#include <sys/file.h>
-#include <sys/fcntl.h>
-#include <sys/dirent.h>
-#include <sys/bio.h>
-#include <sys/buf.h>
-#include <sys/sysctl.h>
-#include <sys/vmmeter.h>
-
-#include <vm/vm.h>
-#include <vm/vm_extern.h>
-#include <vm/pmap.h>
-#include <vm/vm_map.h>
-#include <vm/vm_page.h>
-#include <vm/vm_param.h>
-#include <vm/vm_object.h>
-#include <vm/vm_pager.h>
-#include <vm/vnode_pager.h>
-#include <vm/vm_object.h>
-
-#include "fuse.h"
-#include "fuse_file.h"
-#include "fuse_internal.h"
-#include "fuse_ipc.h"
-#include "fuse_node.h"
-#include "fuse_param.h"
-#include "fuse_io.h"
-
-#include <sys/priv.h>
-
-#define FUSE_DEBUG_MODULE VNOPS
-#include "fuse_debug.h"
-
-/* vnode ops */
-static vop_access_t fuse_vnop_access;
-static vop_close_t fuse_vnop_close;
-static vop_create_t fuse_vnop_create;
-static vop_deleteextattr_t fuse_vnop_deleteextattr;
-static vop_fsync_t fuse_vnop_fsync;
-static vop_getattr_t fuse_vnop_getattr;
-static vop_getextattr_t fuse_vnop_getextattr;
-static vop_inactive_t fuse_vnop_inactive;
-static vop_link_t fuse_vnop_link;
-static vop_listextattr_t fuse_vnop_listextattr;
-static vop_lookup_t fuse_vnop_lookup;
-static vop_mkdir_t fuse_vnop_mkdir;
-static vop_mknod_t fuse_vnop_mknod;
-static vop_open_t fuse_vnop_open;
-static vop_pathconf_t fuse_vnop_pathconf;
-static vop_read_t fuse_vnop_read;
-static vop_readdir_t fuse_vnop_readdir;
-static vop_readlink_t fuse_vnop_readlink;
-static vop_reclaim_t fuse_vnop_reclaim;
-static vop_remove_t fuse_vnop_remove;
-static vop_rename_t fuse_vnop_rename;
-static vop_rmdir_t fuse_vnop_rmdir;
-static vop_setattr_t fuse_vnop_setattr;
-static vop_setextattr_t fuse_vnop_setextattr;
-static vop_strategy_t fuse_vnop_strategy;
-static vop_symlink_t fuse_vnop_symlink;
-static vop_write_t fuse_vnop_write;
-static vop_getpages_t fuse_vnop_getpages;
-static vop_putpages_t fuse_vnop_putpages;
-static vop_print_t fuse_vnop_print;
-
-struct vop_vector fuse_vnops = {
- .vop_default = &default_vnodeops,
- .vop_access = fuse_vnop_access,
- .vop_close = fuse_vnop_close,
- .vop_create = fuse_vnop_create,
- .vop_deleteextattr = fuse_vnop_deleteextattr,
- .vop_fsync = fuse_vnop_fsync,
- .vop_getattr = fuse_vnop_getattr,
- .vop_getextattr = fuse_vnop_getextattr,
- .vop_inactive = fuse_vnop_inactive,
- .vop_link = fuse_vnop_link,
- .vop_listextattr = fuse_vnop_listextattr,
- .vop_lookup = fuse_vnop_lookup,
- .vop_mkdir = fuse_vnop_mkdir,
- .vop_mknod = fuse_vnop_mknod,
- .vop_open = fuse_vnop_open,
- .vop_pathconf = fuse_vnop_pathconf,
- .vop_read = fuse_vnop_read,
- .vop_readdir = fuse_vnop_readdir,
- .vop_readlink = fuse_vnop_readlink,
- .vop_reclaim = fuse_vnop_reclaim,
- .vop_remove = fuse_vnop_remove,
- .vop_rename = fuse_vnop_rename,
- .vop_rmdir = fuse_vnop_rmdir,
- .vop_setattr = fuse_vnop_setattr,
- .vop_setextattr = fuse_vnop_setextattr,
- .vop_strategy = fuse_vnop_strategy,
- .vop_symlink = fuse_vnop_symlink,
- .vop_write = fuse_vnop_write,
- .vop_getpages = fuse_vnop_getpages,
- .vop_putpages = fuse_vnop_putpages,
- .vop_print = fuse_vnop_print,
-};
-
-static u_long fuse_lookup_cache_hits = 0;
-
-SYSCTL_ULONG(_vfs_fuse, OID_AUTO, lookup_cache_hits, CTLFLAG_RD,
- &fuse_lookup_cache_hits, 0, "number of positive cache hits in lookup");
-
-static u_long fuse_lookup_cache_misses = 0;
-
-SYSCTL_ULONG(_vfs_fuse, OID_AUTO, lookup_cache_misses, CTLFLAG_RD,
- &fuse_lookup_cache_misses, 0, "number of cache misses in lookup");
-
-int fuse_lookup_cache_enable = 1;
-
-SYSCTL_INT(_vfs_fuse, OID_AUTO, lookup_cache_enable, CTLFLAG_RW,
- &fuse_lookup_cache_enable, 0, "if non-zero, enable lookup cache");
-
-/*
- * XXX: This feature is highly experimental and can bring to instabilities,
- * needs revisiting before to be enabled by default.
- */
-static int fuse_reclaim_revoked = 0;
-
-SYSCTL_INT(_vfs_fuse, OID_AUTO, reclaim_revoked, CTLFLAG_RW,
- &fuse_reclaim_revoked, 0, "");
-
-uma_zone_t fuse_pbuf_zone;
-
-#define fuse_vm_page_lock(m) vm_page_lock((m));
-#define fuse_vm_page_unlock(m) vm_page_unlock((m));
-#define fuse_vm_page_lock_queues() ((void)0)
-#define fuse_vm_page_unlock_queues() ((void)0)
-
-/*
- struct vnop_access_args {
- struct vnode *a_vp;
-#if VOP_ACCESS_TAKES_ACCMODE_T
- accmode_t a_accmode;
-#else
- int a_mode;
-#endif
- struct ucred *a_cred;
- struct thread *a_td;
- };
-*/
-static int
-fuse_vnop_access(struct vop_access_args *ap)
-{
- struct vnode *vp = ap->a_vp;
- int accmode = ap->a_accmode;
- struct ucred *cred = ap->a_cred;
-
- struct fuse_access_param facp;
- struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp));
-
- int err;
-
- FS_DEBUG2G("inode=%ju\n", (uintmax_t)VTOI(vp));
-
- if (fuse_isdeadfs(vp)) {
- if (vnode_isvroot(vp)) {
- return 0;
- }
- return ENXIO;
- }
- if (!(data->dataflags & FSESS_INITED)) {
- if (vnode_isvroot(vp)) {
- if (priv_check_cred(cred, PRIV_VFS_ADMIN) ||
- (fuse_match_cred(data->daemoncred, cred) == 0)) {
- return 0;
- }
- }
- return EBADF;
- }
- if (vnode_islnk(vp)) {
- return 0;
- }
- bzero(&facp, sizeof(facp));
-
- err = fuse_internal_access(vp, accmode, &facp, ap->a_td, ap->a_cred);
- FS_DEBUG2G("err=%d accmode=0x%x\n", err, accmode);
- return err;
-}
-
-/*
- struct vnop_close_args {
- struct vnode *a_vp;
- int a_fflag;
- struct ucred *a_cred;
- struct thread *a_td;
- };
-*/
-static int
-fuse_vnop_close(struct vop_close_args *ap)
-{
- struct vnode *vp = ap->a_vp;
- struct ucred *cred = ap->a_cred;
- int fflag = ap->a_fflag;
- fufh_type_t fufh_type;
-
- fuse_trace_printf_vnop();
-
- if (fuse_isdeadfs(vp)) {
- return 0;
- }
- if (vnode_isdir(vp)) {
- if (fuse_filehandle_valid(vp, FUFH_RDONLY)) {
- fuse_filehandle_close(vp, FUFH_RDONLY, NULL, cred);
- }
- return 0;
- }
- if (fflag & IO_NDELAY) {
- return 0;
- }
- fufh_type = fuse_filehandle_xlate_from_fflags(fflag);
-
- if (!fuse_filehandle_valid(vp, fufh_type)) {
- int i;
-
- for (i = 0; i < FUFH_MAXTYPE; i++)
- if (fuse_filehandle_valid(vp, i))
- break;
- if (i == FUFH_MAXTYPE)
- panic("FUSE: fufh type %d found to be invalid in close"
- " (fflag=0x%x)\n",
- fufh_type, fflag);
- }
- if ((VTOFUD(vp)->flag & FN_SIZECHANGE) != 0) {
- fuse_vnode_savesize(vp, cred);
- }
- return 0;
-}
-
-/*
- struct vnop_create_args {
- struct vnode *a_dvp;
- struct vnode **a_vpp;
- struct componentname *a_cnp;
- struct vattr *a_vap;
- };
-*/
-static int
-fuse_vnop_create(struct vop_create_args *ap)
-{
- struct vnode *dvp = ap->a_dvp;
- struct vnode **vpp = ap->a_vpp;
- struct componentname *cnp = ap->a_cnp;
- struct vattr *vap = ap->a_vap;
- struct thread *td = cnp->cn_thread;
- struct ucred *cred = cnp->cn_cred;
-
- struct fuse_open_in *foi;
- struct fuse_entry_out *feo;
- struct fuse_dispatcher fdi;
- struct fuse_dispatcher *fdip = &fdi;
-
- int err;
-
- struct mount *mp = vnode_mount(dvp);
- uint64_t parentnid = VTOFUD(dvp)->nid;
- mode_t mode = MAKEIMODE(vap->va_type, vap->va_mode);
- uint64_t x_fh_id;
- uint32_t x_open_flags;
-
- fuse_trace_printf_vnop();
-
- if (fuse_isdeadfs(dvp)) {
- return ENXIO;
- }
- bzero(&fdi, sizeof(fdi));
-
- /* XXX: Will we ever want devices ? */
- if ((vap->va_type != VREG)) {
- printf("fuse_vnop_create: unsupported va_type %d\n",
- vap->va_type);
- return (EINVAL);
- }
- debug_printf("parent nid = %ju, mode = %x\n", (uintmax_t)parentnid,
- mode);
-
- fdisp_init(fdip, sizeof(*foi) + cnp->cn_namelen + 1);
- if (!fsess_isimpl(mp, FUSE_CREATE)) {
- debug_printf("eh, daemon doesn't implement create?\n");
- return (EINVAL);
- }
- fdisp_make(fdip, FUSE_CREATE, vnode_mount(dvp), parentnid, td, cred);
-
- foi = fdip->indata;
- foi->mode = mode;
- foi->flags = O_CREAT | O_RDWR;
-
- memcpy((char *)fdip->indata + sizeof(*foi), cnp->cn_nameptr,
- cnp->cn_namelen);
- ((char *)fdip->indata)[sizeof(*foi) + cnp->cn_namelen] = '\0';
-
- err = fdisp_wait_answ(fdip);
-
- if (err) {
- if (err == ENOSYS)
- fsess_set_notimpl(mp, FUSE_CREATE);
- debug_printf("create: got err=%d from daemon\n", err);
- goto out;
- }
-
- feo = fdip->answ;
-
- if ((err = fuse_internal_checkentry(feo, VREG))) {
- goto out;
- }
- err = fuse_vnode_get(mp, feo, feo->nodeid, dvp, vpp, cnp, VREG);
- if (err) {
- struct fuse_release_in *fri;
- uint64_t nodeid = feo->nodeid;
- uint64_t fh_id = ((struct fuse_open_out *)(feo + 1))->fh;
-
- fdisp_init(fdip, sizeof(*fri));
- fdisp_make(fdip, FUSE_RELEASE, mp, nodeid, td, cred);
- fri = fdip->indata;
- fri->fh = fh_id;
- fri->flags = OFLAGS(mode);
- fuse_insert_callback(fdip->tick, fuse_internal_forget_callback);
- fuse_insert_message(fdip->tick);
- return err;
- }
- ASSERT_VOP_ELOCKED(*vpp, "fuse_vnop_create");
-
- fdip->answ = feo + 1;
-
- x_fh_id = ((struct fuse_open_out *)(feo + 1))->fh;
- x_open_flags = ((struct fuse_open_out *)(feo + 1))->open_flags;
- fuse_filehandle_init(*vpp, FUFH_RDWR, NULL, x_fh_id);
- fuse_vnode_open(*vpp, x_open_flags, td);
- cache_purge_negative(dvp);
-
-out:
- fdisp_destroy(fdip);
- return err;
-}
-
-/*
- * Our vnop_fsync roughly corresponds to the FUSE_FSYNC method. The Linux
- * version of FUSE also has a FUSE_FLUSH method.
- *
- * On Linux, fsync() synchronizes a file's complete in-core state with that
- * on disk. The call is not supposed to return until the system has completed
- * that action or until an error is detected.
- *
- * Linux also has an fdatasync() call that is similar to fsync() but is not
- * required to update the metadata such as access time and modification time.
- */
-
-/*
- struct vnop_fsync_args {
- struct vnodeop_desc *a_desc;
- struct vnode * a_vp;
- struct ucred * a_cred;
- int a_waitfor;
- struct thread * a_td;
- };
-*/
-static int
-fuse_vnop_fsync(struct vop_fsync_args *ap)
-{
- struct vnode *vp = ap->a_vp;
- struct thread *td = ap->a_td;
-
- struct fuse_filehandle *fufh;
- struct fuse_vnode_data *fvdat = VTOFUD(vp);
-
- int type, err = 0;
-
- fuse_trace_printf_vnop();
-
- if (fuse_isdeadfs(vp)) {
- return 0;
- }
- if ((err = vop_stdfsync(ap)))
- return err;
-
- if (!fsess_isimpl(vnode_mount(vp),
- (vnode_vtype(vp) == VDIR ? FUSE_FSYNCDIR : FUSE_FSYNC))) {
- goto out;
- }
- for (type = 0; type < FUFH_MAXTYPE; type++) {
- fufh = &(fvdat->fufh[type]);
- if (FUFH_IS_VALID(fufh)) {
- fuse_internal_fsync(vp, td, NULL, fufh);
- }
- }
-
-out:
- return 0;
-}
-
-/*
- struct vnop_getattr_args {
- struct vnode *a_vp;
- struct vattr *a_vap;
- struct ucred *a_cred;
- struct thread *a_td;
- };
-*/
-static int
-fuse_vnop_getattr(struct vop_getattr_args *ap)
-{
- struct vnode *vp = ap->a_vp;
- struct vattr *vap = ap->a_vap;
- struct ucred *cred = ap->a_cred;
- struct thread *td = curthread;
- struct fuse_vnode_data *fvdat = VTOFUD(vp);
-
- int err = 0;
- int dataflags;
- struct fuse_dispatcher fdi;
-
- FS_DEBUG2G("inode=%ju\n", (uintmax_t)VTOI(vp));
-
- dataflags = fuse_get_mpdata(vnode_mount(vp))->dataflags;
-
- /* Note that we are not bailing out on a dead file system just yet. */
-
- if (!(dataflags & FSESS_INITED)) {
- if (!vnode_isvroot(vp)) {
- fdata_set_dead(fuse_get_mpdata(vnode_mount(vp)));
- err = ENOTCONN;
- debug_printf("fuse_getattr b: returning ENOTCONN\n");
- return err;
- } else {
- goto fake;
- }
- }
- fdisp_init(&fdi, 0);
- if ((err = fdisp_simple_putget_vp(&fdi, FUSE_GETATTR, vp, td, cred))) {
- if ((err == ENOTCONN) && vnode_isvroot(vp)) {
- /* see comment at similar place in fuse_statfs() */
- fdisp_destroy(&fdi);
- goto fake;
- }
- if (err == ENOENT) {
- fuse_internal_vnode_disappear(vp);
- }
- goto out;
- }
-
- cache_attrs(vp, (struct fuse_attr_out *)fdi.answ, vap);
- if (vap->va_type != vnode_vtype(vp)) {
- fuse_internal_vnode_disappear(vp);
- err = ENOENT;
- goto out;
- }
- if ((fvdat->flag & FN_SIZECHANGE) != 0)
- vap->va_size = fvdat->filesize;
-
- if (vnode_isreg(vp) && (fvdat->flag & FN_SIZECHANGE) == 0) {
- /*
- * This is for those cases when the file size changed without us
- * knowing, and we want to catch up.
- */
- off_t new_filesize = ((struct fuse_attr_out *)
- fdi.answ)->attr.size;
-
- if (fvdat->filesize != new_filesize) {
- fuse_vnode_setsize(vp, cred, new_filesize);
- fvdat->flag &= ~FN_SIZECHANGE;
- }
- }
- debug_printf("fuse_getattr e: returning 0\n");
-
-out:
- fdisp_destroy(&fdi);
- return err;
-
-fake:
- bzero(vap, sizeof(*vap));
- vap->va_type = vnode_vtype(vp);
-
- return 0;
-}
-
-/*
- struct vnop_inactive_args {
- struct vnode *a_vp;
- struct thread *a_td;
- };
-*/
-static int
-fuse_vnop_inactive(struct vop_inactive_args *ap)
-{
- struct vnode *vp = ap->a_vp;
- struct thread *td = ap->a_td;
-
- struct fuse_vnode_data *fvdat = VTOFUD(vp);
- struct fuse_filehandle *fufh = NULL;
-
- int type, need_flush = 1;
-
- FS_DEBUG("inode=%ju\n", (uintmax_t)VTOI(vp));
-
- for (type = 0; type < FUFH_MAXTYPE; type++) {
- fufh = &(fvdat->fufh[type]);
- if (FUFH_IS_VALID(fufh)) {
- if (need_flush && vp->v_type == VREG) {
- if ((VTOFUD(vp)->flag & FN_SIZECHANGE) != 0) {
- fuse_vnode_savesize(vp, NULL);
- }
- if (fuse_data_cache_invalidate ||
- (fvdat->flag & FN_REVOKED) != 0)
- fuse_io_invalbuf(vp, td);
- else
- fuse_io_flushbuf(vp, MNT_WAIT, td);
- need_flush = 0;
- }
- fuse_filehandle_close(vp, type, td, NULL);
- }
- }
-
- if ((fvdat->flag & FN_REVOKED) != 0 && fuse_reclaim_revoked) {
- vrecycle(vp);
- }
- return 0;
-}
-
-/*
- struct vnop_link_args {
- struct vnode *a_tdvp;
- struct vnode *a_vp;
- struct componentname *a_cnp;
- };
-*/
-static int
-fuse_vnop_link(struct vop_link_args *ap)
-{
- struct vnode *vp = ap->a_vp;
- struct vnode *tdvp = ap->a_tdvp;
- struct componentname *cnp = ap->a_cnp;
-
- struct vattr *vap = VTOVA(vp);
-
- struct fuse_dispatcher fdi;
- struct fuse_entry_out *feo;
- struct fuse_link_in fli;
-
- int err;
-
- fuse_trace_printf_vnop();
-
- if (fuse_isdeadfs(vp)) {
- return ENXIO;
- }
- if (vnode_mount(tdvp) != vnode_mount(vp)) {
- return EXDEV;
- }
-
- /*
- * This is a seatbelt check to protect naive userspace filesystems from
- * themselves and the limitations of the FUSE IPC protocol. If a
- * filesystem does not allow attribute caching, assume it is capable of
- * validating that nlink does not overflow.
- */
- if (vap != NULL && vap->va_nlink >= FUSE_LINK_MAX)
- return EMLINK;
- fli.oldnodeid = VTOI(vp);
-
- fdisp_init(&fdi, 0);
- fuse_internal_newentry_makerequest(vnode_mount(tdvp), VTOI(tdvp), cnp,
- FUSE_LINK, &fli, sizeof(fli), &fdi);
- if ((err = fdisp_wait_answ(&fdi))) {
- goto out;
- }
- feo = fdi.answ;
-
- err = fuse_internal_checkentry(feo, vnode_vtype(vp));
-out:
- fdisp_destroy(&fdi);
- return err;
-}
-
-/*
- struct vnop_lookup_args {
- struct vnodeop_desc *a_desc;
- struct vnode *a_dvp;
- struct vnode **a_vpp;
- struct componentname *a_cnp;
- };
-*/
-int
-fuse_vnop_lookup(struct vop_lookup_args *ap)
-{
- struct vnode *dvp = ap->a_dvp;
- struct vnode **vpp = ap->a_vpp;
- struct componentname *cnp = ap->a_cnp;
- struct thread *td = cnp->cn_thread;
- struct ucred *cred = cnp->cn_cred;
-
- int nameiop = cnp->cn_nameiop;
- int flags = cnp->cn_flags;
- int wantparent = flags & (LOCKPARENT | WANTPARENT);
- int islastcn = flags & ISLASTCN;
- struct mount *mp = vnode_mount(dvp);
-
- int err = 0;
- int lookup_err = 0;
- struct vnode *vp = NULL;
-
- struct fuse_dispatcher fdi;
- enum fuse_opcode op;
-
- uint64_t nid;
- struct fuse_access_param facp;
-
- FS_DEBUG2G("parent_inode=%ju - %*s\n",
- (uintmax_t)VTOI(dvp), (int)cnp->cn_namelen, cnp->cn_nameptr);
-
- if (fuse_isdeadfs(dvp)) {
- *vpp = NULL;
- return ENXIO;
- }
- if (!vnode_isdir(dvp)) {
- return ENOTDIR;
- }
- if (islastcn && vfs_isrdonly(mp) && (nameiop != LOOKUP)) {
- return EROFS;
- }
- /*
- * We do access check prior to doing anything else only in the case
- * when we are at fs root (we'd like to say, "we are at the first
- * component", but that's not exactly the same... nevermind).
- * See further comments at further access checks.
- */
-
- bzero(&facp, sizeof(facp));
- if (vnode_isvroot(dvp)) { /* early permission check hack */
- if ((err = fuse_internal_access(dvp, VEXEC, &facp, td, cred))) {
- return err;
- }
- }
- if (flags & ISDOTDOT) {
- nid = VTOFUD(dvp)->parent_nid;
- if (nid == 0) {
- return ENOENT;
- }
- fdisp_init(&fdi, 0);
- op = FUSE_GETATTR;
- goto calldaemon;
- } else if (cnp->cn_namelen == 1 && *(cnp->cn_nameptr) == '.') {
- nid = VTOI(dvp);
- fdisp_init(&fdi, 0);
- op = FUSE_GETATTR;
- goto calldaemon;
- } else if (fuse_lookup_cache_enable) {
- err = cache_lookup(dvp, vpp, cnp, NULL, NULL);
- switch (err) {
-
- case -1: /* positive match */
- atomic_add_acq_long(&fuse_lookup_cache_hits, 1);
- return 0;
-
- case 0: /* no match in cache */
- atomic_add_acq_long(&fuse_lookup_cache_misses, 1);
- break;
-
- case ENOENT: /* negative match */
- /* fall through */
- default:
- return err;
- }
- }
- nid = VTOI(dvp);
- fdisp_init(&fdi, cnp->cn_namelen + 1);
- op = FUSE_LOOKUP;
-
-calldaemon:
- fdisp_make(&fdi, op, mp, nid, td, cred);
-
- if (op == FUSE_LOOKUP) {
- memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
- ((char *)fdi.indata)[cnp->cn_namelen] = '\0';
- }
- lookup_err = fdisp_wait_answ(&fdi);
-
- if ((op == FUSE_LOOKUP) && !lookup_err) { /* lookup call succeeded */
- nid = ((struct fuse_entry_out *)fdi.answ)->nodeid;
- if (!nid) {
- /*
- * zero nodeid is the same as "not found",
- * but it's also cacheable (which we keep
- * keep on doing not as of writing this)
- */
- lookup_err = ENOENT;
- } else if (nid == FUSE_ROOT_ID) {
- lookup_err = EINVAL;
- }
- }
- if (lookup_err &&
- (!fdi.answ_stat || lookup_err != ENOENT || op != FUSE_LOOKUP)) {
- fdisp_destroy(&fdi);
- return lookup_err;
- }
- /* lookup_err, if non-zero, must be ENOENT at this point */
-
- if (lookup_err) {
-
- if ((nameiop == CREATE || nameiop == RENAME) && islastcn
- /* && directory dvp has not been removed */ ) {
-
- if (vfs_isrdonly(mp)) {
- err = EROFS;
- goto out;
- }
-#if 0 /* THINK_ABOUT_THIS */
- if ((err = fuse_internal_access(dvp, VWRITE, cred, td, &facp))) {
- goto out;
- }
-#endif
-
- /*
- * Possibly record the position of a slot in the
- * directory large enough for the new component name.
- * This can be recorded in the vnode private data for
- * dvp. Set the SAVENAME flag to hold onto the
- * pathname for use later in VOP_CREATE or VOP_RENAME.
- */
- cnp->cn_flags |= SAVENAME;
-
- err = EJUSTRETURN;
- goto out;
- }
- /* Consider inserting name into cache. */
-
- /*
- * No we can't use negative caching, as the fs
- * changes are out of our control.
- * False positives' falseness turns out just as things
- * go by, but false negatives' falseness doesn't.
- * (and aiding the caching mechanism with extra control
- * mechanisms comes quite close to beating the whole purpose
- * caching...)
- */
-#if 0
- if ((cnp->cn_flags & MAKEENTRY) != 0) {
- FS_DEBUG("inserting NULL into cache\n");
- cache_enter(dvp, NULL, cnp);
- }
-#endif
- err = ENOENT;
- goto out;
-
- } else {
-
- /* !lookup_err */
-
- struct fuse_entry_out *feo = NULL;
- struct fuse_attr *fattr = NULL;
-
- if (op == FUSE_GETATTR) {
- fattr = &((struct fuse_attr_out *)fdi.answ)->attr;
- } else {
- feo = (struct fuse_entry_out *)fdi.answ;
- fattr = &(feo->attr);
- }
-
- /*
- * If deleting, and at end of pathname, return parameters
- * which can be used to remove file. If the wantparent flag
- * isn't set, we return only the directory, otherwise we go on
- * and lock the inode, being careful with ".".
- */
- if (nameiop == DELETE && islastcn) {
- /*
- * Check for write access on directory.
- */
- facp.xuid = fattr->uid;
- facp.facc_flags |= FACCESS_STICKY;
- err = fuse_internal_access(dvp, VWRITE, &facp, td, cred);
- facp.facc_flags &= ~FACCESS_XQUERIES;
-
- if (err) {
- goto out;
- }
- if (nid == VTOI(dvp)) {
- vref(dvp);
- *vpp = dvp;
- } else {
- err = fuse_vnode_get(dvp->v_mount, feo, nid,
- dvp, &vp, cnp, IFTOVT(fattr->mode));
- if (err)
- goto out;
- *vpp = vp;
- }
-
- /*
- * Save the name for use in VOP_RMDIR and VOP_REMOVE
- * later.
- */
- cnp->cn_flags |= SAVENAME;
- goto out;
-
- }
- /*
- * If rewriting (RENAME), return the inode and the
- * information required to rewrite the present directory
- * Must get inode of directory entry to verify it's a
- * regular file, or empty directory.
- */
- if (nameiop == RENAME && wantparent && islastcn) {
-
-#if 0 /* THINK_ABOUT_THIS */
- if ((err = fuse_internal_access(dvp, VWRITE, cred, td, &facp))) {
- goto out;
- }
-#endif
-
- /*
- * Check for "."
- */
- if (nid == VTOI(dvp)) {
- err = EISDIR;
- goto out;
- }
- err = fuse_vnode_get(vnode_mount(dvp), feo, nid, dvp,
- &vp, cnp, IFTOVT(fattr->mode));
- if (err) {
- goto out;
- }
- *vpp = vp;
- /*
- * Save the name for use in VOP_RENAME later.
- */
- cnp->cn_flags |= SAVENAME;
-
- goto out;
- }
- if (flags & ISDOTDOT) {
- struct mount *mp;
- int ltype;
-
- /*
- * Expanded copy of vn_vget_ino() so that
- * fuse_vnode_get() can be used.
- */
- mp = dvp->v_mount;
- ltype = VOP_ISLOCKED(dvp);
- err = vfs_busy(mp, MBF_NOWAIT);
- if (err != 0) {
- vfs_ref(mp);
- VOP_UNLOCK(dvp, 0);
- err = vfs_busy(mp, 0);
- vn_lock(dvp, ltype | LK_RETRY);
- vfs_rel(mp);
- if (err)
- goto out;
- if ((dvp->v_iflag & VI_DOOMED) != 0) {
- err = ENOENT;
- vfs_unbusy(mp);
- goto out;
- }
- }
- VOP_UNLOCK(dvp, 0);
- err = fuse_vnode_get(vnode_mount(dvp), feo, nid, NULL,
- &vp, cnp, IFTOVT(fattr->mode));
- vfs_unbusy(mp);
- vn_lock(dvp, ltype | LK_RETRY);
- if ((dvp->v_iflag & VI_DOOMED) != 0) {
- if (err == 0)
- vput(vp);
- err = ENOENT;
- }
- if (err)
- goto out;
- *vpp = vp;
- } else if (nid == VTOI(dvp)) {
- vref(dvp);
- *vpp = dvp;
- } else {
- struct fuse_vnode_data *fvdat;
-
- err = fuse_vnode_get(vnode_mount(dvp), feo, nid, dvp,
- &vp, cnp, IFTOVT(fattr->mode));
- if (err) {
- goto out;
- }
- fuse_vnode_setparent(vp, dvp);
-
- /*
- * In the case where we are looking up a FUSE node
- * represented by an existing cached vnode, and the
- * true size reported by FUSE_LOOKUP doesn't match
- * the vnode's cached size, fix the vnode cache to
- * match the real object size.
- *
- * This can occur via FUSE distributed filesystems,
- * irregular files, etc.
- */
- fvdat = VTOFUD(vp);
- if (vnode_isreg(vp) &&
- fattr->size != fvdat->filesize) {
- /*
- * The FN_SIZECHANGE flag reflects a dirty
- * append. If userspace lets us know our cache
- * is invalid, that write was lost. (Dirty
- * writes that do not cause append are also
- * lost, but we don't detect them here.)
- *
- * XXX: Maybe disable WB caching on this mount.
- */
- if (fvdat->flag & FN_SIZECHANGE)
- printf("%s: WB cache incoherent on "
- "%s!\n", __func__,
- vnode_mount(vp)->mnt_stat.f_mntonname);
-
- (void)fuse_vnode_setsize(vp, cred, fattr->size);
- fvdat->flag &= ~FN_SIZECHANGE;
- }
- *vpp = vp;
- }
-
- if (op == FUSE_GETATTR) {
- cache_attrs(*vpp, (struct fuse_attr_out *)fdi.answ,
- NULL);
- } else {
- cache_attrs(*vpp, (struct fuse_entry_out *)fdi.answ,
- NULL);
- }
-
- /* Insert name into cache if appropriate. */
-
- /*
- * Nooo, caching is evil. With caching, we can't avoid stale
- * information taking over the playground (cached info is not
- * just positive/negative, it does have qualitative aspects,
- * too). And a (VOP/FUSE)_GETATTR is always thrown anyway, when
- * walking down along cached path components, and that's not
- * any cheaper than FUSE_LOOKUP. This might change with
- * implementing kernel side attr caching, but... In Linux,
- * lookup results are not cached, and the daemon is bombarded
- * with FUSE_LOOKUPS on and on. This shows that by design, the
- * daemon is expected to handle frequent lookup queries
- * efficiently, do its caching in userspace, and so on.
- *
- * So just leave the name cache alone.
- */
-
- /*
- * Well, now I know, Linux caches lookups, but with a
- * timeout... So it's the same thing as attribute caching:
- * we can deal with it when implement timeouts.
- */
-#if 0
- if (cnp->cn_flags & MAKEENTRY) {
- cache_enter(dvp, *vpp, cnp);
- }
-#endif
- }
-out:
- if (!lookup_err) {
-
- /* No lookup error; need to clean up. */
-
- if (err) { /* Found inode; exit with no vnode. */
- if (op == FUSE_LOOKUP) {
- fuse_internal_forget_send(vnode_mount(dvp), td, cred,
- nid, 1);
- }
- fdisp_destroy(&fdi);
- return err;
- } else {
-#ifndef NO_EARLY_PERM_CHECK_HACK
- if (!islastcn) {
- /*
- * We have the attributes of the next item
- * *now*, and it's a fact, and we do not
- * have to do extra work for it (ie, beg the
- * daemon), and it neither depends on such
- * accidental things like attr caching. So
- * the big idea: check credentials *now*,
- * not at the beginning of the next call to
- * lookup.
- *
- * The first item of the lookup chain (fs root)
- * won't be checked then here, of course, as
- * its never "the next". But go and see that
- * the root is taken care about at the very
- * beginning of this function.
- *
- * Now, given we want to do the access check
- * this way, one might ask: so then why not
- * do the access check just after fetching
- * the inode and its attributes from the
- * daemon? Why bother with producing the
- * corresponding vnode at all if something
- * is not OK? We know what's the deal as
- * soon as we get those attrs... There is
- * one bit of info though not given us by
- * the daemon: whether his response is
- * authoritative or not... His response should
- * be ignored if something is mounted over
- * the dir in question. But that can be
- * known only by having the vnode...
- */
- int tmpvtype = vnode_vtype(*vpp);
-
- bzero(&facp, sizeof(facp));
- /*the early perm check hack */
- facp.facc_flags |= FACCESS_VA_VALID;
-
- if ((tmpvtype != VDIR) && (tmpvtype != VLNK)) {
- err = ENOTDIR;
- }
- if (!err && !vnode_mountedhere(*vpp)) {
- err = fuse_internal_access(*vpp, VEXEC, &facp, td, cred);
- }
- if (err) {
- if (tmpvtype == VLNK)
- FS_DEBUG("weird, permission error with a symlink?\n");
- vput(*vpp);
- *vpp = NULL;
- }
- }
-#endif
- }
- }
- fdisp_destroy(&fdi);
-
- return err;
-}
-
-/*
- struct vnop_mkdir_args {
- struct vnode *a_dvp;
- struct vnode **a_vpp;
- struct componentname *a_cnp;
- struct vattr *a_vap;
- };
-*/
-static int
-fuse_vnop_mkdir(struct vop_mkdir_args *ap)
-{
- struct vnode *dvp = ap->a_dvp;
- struct vnode **vpp = ap->a_vpp;
- struct componentname *cnp = ap->a_cnp;
- struct vattr *vap = ap->a_vap;
-
- struct fuse_mkdir_in fmdi;
-
- fuse_trace_printf_vnop();
-
- if (fuse_isdeadfs(dvp)) {
- return ENXIO;
- }
- fmdi.mode = MAKEIMODE(vap->va_type, vap->va_mode);
-
- return (fuse_internal_newentry(dvp, vpp, cnp, FUSE_MKDIR, &fmdi,
- sizeof(fmdi), VDIR));
-}
-
-/*
- struct vnop_mknod_args {
- struct vnode *a_dvp;
- struct vnode **a_vpp;
- struct componentname *a_cnp;
- struct vattr *a_vap;
- };
-*/
-static int
-fuse_vnop_mknod(struct vop_mknod_args *ap)
-{
-
- return (EINVAL);
-}
-
-
-/*
- struct vnop_open_args {
- struct vnode *a_vp;
- int a_mode;
- struct ucred *a_cred;
- struct thread *a_td;
- int a_fdidx; / struct file *a_fp;
- };
-*/
-static int
-fuse_vnop_open(struct vop_open_args *ap)
-{
- struct vnode *vp = ap->a_vp;
- int mode = ap->a_mode;
- struct thread *td = ap->a_td;
- struct ucred *cred = ap->a_cred;
-
- fufh_type_t fufh_type;
- struct fuse_vnode_data *fvdat;
-
- int error, isdir = 0;
- int32_t fuse_open_flags;
-
- FS_DEBUG2G("inode=%ju mode=0x%x\n", (uintmax_t)VTOI(vp), mode);
-
- if (fuse_isdeadfs(vp)) {
- return ENXIO;
- }
- if ((mode & (FREAD | FWRITE)) == 0)
- return EINVAL;
-
- fvdat = VTOFUD(vp);
-
- if (vnode_isdir(vp)) {
- isdir = 1;
- }
- fuse_open_flags = 0;
- if (isdir) {
- fufh_type = FUFH_RDONLY;
- } else {
- fufh_type = fuse_filehandle_xlate_from_fflags(mode);
- /*
- * For WRONLY opens, force DIRECT_IO. This is necessary
- * since writing a partial block through the buffer cache
- * will result in a read of the block and that read won't
- * be allowed by the WRONLY open.
- */
- if (fufh_type == FUFH_WRONLY ||
- (fvdat->flag & FN_DIRECTIO) != 0)
- fuse_open_flags = FOPEN_DIRECT_IO;
- }
-
- if (fuse_filehandle_validrw(vp, fufh_type) != FUFH_INVALID) {
- fuse_vnode_open(vp, fuse_open_flags, td);
- return 0;
- }
- error = fuse_filehandle_open(vp, fufh_type, NULL, td, cred);
-
- return error;
-}
-
-static int
-fuse_vnop_pathconf(struct vop_pathconf_args *ap)
-{
-
- switch (ap->a_name) {
- case _PC_FILESIZEBITS:
- *ap->a_retval = 64;
- return (0);
- case _PC_NAME_MAX:
- *ap->a_retval = NAME_MAX;
- return (0);
- case _PC_LINK_MAX:
- *ap->a_retval = MIN(LONG_MAX, FUSE_LINK_MAX);
- return (0);
- case _PC_SYMLINK_MAX:
- *ap->a_retval = MAXPATHLEN;
- return (0);
- case _PC_NO_TRUNC:
- *ap->a_retval = 1;
- return (0);
- default:
- return (vop_stdpathconf(ap));
- }
-}
-
-/*
- struct vnop_read_args {
- struct vnode *a_vp;
- struct uio *a_uio;
- int a_ioflag;
- struct ucred *a_cred;
- };
-*/
-static int
-fuse_vnop_read(struct vop_read_args *ap)
-{
- struct vnode *vp = ap->a_vp;
- struct uio *uio = ap->a_uio;
- int ioflag = ap->a_ioflag;
- struct ucred *cred = ap->a_cred;
-
- FS_DEBUG2G("inode=%ju offset=%jd resid=%zd\n",
- (uintmax_t)VTOI(vp), uio->uio_offset, uio->uio_resid);
-
- if (fuse_isdeadfs(vp)) {
- return ENXIO;
- }
-
- if (VTOFUD(vp)->flag & FN_DIRECTIO) {
- ioflag |= IO_DIRECT;
- }
-
- return fuse_io_dispatch(vp, uio, ioflag, cred);
-}
-
-/*
- struct vnop_readdir_args {
- struct vnode *a_vp;
- struct uio *a_uio;
- struct ucred *a_cred;
- int *a_eofflag;
- int *ncookies;
- u_long **a_cookies;
- };
-*/
-static int
-fuse_vnop_readdir(struct vop_readdir_args *ap)
-{
- struct vnode *vp = ap->a_vp;
- struct uio *uio = ap->a_uio;
- struct ucred *cred = ap->a_cred;
-
- struct fuse_filehandle *fufh = NULL;
- struct fuse_iov cookediov;
-
- int err = 0;
- int freefufh = 0;
-
- FS_DEBUG2G("inode=%ju\n", (uintmax_t)VTOI(vp));
-
- if (fuse_isdeadfs(vp)) {
- return ENXIO;
- }
- if ( /* XXXIP ((uio_iovcnt(uio) > 1)) || */
- (uio_resid(uio) < sizeof(struct dirent))) {
- return EINVAL;
- }
-
- if (!fuse_filehandle_valid(vp, FUFH_RDONLY)) {
- FS_DEBUG("calling readdir() before open()");
- err = fuse_filehandle_open(vp, FUFH_RDONLY, &fufh, NULL, cred);
- freefufh = 1;
- } else {
- err = fuse_filehandle_get(vp, FUFH_RDONLY, &fufh);
- }
- if (err) {
- return (err);
- }
-#define DIRCOOKEDSIZE FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + MAXNAMLEN + 1)
- fiov_init(&cookediov, DIRCOOKEDSIZE);
-
- err = fuse_internal_readdir(vp, uio, fufh, &cookediov);
-
- fiov_teardown(&cookediov);
- if (freefufh) {
- fuse_filehandle_close(vp, FUFH_RDONLY, NULL, cred);
- }
- return err;
-}
-
-/*
- struct vnop_readlink_args {
- struct vnode *a_vp;
- struct uio *a_uio;
- struct ucred *a_cred;
- };
-*/
-static int
-fuse_vnop_readlink(struct vop_readlink_args *ap)
-{
- struct vnode *vp = ap->a_vp;
- struct uio *uio = ap->a_uio;
- struct ucred *cred = ap->a_cred;
-
- struct fuse_dispatcher fdi;
- int err;
-
- FS_DEBUG2G("inode=%ju\n", (uintmax_t)VTOI(vp));
-
- if (fuse_isdeadfs(vp)) {
- return ENXIO;
- }
- if (!vnode_islnk(vp)) {
- return EINVAL;
- }
- fdisp_init(&fdi, 0);
- err = fdisp_simple_putget_vp(&fdi, FUSE_READLINK, vp, curthread, cred);
- if (err) {
- goto out;
- }
- if (((char *)fdi.answ)[0] == '/' &&
- fuse_get_mpdata(vnode_mount(vp))->dataflags & FSESS_PUSH_SYMLINKS_IN) {
- char *mpth = vnode_mount(vp)->mnt_stat.f_mntonname;
-
- err = uiomove(mpth, strlen(mpth), uio);
- }
- if (!err) {
- err = uiomove(fdi.answ, fdi.iosize, uio);
- }
-out:
- fdisp_destroy(&fdi);
- return err;
-}
-
-/*
- struct vnop_reclaim_args {
- struct vnode *a_vp;
- struct thread *a_td;
- };
-*/
-static int
-fuse_vnop_reclaim(struct vop_reclaim_args *ap)
-{
- struct vnode *vp = ap->a_vp;
- struct thread *td = ap->a_td;
-
- struct fuse_vnode_data *fvdat = VTOFUD(vp);
- struct fuse_filehandle *fufh = NULL;
-
- int type;
-
- if (!fvdat) {
- panic("FUSE: no vnode data during recycling");
- }
- FS_DEBUG("inode=%ju\n", (uintmax_t)VTOI(vp));
-
- for (type = 0; type < FUFH_MAXTYPE; type++) {
- fufh = &(fvdat->fufh[type]);
- if (FUFH_IS_VALID(fufh)) {
- printf("FUSE: vnode being reclaimed but fufh (type=%d) is valid",
- type);
- fuse_filehandle_close(vp, type, td, NULL);
- }
- }
-
- if ((!fuse_isdeadfs(vp)) && (fvdat->nlookup)) {
- fuse_internal_forget_send(vnode_mount(vp), td, NULL, VTOI(vp),
- fvdat->nlookup);
- }
- fuse_vnode_setparent(vp, NULL);
- cache_purge(vp);
- vfs_hash_remove(vp);
- vnode_destroy_vobject(vp);
- fuse_vnode_destroy(vp);
-
- return 0;
-}
-
-/*
- struct vnop_remove_args {
- struct vnode *a_dvp;
- struct vnode *a_vp;
- struct componentname *a_cnp;
- };
-*/
-static int
-fuse_vnop_remove(struct vop_remove_args *ap)
-{
- struct vnode *dvp = ap->a_dvp;
- struct vnode *vp = ap->a_vp;
- struct componentname *cnp = ap->a_cnp;
-
- int err;
-
- FS_DEBUG2G("inode=%ju name=%*s\n",
- (uintmax_t)VTOI(vp), (int)cnp->cn_namelen, cnp->cn_nameptr);
-
- if (fuse_isdeadfs(vp)) {
- return ENXIO;
- }
- if (vnode_isdir(vp)) {
- return EPERM;
- }
- cache_purge(vp);
-
- err = fuse_internal_remove(dvp, vp, cnp, FUSE_UNLINK);
-
- if (err == 0)
- fuse_internal_vnode_disappear(vp);
- return err;
-}
-
-/*
- struct vnop_rename_args {
- struct vnode *a_fdvp;
- struct vnode *a_fvp;
- struct componentname *a_fcnp;
- struct vnode *a_tdvp;
- struct vnode *a_tvp;
- struct componentname *a_tcnp;
- };
-*/
-static int
-fuse_vnop_rename(struct vop_rename_args *ap)
-{
- struct vnode *fdvp = ap->a_fdvp;
- struct vnode *fvp = ap->a_fvp;
- struct componentname *fcnp = ap->a_fcnp;
- struct vnode *tdvp = ap->a_tdvp;
- struct vnode *tvp = ap->a_tvp;
- struct componentname *tcnp = ap->a_tcnp;
- struct fuse_data *data;
-
- int err = 0;
-
- FS_DEBUG2G("from: inode=%ju name=%*s -> to: inode=%ju name=%*s\n",
- (uintmax_t)VTOI(fvp), (int)fcnp->cn_namelen, fcnp->cn_nameptr,
- (uintmax_t)(tvp == NULL ? -1 : VTOI(tvp)),
- (int)tcnp->cn_namelen, tcnp->cn_nameptr);
-
- if (fuse_isdeadfs(fdvp)) {
- return ENXIO;
- }
- if (fvp->v_mount != tdvp->v_mount ||
- (tvp && fvp->v_mount != tvp->v_mount)) {
- FS_DEBUG("cross-device rename: %s -> %s\n",
- fcnp->cn_nameptr, (tcnp != NULL ? tcnp->cn_nameptr : "(NULL)"));
- err = EXDEV;
- goto out;
- }
- cache_purge(fvp);
-
- /*
- * FUSE library is expected to check if target directory is not
- * under the source directory in the file system tree.
- * Linux performs this check at VFS level.
- */
- data = fuse_get_mpdata(vnode_mount(tdvp));
- sx_xlock(&data->rename_lock);
- err = fuse_internal_rename(fdvp, fcnp, tdvp, tcnp);
- if (err == 0) {
- if (tdvp != fdvp)
- fuse_vnode_setparent(fvp, tdvp);
- if (tvp != NULL)
- fuse_vnode_setparent(tvp, NULL);
- }
- sx_unlock(&data->rename_lock);
-
- if (tvp != NULL && tvp != fvp) {
- cache_purge(tvp);
- }
- if (vnode_isdir(fvp)) {
- if ((tvp != NULL) && vnode_isdir(tvp)) {
- cache_purge(tdvp);
- }
- cache_purge(fdvp);
- }
-out:
- if (tdvp == tvp) {
- vrele(tdvp);
- } else {
- vput(tdvp);
- }
- if (tvp != NULL) {
- vput(tvp);
- }
- vrele(fdvp);
- vrele(fvp);
-
- return err;
-}
-
-/*
- struct vnop_rmdir_args {
- struct vnode *a_dvp;
- struct vnode *a_vp;
- struct componentname *a_cnp;
- } *ap;
-*/
-static int
-fuse_vnop_rmdir(struct vop_rmdir_args *ap)
-{
- struct vnode *dvp = ap->a_dvp;
- struct vnode *vp = ap->a_vp;
-
- int err;
-
- FS_DEBUG2G("inode=%ju\n", (uintmax_t)VTOI(vp));
-
- if (fuse_isdeadfs(vp)) {
- return ENXIO;
- }
- if (VTOFUD(vp) == VTOFUD(dvp)) {
- return EINVAL;
- }
- err = fuse_internal_remove(dvp, vp, ap->a_cnp, FUSE_RMDIR);
-
- if (err == 0)
- fuse_internal_vnode_disappear(vp);
- return err;
-}
-
-/*
- struct vnop_setattr_args {
- struct vnode *a_vp;
- struct vattr *a_vap;
- struct ucred *a_cred;
- struct thread *a_td;
- };
-*/
-static int
-fuse_vnop_setattr(struct vop_setattr_args *ap)
-{
- struct vnode *vp = ap->a_vp;
- struct vattr *vap = ap->a_vap;
- struct ucred *cred = ap->a_cred;
- struct thread *td = curthread;
-
- struct fuse_dispatcher fdi;
- struct fuse_setattr_in *fsai;
- struct fuse_access_param facp;
-
- int err = 0;
- enum vtype vtyp;
- int sizechanged = 0;
- uint64_t newsize = 0;
-
- FS_DEBUG2G("inode=%ju\n", (uintmax_t)VTOI(vp));
-
- if (fuse_isdeadfs(vp)) {
- return ENXIO;
- }
- fdisp_init(&fdi, sizeof(*fsai));
- fdisp_make_vp(&fdi, FUSE_SETATTR, vp, td, cred);
- fsai = fdi.indata;
- fsai->valid = 0;
-
- bzero(&facp, sizeof(facp));
-
- facp.xuid = vap->va_uid;
- facp.xgid = vap->va_gid;
-
- if (vap->va_uid != (uid_t)VNOVAL) {
- facp.facc_flags |= FACCESS_CHOWN;
- fsai->uid = vap->va_uid;
- fsai->valid |= FATTR_UID;
- }
- if (vap->va_gid != (gid_t)VNOVAL) {
- facp.facc_flags |= FACCESS_CHOWN;
- fsai->gid = vap->va_gid;
- fsai->valid |= FATTR_GID;
- }
- if (vap->va_size != VNOVAL) {
-
- struct fuse_filehandle *fufh = NULL;
-
- /*Truncate to a new value. */
- fsai->size = vap->va_size;
- sizechanged = 1;
- newsize = vap->va_size;
- fsai->valid |= FATTR_SIZE;
-
- fuse_filehandle_getrw(vp, FUFH_WRONLY, &fufh);
- if (fufh) {
- fsai->fh = fufh->fh_id;
- fsai->valid |= FATTR_FH;
- }
- }
- if (vap->va_atime.tv_sec != VNOVAL) {
- fsai->atime = vap->va_atime.tv_sec;
- fsai->atimensec = vap->va_atime.tv_nsec;
- fsai->valid |= FATTR_ATIME;
- }
- if (vap->va_mtime.tv_sec != VNOVAL) {
- fsai->mtime = vap->va_mtime.tv_sec;
- fsai->mtimensec = vap->va_mtime.tv_nsec;
- fsai->valid |= FATTR_MTIME;
- }
- if (vap->va_mode != (mode_t)VNOVAL) {
- fsai->mode = vap->va_mode & ALLPERMS;
- fsai->valid |= FATTR_MODE;
- }
- if (!fsai->valid) {
- goto out;
- }
- vtyp = vnode_vtype(vp);
-
- if (fsai->valid & FATTR_SIZE && vtyp == VDIR) {
- err = EISDIR;
- goto out;
- }
- if (vfs_isrdonly(vnode_mount(vp)) && (fsai->valid & ~FATTR_SIZE || vtyp == VREG)) {
- err = EROFS;
- goto out;
- }
- if (fsai->valid & ~FATTR_SIZE) {
- /*err = fuse_internal_access(vp, VADMIN, context, &facp); */
- /*XXX */
- err = 0;
- }
- facp.facc_flags &= ~FACCESS_XQUERIES;
-
- if (err && !(fsai->valid & ~(FATTR_ATIME | FATTR_MTIME)) &&
- vap->va_vaflags & VA_UTIMES_NULL) {
- err = fuse_internal_access(vp, VWRITE, &facp, td, cred);
- }
- if (err)
- goto out;
- if ((err = fdisp_wait_answ(&fdi)))
- goto out;
- vtyp = IFTOVT(((struct fuse_attr_out *)fdi.answ)->attr.mode);
-
- if (vnode_vtype(vp) != vtyp) {
- if (vnode_vtype(vp) == VNON && vtyp != VNON) {
- debug_printf("FUSE: Dang! vnode_vtype is VNON and vtype isn't.\n");
- } else {
- /*
- * STALE vnode, ditch
- *
- * The vnode has changed its type "behind our back". There's
- * nothing really we can do, so let us just force an internal
- * revocation and tell the caller to try again, if interested.
- */
- fuse_internal_vnode_disappear(vp);
- err = EAGAIN;
- }
- }
- if (err == 0)
- cache_attrs(vp, (struct fuse_attr_out *)fdi.answ, NULL);
-
-out:
- fdisp_destroy(&fdi);
- if (!err && sizechanged) {
- fuse_vnode_setsize(vp, cred, newsize);
- VTOFUD(vp)->flag &= ~FN_SIZECHANGE;
- }
- return err;
-}
-
-/*
- struct vnop_strategy_args {
- struct vnode *a_vp;
- struct buf *a_bp;
- };
-*/
-static int
-fuse_vnop_strategy(struct vop_strategy_args *ap)
-{
- struct vnode *vp = ap->a_vp;
- struct buf *bp = ap->a_bp;
-
- fuse_trace_printf_vnop();
-
- if (!vp || fuse_isdeadfs(vp)) {
- bp->b_ioflags |= BIO_ERROR;
- bp->b_error = ENXIO;
- bufdone(bp);
- return ENXIO;
- }
- if (bp->b_iocmd == BIO_WRITE)
- fuse_vnode_refreshsize(vp, NOCRED);
-
- (void)fuse_io_strategy(vp, bp);
-
- /*
- * This is a dangerous function. If returns error, that might mean a
- * panic. We prefer pretty much anything over being forced to panic
- * by a malicious daemon (a demon?). So we just return 0 anyway. You
- * should never mind this: this function has its own error
- * propagation mechanism via the argument buffer, so
- * not-that-melodramatic residents of the call chain still will be
- * able to know what to do.
- */
- return 0;
-}
-
-
-/*
- struct vnop_symlink_args {
- struct vnode *a_dvp;
- struct vnode **a_vpp;
- struct componentname *a_cnp;
- struct vattr *a_vap;
- char *a_target;
- };
-*/
-static int
-fuse_vnop_symlink(struct vop_symlink_args *ap)
-{
- struct vnode *dvp = ap->a_dvp;
- struct vnode **vpp = ap->a_vpp;
- struct componentname *cnp = ap->a_cnp;
- const char *target = ap->a_target;
-
- struct fuse_dispatcher fdi;
-
- int err;
- size_t len;
-
- FS_DEBUG2G("inode=%ju name=%*s\n",
- (uintmax_t)VTOI(dvp), (int)cnp->cn_namelen, cnp->cn_nameptr);
-
- if (fuse_isdeadfs(dvp)) {
- return ENXIO;
- }
- /*
- * Unlike the other creator type calls, here we have to create a message
- * where the name of the new entry comes first, and the data describing
- * the entry comes second.
- * Hence we can't rely on our handy fuse_internal_newentry() routine,
- * but put together the message manually and just call the core part.
- */
-
- len = strlen(target) + 1;
- fdisp_init(&fdi, len + cnp->cn_namelen + 1);
- fdisp_make_vp(&fdi, FUSE_SYMLINK, dvp, curthread, NULL);
-
- memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
- ((char *)fdi.indata)[cnp->cn_namelen] = '\0';
- memcpy((char *)fdi.indata + cnp->cn_namelen + 1, target, len);
-
- err = fuse_internal_newentry_core(dvp, vpp, cnp, VLNK, &fdi);
- fdisp_destroy(&fdi);
- return err;
-}
-
-/*
- struct vnop_write_args {
- struct vnode *a_vp;
- struct uio *a_uio;
- int a_ioflag;
- struct ucred *a_cred;
- };
-*/
-static int
-fuse_vnop_write(struct vop_write_args *ap)
-{
- struct vnode *vp = ap->a_vp;
- struct uio *uio = ap->a_uio;
- int ioflag = ap->a_ioflag;
- struct ucred *cred = ap->a_cred;
-
- fuse_trace_printf_vnop();
-
- if (fuse_isdeadfs(vp)) {
- return ENXIO;
- }
- fuse_vnode_refreshsize(vp, cred);
-
- if (VTOFUD(vp)->flag & FN_DIRECTIO) {
- ioflag |= IO_DIRECT;
- }
-
- return fuse_io_dispatch(vp, uio, ioflag, cred);
-}
-
-/*
- struct vnop_getpages_args {
- struct vnode *a_vp;
- vm_page_t *a_m;
- int a_count;
- int a_reqpage;
- };
-*/
-static int
-fuse_vnop_getpages(struct vop_getpages_args *ap)
-{
- int i, error, nextoff, size, toff, count, npages;
- struct uio uio;
- struct iovec iov;
- vm_offset_t kva;
- struct buf *bp;
- struct vnode *vp;
- struct thread *td;
- struct ucred *cred;
- vm_page_t *pages;
-
- FS_DEBUG2G("heh\n");
-
- vp = ap->a_vp;
- KASSERT(vp->v_object, ("objectless vp passed to getpages"));
- td = curthread; /* XXX */
- cred = curthread->td_ucred; /* XXX */
- pages = ap->a_m;
- npages = ap->a_count;
-
- if (!fsess_opt_mmap(vnode_mount(vp))) {
- FS_DEBUG("called on non-cacheable vnode??\n");
- return (VM_PAGER_ERROR);
- }
-
- /*
- * If the last page is partially valid, just return it and allow
- * the pager to zero-out the blanks. Partially valid pages can
- * only occur at the file EOF.
- *
- * XXXGL: is that true for FUSE, which is a local filesystem,
- * but still somewhat disconnected from the kernel?
- */
- VM_OBJECT_WLOCK(vp->v_object);
- if (pages[npages - 1]->valid != 0 && --npages == 0)
- goto out;
- VM_OBJECT_WUNLOCK(vp->v_object);
-
- /*
- * We use only the kva address for the buffer, but this is extremely
- * convenient and fast.
- */
- bp = uma_zalloc(fuse_pbuf_zone, M_WAITOK);
-
- kva = (vm_offset_t)bp->b_data;
- pmap_qenter(kva, pages, npages);
- VM_CNT_INC(v_vnodein);
- VM_CNT_ADD(v_vnodepgsin, npages);
-
- count = npages << PAGE_SHIFT;
- iov.iov_base = (caddr_t)kva;
- iov.iov_len = count;
- uio.uio_iov = &iov;
- uio.uio_iovcnt = 1;
- uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
- uio.uio_resid = count;
- uio.uio_segflg = UIO_SYSSPACE;
- uio.uio_rw = UIO_READ;
- uio.uio_td = td;
-
- error = fuse_io_dispatch(vp, &uio, IO_DIRECT, cred);
- pmap_qremove(kva, npages);
-
- uma_zfree(fuse_pbuf_zone, bp);
-
- if (error && (uio.uio_resid == count)) {
- FS_DEBUG("error %d\n", error);
- return VM_PAGER_ERROR;
- }
- /*
- * Calculate the number of bytes read and validate only that number
- * of bytes. Note that due to pending writes, size may be 0. This
- * does not mean that the remaining data is invalid!
- */
-
- size = count - uio.uio_resid;
- VM_OBJECT_WLOCK(vp->v_object);
- fuse_vm_page_lock_queues();
- for (i = 0, toff = 0; i < npages; i++, toff = nextoff) {
- vm_page_t m;
-
- nextoff = toff + PAGE_SIZE;
- m = pages[i];
-
- if (nextoff <= size) {
- /*
- * Read operation filled an entire page
- */
- m->valid = VM_PAGE_BITS_ALL;
- KASSERT(m->dirty == 0,
- ("fuse_getpages: page %p is dirty", m));
- } else if (size > toff) {
- /*
- * Read operation filled a partial page.
- */
- m->valid = 0;
- vm_page_set_valid_range(m, 0, size - toff);
- KASSERT(m->dirty == 0,
- ("fuse_getpages: page %p is dirty", m));
- } else {
- /*
- * Read operation was short. If no error occurred
- * we may have hit a zero-fill section. We simply
- * leave valid set to 0.
- */
- ;
- }
- }
- fuse_vm_page_unlock_queues();
-out:
- VM_OBJECT_WUNLOCK(vp->v_object);
- if (ap->a_rbehind)
- *ap->a_rbehind = 0;
- if (ap->a_rahead)
- *ap->a_rahead = 0;
- return (VM_PAGER_OK);
-}
-
-/*
- struct vnop_putpages_args {
- struct vnode *a_vp;
- vm_page_t *a_m;
- int a_count;
- int a_sync;
- int *a_rtvals;
- vm_ooffset_t a_offset;
- };
-*/
-static int
-fuse_vnop_putpages(struct vop_putpages_args *ap)
-{
- struct uio uio;
- struct iovec iov;
- vm_offset_t kva;
- struct buf *bp;
- int i, error, npages, count;
- off_t offset;
- int *rtvals;
- struct vnode *vp;
- struct thread *td;
- struct ucred *cred;
- vm_page_t *pages;
- vm_ooffset_t fsize;
-
- FS_DEBUG2G("heh\n");
-
- vp = ap->a_vp;
- KASSERT(vp->v_object, ("objectless vp passed to putpages"));
- fsize = vp->v_object->un_pager.vnp.vnp_size;
- td = curthread; /* XXX */
- cred = curthread->td_ucred; /* XXX */
- pages = ap->a_m;
- count = ap->a_count;
- rtvals = ap->a_rtvals;
- npages = btoc(count);
- offset = IDX_TO_OFF(pages[0]->pindex);
-
- if (!fsess_opt_mmap(vnode_mount(vp))) {
- FS_DEBUG("called on non-cacheable vnode??\n");
- }
- for (i = 0; i < npages; i++)
- rtvals[i] = VM_PAGER_AGAIN;
-
- /*
- * When putting pages, do not extend file past EOF.
- */
-
- if (offset + count > fsize) {
- count = fsize - offset;
- if (count < 0)
- count = 0;
- }
- /*
- * We use only the kva address for the buffer, but this is extremely
- * convenient and fast.
- */
- bp = uma_zalloc(fuse_pbuf_zone, M_WAITOK);
-
- kva = (vm_offset_t)bp->b_data;
- pmap_qenter(kva, pages, npages);
- VM_CNT_INC(v_vnodeout);
- VM_CNT_ADD(v_vnodepgsout, count);
-
- iov.iov_base = (caddr_t)kva;
- iov.iov_len = count;
- uio.uio_iov = &iov;
- uio.uio_iovcnt = 1;
- uio.uio_offset = offset;
- uio.uio_resid = count;
- uio.uio_segflg = UIO_SYSSPACE;
- uio.uio_rw = UIO_WRITE;
- uio.uio_td = td;
-
- error = fuse_io_dispatch(vp, &uio, IO_DIRECT, cred);
-
- pmap_qremove(kva, npages);
- uma_zfree(fuse_pbuf_zone, bp);
-
- if (!error) {
- int nwritten = round_page(count - uio.uio_resid) / PAGE_SIZE;
-
- for (i = 0; i < nwritten; i++) {
- rtvals[i] = VM_PAGER_OK;
- VM_OBJECT_WLOCK(pages[i]->object);
- vm_page_undirty(pages[i]);
- VM_OBJECT_WUNLOCK(pages[i]->object);
- }
- }
- return rtvals[0];
-}
-
-static const char extattr_namespace_separator = '.';
-
-/*
- struct vop_getextattr_args {
- struct vop_generic_args a_gen;
- struct vnode *a_vp;
- int a_attrnamespace;
- const char *a_name;
- struct uio *a_uio;
- size_t *a_size;
- struct ucred *a_cred;
- struct thread *a_td;
- };
-*/
-static int
-fuse_vnop_getextattr(struct vop_getextattr_args *ap)
-{
- struct vnode *vp = ap->a_vp;
- struct uio *uio = ap->a_uio;
- struct fuse_dispatcher fdi;
- struct fuse_getxattr_in *get_xattr_in;
- struct fuse_getxattr_out *get_xattr_out;
- struct mount *mp = vnode_mount(vp);
- struct thread *td = ap->a_td;
- struct ucred *cred = ap->a_cred;
- char *prefix;
- char *attr_str;
- size_t len;
- int err;
-
- fuse_trace_printf_vnop();
-
- if (fuse_isdeadfs(vp))
- return (ENXIO);
-
- /* Default to looking for user attributes. */
- if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
- prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
- else
- prefix = EXTATTR_NAMESPACE_USER_STRING;
-
- len = strlen(prefix) + sizeof(extattr_namespace_separator) +
- strlen(ap->a_name) + 1;
-
- fdisp_init(&fdi, len + sizeof(*get_xattr_in));
- fdisp_make_vp(&fdi, FUSE_GETXATTR, vp, td, cred);
-
- get_xattr_in = fdi.indata;
- /*
- * Check to see whether we're querying the available size or
- * issuing the actual request. If we pass in 0, we get back struct
- * fuse_getxattr_out. If we pass in a non-zero size, we get back
- * that much data, without the struct fuse_getxattr_out header.
- */
- if (uio == NULL)
- get_xattr_in->size = 0;
- else
- get_xattr_in->size = uio->uio_resid;
-
- attr_str = (char *)fdi.indata + sizeof(*get_xattr_in);
- snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator,
- ap->a_name);
-
- err = fdisp_wait_answ(&fdi);
- if (err != 0) {
- if (err == ENOSYS)
- fsess_set_notimpl(mp, FUSE_GETXATTR);
- debug_printf("getxattr: got err=%d from daemon\n", err);
- goto out;
- }
-
- get_xattr_out = fdi.answ;
-
- if (ap->a_size != NULL)
- *ap->a_size = get_xattr_out->size;
-
- if (uio != NULL)
- err = uiomove(fdi.answ, fdi.iosize, uio);
-
-out:
- fdisp_destroy(&fdi);
- return (err);
-}
-
-/*
- struct vop_setextattr_args {
- struct vop_generic_args a_gen;
- struct vnode *a_vp;
- int a_attrnamespace;
- const char *a_name;
- struct uio *a_uio;
- struct ucred *a_cred;
- struct thread *a_td;
- };
-*/
-static int
-fuse_vnop_setextattr(struct vop_setextattr_args *ap)
-{
- struct vnode *vp = ap->a_vp;
- struct uio *uio = ap->a_uio;
- struct fuse_dispatcher fdi;
- struct fuse_setxattr_in *set_xattr_in;
- struct mount *mp = vnode_mount(vp);
- struct thread *td = ap->a_td;
- struct ucred *cred = ap->a_cred;
- char *prefix;
- size_t len;
- char *attr_str;
- int err;
-
- fuse_trace_printf_vnop();
-
- if (fuse_isdeadfs(vp))
- return (ENXIO);
-
- /* Default to looking for user attributes. */
- if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
- prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
- else
- prefix = EXTATTR_NAMESPACE_USER_STRING;
-
- len = strlen(prefix) + sizeof(extattr_namespace_separator) +
- strlen(ap->a_name) + 1;
-
- fdisp_init(&fdi, len + sizeof(*set_xattr_in) + uio->uio_resid);
- fdisp_make_vp(&fdi, FUSE_SETXATTR, vp, td, cred);
-
- set_xattr_in = fdi.indata;
- set_xattr_in->size = uio->uio_resid;
-
- attr_str = (char *)fdi.indata + sizeof(*set_xattr_in);
- snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator,
- ap->a_name);
-
- err = uiomove((char *)fdi.indata + sizeof(*set_xattr_in) + len,
- uio->uio_resid, uio);
- if (err != 0) {
- debug_printf("setxattr: got error %d from uiomove\n", err);
- goto out;
- }
-
- err = fdisp_wait_answ(&fdi);
-
- if (err != 0) {
- if (err == ENOSYS)
- fsess_set_notimpl(mp, FUSE_SETXATTR);
- debug_printf("setxattr: got err=%d from daemon\n", err);
- goto out;
- }
-
-out:
- fdisp_destroy(&fdi);
- return (err);
-}
-
-/*
- * The Linux / FUSE extended attribute list is simply a collection of
- * NUL-terminated strings. The FreeBSD extended attribute list is a single
- * byte length followed by a non-NUL terminated string. So, this allows
- * conversion of the Linux / FUSE format to the FreeBSD format in place.
- * Linux attribute names are reported with the namespace as a prefix (e.g.
- * "user.attribute_name"), but in FreeBSD they are reported without the
- * namespace prefix (e.g. "attribute_name"). So, we're going from:
- *
- * user.attr_name1\0user.attr_name2\0
- *
- * to:
- *
- * <num>attr_name1<num>attr_name2
- *
- * Where "<num>" is a single byte number of characters in the attribute name.
- *
- * Args:
- * prefix - exattr namespace prefix string
- * list, list_len - input list with namespace prefixes
- * bsd_list, bsd_list_len - output list compatible with bsd vfs
- */
-static int
-fuse_xattrlist_convert(char *prefix, const char *list, int list_len,
- char *bsd_list, int *bsd_list_len)
-{
- int len, pos, dist_to_next, prefix_len;
-
- pos = 0;
- *bsd_list_len = 0;
- prefix_len = strlen(prefix);
-
- while (pos < list_len && list[pos] != '\0') {
- dist_to_next = strlen(&list[pos]) + 1;
- if (bcmp(&list[pos], prefix, prefix_len) == 0 &&
- list[pos + prefix_len] == extattr_namespace_separator) {
- len = dist_to_next -
- (prefix_len + sizeof(extattr_namespace_separator)) - 1;
- if (len >= EXTATTR_MAXNAMELEN)
- return (ENAMETOOLONG);
-
- bsd_list[*bsd_list_len] = len;
- memcpy(&bsd_list[*bsd_list_len + 1],
- &list[pos + prefix_len +
- sizeof(extattr_namespace_separator)], len);
-
- *bsd_list_len += len + 1;
- }
-
- pos += dist_to_next;
- }
-
- return (0);
-}
-
-/*
- struct vop_listextattr_args {
- struct vop_generic_args a_gen;
- struct vnode *a_vp;
- int a_attrnamespace;
- struct uio *a_uio;
- size_t *a_size;
- struct ucred *a_cred;
- struct thread *a_td;
- };
-*/
-static int
-fuse_vnop_listextattr(struct vop_listextattr_args *ap)
-{
- struct vnode *vp = ap->a_vp;
- struct uio *uio = ap->a_uio;
- struct fuse_dispatcher fdi;
- struct fuse_listxattr_in *list_xattr_in;
- struct fuse_listxattr_out *list_xattr_out;
- struct mount *mp = vnode_mount(vp);
- struct thread *td = ap->a_td;
- struct ucred *cred = ap->a_cred;
- size_t len;
- char *prefix;
- char *attr_str;
- char *bsd_list = NULL;
- char *linux_list;
- int bsd_list_len;
- int linux_list_len;
- int err;
-
- fuse_trace_printf_vnop();
-
- if (fuse_isdeadfs(vp))
- return (ENXIO);
-
- /*
- * Add space for a NUL and the period separator if enabled.
- * Default to looking for user attributes.
- */
- if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
- prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
- else
- prefix = EXTATTR_NAMESPACE_USER_STRING;
-
- len = strlen(prefix) + sizeof(extattr_namespace_separator) + 1;
-
- fdisp_init(&fdi, sizeof(*list_xattr_in) + len);
- fdisp_make_vp(&fdi, FUSE_LISTXATTR, vp, td, cred);
-
- /*
- * Retrieve Linux / FUSE compatible list size.
- */
- list_xattr_in = fdi.indata;
- list_xattr_in->size = 0;
- attr_str = (char *)fdi.indata + sizeof(*list_xattr_in);
- snprintf(attr_str, len, "%s%c", prefix, extattr_namespace_separator);
-
- err = fdisp_wait_answ(&fdi);
- if (err != 0) {
- if (err == ENOSYS)
- fsess_set_notimpl(mp, FUSE_LISTXATTR);
- debug_printf("listextattr: got err=%d from daemon\n", err);
- goto out;
- }
-
- list_xattr_out = fdi.answ;
- linux_list_len = list_xattr_out->size;
- if (linux_list_len == 0) {
- if (ap->a_size != NULL)
- *ap->a_size = linux_list_len;
- goto out;
- }
-
- /*
- * Retrieve Linux / FUSE compatible list values.
- */
- fdisp_make_vp(&fdi, FUSE_LISTXATTR, vp, td, cred);
- list_xattr_in = fdi.indata;
- list_xattr_in->size = linux_list_len + sizeof(*list_xattr_out);
- attr_str = (char *)fdi.indata + sizeof(*list_xattr_in);
- snprintf(attr_str, len, "%s%c", prefix, extattr_namespace_separator);
-
- err = fdisp_wait_answ(&fdi);
- if (err != 0)
- goto out;
-
- linux_list = fdi.answ;
- linux_list_len = fdi.iosize;
-
- /*
- * Retrieve the BSD compatible list values.
- * The Linux / FUSE attribute list format isn't the same
- * as FreeBSD's format. So we need to transform it into
- * FreeBSD's format before giving it to the user.
- */
- bsd_list = malloc(linux_list_len, M_TEMP, M_WAITOK);
- err = fuse_xattrlist_convert(prefix, linux_list, linux_list_len,
- bsd_list, &bsd_list_len);
- if (err != 0)
- goto out;
-
- if (ap->a_size != NULL)
- *ap->a_size = bsd_list_len;
-
- if (uio != NULL)
- err = uiomove(bsd_list, bsd_list_len, uio);
-
-out:
- free(bsd_list, M_TEMP);
- fdisp_destroy(&fdi);
- return (err);
-}
-
-/*
- struct vop_deleteextattr_args {
- struct vop_generic_args a_gen;
- struct vnode *a_vp;
- int a_attrnamespace;
- const char *a_name;
- struct ucred *a_cred;
- struct thread *a_td;
- };
-*/
-static int
-fuse_vnop_deleteextattr(struct vop_deleteextattr_args *ap)
-{
- struct vnode *vp = ap->a_vp;
- struct fuse_dispatcher fdi;
- struct mount *mp = vnode_mount(vp);
- struct thread *td = ap->a_td;
- struct ucred *cred = ap->a_cred;
- char *prefix;
- size_t len;
- char *attr_str;
- int err;
-
- fuse_trace_printf_vnop();
-
- if (fuse_isdeadfs(vp))
- return (ENXIO);
-
- /* Default to looking for user attributes. */
- if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
- prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
- else
- prefix = EXTATTR_NAMESPACE_USER_STRING;
-
- len = strlen(prefix) + sizeof(extattr_namespace_separator) +
- strlen(ap->a_name) + 1;
-
- fdisp_init(&fdi, len);
- fdisp_make_vp(&fdi, FUSE_REMOVEXATTR, vp, td, cred);
-
- attr_str = fdi.indata;
- snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator,
- ap->a_name);
-
- err = fdisp_wait_answ(&fdi);
- if (err != 0) {
- if (err == ENOSYS)
- fsess_set_notimpl(mp, FUSE_REMOVEXATTR);
- debug_printf("removexattr: got err=%d from daemon\n", err);
- }
-
- fdisp_destroy(&fdi);
- return (err);
-}
-
-/*
- struct vnop_print_args {
- struct vnode *a_vp;
- };
-*/
-static int
-fuse_vnop_print(struct vop_print_args *ap)
-{
- struct fuse_vnode_data *fvdat = VTOFUD(ap->a_vp);
-
- printf("nodeid: %ju, parent nodeid: %ju, nlookup: %ju, flag: %#x\n",
- (uintmax_t)VTOILLU(ap->a_vp), (uintmax_t)fvdat->parent_nid,
- (uintmax_t)fvdat->nlookup,
- fvdat->flag);
-
- return 0;
-}
Index: sys/fs/fusefs/fuse.h
===================================================================
--- sys/fs/fusefs/fuse.h
+++ sys/fs/fusefs/fuse.h
@@ -143,7 +143,7 @@
/* misc */
-SYSCTL_DECL(_vfs_fuse);
+SYSCTL_DECL(_vfs_fusefs);
/* Fuse locking */
Index: sys/fs/fusefs/fuse_file.c
===================================================================
--- sys/fs/fusefs/fuse_file.c
+++ sys/fs/fusefs/fuse_file.c
@@ -87,7 +87,7 @@
static int fuse_fh_count = 0;
-SYSCTL_INT(_vfs_fuse, OID_AUTO, filehandle_count, CTLFLAG_RD,
+SYSCTL_INT(_vfs_fusefs, OID_AUTO, filehandle_count, CTLFLAG_RD,
&fuse_fh_count, 0, "number of open FUSE filehandles");
int
Index: sys/fs/fusefs/fuse_ipc.c
===================================================================
--- sys/fs/fusefs/fuse_ipc.c
+++ sys/fs/fusefs/fuse_ipc.c
@@ -99,21 +99,21 @@
static fuse_handler_t fuse_standard_handler;
-SYSCTL_NODE(_vfs, OID_AUTO, fuse, CTLFLAG_RW, 0, "FUSE tunables");
-SYSCTL_STRING(_vfs_fuse, OID_AUTO, version, CTLFLAG_RD,
+SYSCTL_NODE(_vfs, OID_AUTO, fusefs, CTLFLAG_RW, 0, "FUSE tunables");
+SYSCTL_STRING(_vfs_fusefs, OID_AUTO, version, CTLFLAG_RD,
FUSE_FREEBSD_VERSION, 0, "fuse-freebsd version");
static int fuse_ticket_count = 0;
-SYSCTL_INT(_vfs_fuse, OID_AUTO, ticket_count, CTLFLAG_RW,
+SYSCTL_INT(_vfs_fusefs, OID_AUTO, ticket_count, CTLFLAG_RW,
&fuse_ticket_count, 0, "number of allocated tickets");
static long fuse_iov_permanent_bufsize = 1 << 19;
-SYSCTL_LONG(_vfs_fuse, OID_AUTO, iov_permanent_bufsize, CTLFLAG_RW,
+SYSCTL_LONG(_vfs_fusefs, OID_AUTO, iov_permanent_bufsize, CTLFLAG_RW,
&fuse_iov_permanent_bufsize, 0,
"limit for permanently stored buffer size for fuse_iovs");
static int fuse_iov_credit = 16;
-SYSCTL_INT(_vfs_fuse, OID_AUTO, iov_credit, CTLFLAG_RW,
+SYSCTL_INT(_vfs_fusefs, OID_AUTO, iov_credit, CTLFLAG_RW,
&fuse_iov_credit, 0,
"how many times is an oversized fuse_iov tolerated");
Index: sys/fs/fusefs/fuse_main.c
===================================================================
--- sys/fs/fusefs/fuse_main.c
+++ sys/fs/fusefs/fuse_main.c
@@ -94,9 +94,9 @@
.vfc_flags = VFCF_JAIL | VFCF_SYNTHETIC
};
-SYSCTL_INT(_vfs_fuse, OID_AUTO, kernelabi_major, CTLFLAG_RD,
+SYSCTL_INT(_vfs_fusefs, OID_AUTO, kernelabi_major, CTLFLAG_RD,
SYSCTL_NULL_INT_PTR, FUSE_KERNEL_VERSION, "FUSE kernel abi major version");
-SYSCTL_INT(_vfs_fuse, OID_AUTO, kernelabi_minor, CTLFLAG_RD,
+SYSCTL_INT(_vfs_fusefs, OID_AUTO, kernelabi_minor, CTLFLAG_RD,
SYSCTL_NULL_INT_PTR, FUSE_KERNEL_MINOR_VERSION, "FUSE kernel abi minor version");
/******************************
@@ -156,10 +156,10 @@
/* Registering the module */
static moduledata_t fuse_moddata = {
- "fuse",
+ "fusefs",
fuse_loader,
&fuse_vfsconf
};
-DECLARE_MODULE(fuse, fuse_moddata, SI_SUB_VFS, SI_ORDER_MIDDLE);
-MODULE_VERSION(fuse, 1);
+DECLARE_MODULE(fusefs, fuse_moddata, SI_SUB_VFS, SI_ORDER_MIDDLE);
+MODULE_VERSION(fusefs, 1);
Index: sys/fs/fusefs/fuse_node.c
===================================================================
--- sys/fs/fusefs/fuse_node.c
+++ sys/fs/fusefs/fuse_node.c
@@ -98,47 +98,47 @@
static int fuse_node_count = 0;
-SYSCTL_INT(_vfs_fuse, OID_AUTO, node_count, CTLFLAG_RD,
+SYSCTL_INT(_vfs_fusefs, OID_AUTO, node_count, CTLFLAG_RD,
&fuse_node_count, 0, "Count of FUSE vnodes");
int fuse_data_cache_mode = FUSE_CACHE_WT;
-SYSCTL_PROC(_vfs_fuse, OID_AUTO, data_cache_mode, CTLTYPE_INT|CTLFLAG_RW,
+SYSCTL_PROC(_vfs_fusefs, OID_AUTO, data_cache_mode, CTLTYPE_INT|CTLFLAG_RW,
&fuse_data_cache_mode, 0, sysctl_fuse_cache_mode, "I",
"Zero: disable caching of FUSE file data; One: write-through caching "
"(default); Two: write-back caching (generally unsafe)");
int fuse_data_cache_invalidate = 0;
-SYSCTL_INT(_vfs_fuse, OID_AUTO, data_cache_invalidate, CTLFLAG_RW,
+SYSCTL_INT(_vfs_fusefs, OID_AUTO, data_cache_invalidate, CTLFLAG_RW,
&fuse_data_cache_invalidate, 0,
"If non-zero, discard cached clean file data when there are no active file"
" users");
int fuse_mmap_enable = 1;
-SYSCTL_INT(_vfs_fuse, OID_AUTO, mmap_enable, CTLFLAG_RW,
+SYSCTL_INT(_vfs_fusefs, OID_AUTO, mmap_enable, CTLFLAG_RW,
&fuse_mmap_enable, 0,
"If non-zero, and data_cache_mode is also non-zero, enable mmap(2) of "
"FUSE files");
int fuse_refresh_size = 0;
-SYSCTL_INT(_vfs_fuse, OID_AUTO, refresh_size, CTLFLAG_RW,
+SYSCTL_INT(_vfs_fusefs, OID_AUTO, refresh_size, CTLFLAG_RW,
&fuse_refresh_size, 0,
"If non-zero, and no dirty file extension data is buffered, fetch file "
"size before write operations");
int fuse_sync_resize = 1;
-SYSCTL_INT(_vfs_fuse, OID_AUTO, sync_resize, CTLFLAG_RW,
+SYSCTL_INT(_vfs_fusefs, OID_AUTO, sync_resize, CTLFLAG_RW,
&fuse_sync_resize, 0,
"If a cached write extended a file, inform FUSE filesystem of the changed"
"size immediately subsequent to the issued writes");
int fuse_fix_broken_io = 0;
-SYSCTL_INT(_vfs_fuse, OID_AUTO, fix_broken_io, CTLFLAG_RW,
+SYSCTL_INT(_vfs_fusefs, OID_AUTO, fix_broken_io, CTLFLAG_RW,
&fuse_fix_broken_io, 0,
"If non-zero, print a diagnostic warning if a userspace filesystem returns"
" EIO on reads of recently extended portions of files");
Index: sys/fs/fusefs/fuse_vfsops.c
===================================================================
--- sys/fs/fusefs/fuse_vfsops.c
+++ sys/fs/fusefs/fuse_vfsops.c
@@ -115,16 +115,16 @@
.vfs_statfs = fuse_vfsop_statfs,
};
-SYSCTL_INT(_vfs_fuse, OID_AUTO, init_backgrounded, CTLFLAG_RD,
+SYSCTL_INT(_vfs_fusefs, OID_AUTO, init_backgrounded, CTLFLAG_RD,
SYSCTL_NULL_INT_PTR, 1, "indicate async handshake");
static int fuse_enforce_dev_perms = 0;
-SYSCTL_INT(_vfs_fuse, OID_AUTO, enforce_dev_perms, CTLFLAG_RW,
+SYSCTL_INT(_vfs_fusefs, OID_AUTO, enforce_dev_perms, CTLFLAG_RW,
&fuse_enforce_dev_perms, 0,
"enforce fuse device permissions for secondary mounts");
static unsigned sync_unmount = 1;
-SYSCTL_UINT(_vfs_fuse, OID_AUTO, sync_unmount, CTLFLAG_RW,
+SYSCTL_UINT(_vfs_fusefs, OID_AUTO, sync_unmount, CTLFLAG_RW,
&sync_unmount, 0, "specify when to use synchronous unmount");
MALLOC_DEFINE(M_FUSEVFS, "fuse_filesystem", "buffer for fuse vfs layer");
Index: sys/fs/fusefs/fuse_vnops.c
===================================================================
--- sys/fs/fusefs/fuse_vnops.c
+++ sys/fs/fusefs/fuse_vnops.c
@@ -179,17 +179,17 @@
static u_long fuse_lookup_cache_hits = 0;
-SYSCTL_ULONG(_vfs_fuse, OID_AUTO, lookup_cache_hits, CTLFLAG_RD,
+SYSCTL_ULONG(_vfs_fusefs, OID_AUTO, lookup_cache_hits, CTLFLAG_RD,
&fuse_lookup_cache_hits, 0, "number of positive cache hits in lookup");
static u_long fuse_lookup_cache_misses = 0;
-SYSCTL_ULONG(_vfs_fuse, OID_AUTO, lookup_cache_misses, CTLFLAG_RD,
+SYSCTL_ULONG(_vfs_fusefs, OID_AUTO, lookup_cache_misses, CTLFLAG_RD,
&fuse_lookup_cache_misses, 0, "number of cache misses in lookup");
int fuse_lookup_cache_enable = 1;
-SYSCTL_INT(_vfs_fuse, OID_AUTO, lookup_cache_enable, CTLFLAG_RW,
+SYSCTL_INT(_vfs_fusefs, OID_AUTO, lookup_cache_enable, CTLFLAG_RW,
&fuse_lookup_cache_enable, 0, "if non-zero, enable lookup cache");
/*
@@ -198,7 +198,7 @@
*/
static int fuse_reclaim_revoked = 0;
-SYSCTL_INT(_vfs_fuse, OID_AUTO, reclaim_revoked, CTLFLAG_RW,
+SYSCTL_INT(_vfs_fusefs, OID_AUTO, reclaim_revoked, CTLFLAG_RW,
&fuse_reclaim_revoked, 0, "");
uma_zone_t fuse_pbuf_zone;
Index: sys/modules/Makefile
===================================================================
--- sys/modules/Makefile
+++ sys/modules/Makefile
@@ -129,7 +129,7 @@
filemon \
firewire \
firmware \
- fuse \
+ fusefs \
${_fxp} \
gem \
geom \
Index: sys/modules/fuse/Makefile
===================================================================
--- sys/modules/fuse/Makefile
+++ sys/modules/fuse/Makefile
@@ -1,10 +0,0 @@
-# $FreeBSD$
-
-.PATH: ${SRCTOP}/sys/fs/fuse
-
-KMOD= fuse
-SRCS= vnode_if.h \
- fuse_node.c fuse_io.c fuse_device.c fuse_ipc.c fuse_file.c \
- fuse_vfsops.c fuse_vnops.c fuse_internal.c fuse_main.c
-
-.include <bsd.kmod.mk>
Index: sys/modules/fusefs/Makefile
===================================================================
--- sys/modules/fusefs/Makefile
+++ sys/modules/fusefs/Makefile
@@ -1,10 +1,13 @@
# $FreeBSD$
-.PATH: ${SRCTOP}/sys/fs/fuse
+.PATH: ${SRCTOP}/sys/fs/fusefs
-KMOD= fuse
+KMOD= fusefs
SRCS= vnode_if.h \
fuse_node.c fuse_io.c fuse_device.c fuse_ipc.c fuse_file.c \
fuse_vfsops.c fuse_vnops.c fuse_internal.c fuse_main.c
+
+# Symlink for backwards compatibility with systems installed at 12.0 or older
+LINKS= ${KMODDIR}/${KMOD}.ko ${KMODDIR}/fuse.ko
.include <bsd.kmod.mk>

File Metadata

Mime Type
text/plain
Expires
Thu, Jun 11, 6:35 PM (11 h, 16 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28882748
Default Alt Text
D19649.1781202912.diff (249 KB)

Event Timeline