svn commit: r238402 - in projects/fuse/sys: . conf fs/fuse modules/fuse

Attilio Rao attilio at FreeBSD.org
Thu Jul 12 16:47:19 UTC 2012


Author: attilio
Date: Thu Jul 12 16:47:18 2012
New Revision: 238402
URL: http://svn.freebsd.org/changeset/base/238402

Log:
  Import FUSE implementation based on a contribution of IlyaPutsikau
  during GSoC 2011 and further developed by gnn recently.
  
  Submitted by:	gnn

Added:
  projects/fuse/sys/fs/fuse/
  projects/fuse/sys/fs/fuse/fuse.h   (contents, props changed)
  projects/fuse/sys/fs/fuse/fuse_debug.h   (contents, props changed)
  projects/fuse/sys/fs/fuse/fuse_device.c   (contents, props changed)
  projects/fuse/sys/fs/fuse/fuse_file.c   (contents, props changed)
  projects/fuse/sys/fs/fuse/fuse_file.h   (contents, props changed)
  projects/fuse/sys/fs/fuse/fuse_internal.c   (contents, props changed)
  projects/fuse/sys/fs/fuse/fuse_internal.h   (contents, props changed)
  projects/fuse/sys/fs/fuse/fuse_io.c   (contents, props changed)
  projects/fuse/sys/fs/fuse/fuse_io.h   (contents, props changed)
  projects/fuse/sys/fs/fuse/fuse_ipc.c   (contents, props changed)
  projects/fuse/sys/fs/fuse/fuse_ipc.h   (contents, props changed)
  projects/fuse/sys/fs/fuse/fuse_kernel.h   (contents, props changed)
  projects/fuse/sys/fs/fuse/fuse_main.c   (contents, props changed)
  projects/fuse/sys/fs/fuse/fuse_node.c   (contents, props changed)
  projects/fuse/sys/fs/fuse/fuse_node.h   (contents, props changed)
  projects/fuse/sys/fs/fuse/fuse_param.h   (contents, props changed)
  projects/fuse/sys/fs/fuse/fuse_version.h   (contents, props changed)
  projects/fuse/sys/fs/fuse/fuse_vfsops.c   (contents, props changed)
  projects/fuse/sys/fs/fuse/fuse_vnops.c   (contents, props changed)
  projects/fuse/sys/modules/fuse/
  projects/fuse/sys/modules/fuse/Makefile   (contents, props changed)
Modified:
  projects/fuse/sys/Makefile
  projects/fuse/sys/conf/files

Modified: projects/fuse/sys/Makefile
==============================================================================
--- projects/fuse/sys/Makefile	Thu Jul 12 16:24:58 2012	(r238401)
+++ projects/fuse/sys/Makefile	Thu Jul 12 16:47:18 2012	(r238402)
@@ -8,8 +8,8 @@ SUBDIR=	boot
 .endif
 
 # Directories to include in cscope name file and TAGS.
-CSCOPEDIRS=	boot bsm cam cddl compat conf contrib crypto ddb dev fs gdb \
-		geom gnu isa kern libkern modules net net80211 netatalk \
+CSCOPEDIRS=	boot bsm cam cddl compat conf contrib crypto ddb dev fs fuse \
+		gdb geom gnu isa kern libkern modules net net80211 netatalk \
 		netgraph netinet netinet6 netipsec netipx netnatm netncp \
 		netsmb nfs nfsclient nfsserver nlm ofed opencrypto \
 		pci rpc security sys ufs vm xdr xen ${CSCOPE_ARCHDIR}

Modified: projects/fuse/sys/conf/files
==============================================================================
--- projects/fuse/sys/conf/files	Thu Jul 12 16:24:58 2012	(r238401)
+++ projects/fuse/sys/conf/files	Thu Jul 12 16:47:18 2012	(r238402)
@@ -2272,6 +2272,15 @@ fs/devfs/devfs_vnops.c		standard
 fs/fdescfs/fdesc_vfsops.c	optional fdescfs
 fs/fdescfs/fdesc_vnops.c	optional fdescfs
 fs/fifofs/fifo_vnops.c		standard
+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/hpfs/hpfs_alsubr.c		optional hpfs
 fs/hpfs/hpfs_lookup.c		optional hpfs
 fs/hpfs/hpfs_subr.c		optional hpfs

Added: projects/fuse/sys/fs/fuse/fuse.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/fuse/sys/fs/fuse/fuse.h	Thu Jul 12 16:47:18 2012	(r238402)
@@ -0,0 +1,216 @@
+/*
+ * 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 "fuse_version.h"
+#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 */
+
+
+/* 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);

Added: projects/fuse/sys/fs/fuse/fuse_debug.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/fuse/sys/fs/fuse/fuse_debug.h	Thu Jul 12 16:47:18 2012	(r238402)
@@ -0,0 +1,77 @@
+/*
+ * 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>
+
+/* 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 DEBUG(fmt, ...)         DEBUGX(FUSE_DEBUG_VAR >= 1, fmt, ## __VA_ARGS__)
+#define DEBUG2G(fmt, ...)       DEBUGX(FUSE_DEBUG_VAR >= 2, fmt, ## __VA_ARGS__)
+
+#define debug_printf(fmt, ...)  DEBUG(fmt, ## __VA_ARGS__)
+#define kdebug_printf(fmt, ...) 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()

Added: projects/fuse/sys/fs/fuse/fuse_device.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/fuse/sys/fs/fuse/fuse_device.c	Thu Jul 12 16:47:18 2012	(r238402)
@@ -0,0 +1,519 @@
+/*
+ * 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 __inline int
+fuse_ohead_audit(struct fuse_out_header *ohead,
+    struct uio *uio);
+
+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;
+
+void
+fuse_device_clone(void *arg, struct ucred *cred, char *name,
+    int namelen, struct cdev **dev);
+
+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,
+	.d_flags = D_NEEDMINOR,
+};
+
+/*
+ * This struct is not public, but we are eager to use it,
+ * so we have to put its def here.
+ */
+struct clonedevs {
+	LIST_HEAD(, cdev) head;
+};
+
+struct clonedevs *fuseclones;
+
+/****************************
+ *
+ * >>> Fuse device op defs
+ *
+ ****************************/
+
+/*
+ * 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;
+
+	if (dev->si_usecount > 1)
+		goto busy;
+
+	DEBUG("device %p\n", dev);
+
+	fdata = fdata_alloc(dev, td->td_ucred);
+
+	FUSE_LOCK();
+	if (fuse_get_devdata(dev)) {
+		fdata_trydestroy(fdata);
+		FUSE_UNLOCK();
+		goto busy;
+	} else {
+		fdata->dataflags |= FSESS_OPENED;
+		dev->si_drv1 = fdata;
+	}
+	FUSE_UNLOCK();
+
+	DEBUG("%s: device opened by thread %d.\n", dev->si_name, td->td_tid);
+
+	return (0);
+
+busy:
+	return (EBUSY);
+}
+
+static int
+fuse_device_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
+{
+	struct fuse_data *data;
+	struct fuse_ticket *tick;
+
+	data = fuse_get_devdata(dev);
+	if (!data)
+		panic("no fuse data upon fuse device close");
+	KASSERT(data->dataflags | FSESS_OPENED,
+	    ("fuse device is already closed upon close"));
+	fdata_set_dead(data);
+
+	FUSE_LOCK();
+	data->dataflags &= ~FSESS_OPENED;
+
+	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);
+
+	dev->si_drv1 = NULL;
+	fdata_trydestroy(data);
+	FUSE_UNLOCK();
+
+	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 revents = 0;
+
+	data = fuse_get_devdata(dev);
+
+	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 = 0;
+	struct fuse_data *data;
+	struct fuse_ticket *tick;
+	void *buf[] = {NULL, NULL, NULL};
+	int buflen[3];
+	int i;
+
+	data = fuse_get_devdata(dev);
+
+	DEBUG("fuse device being read on thread %d\n", uio->uio_td->td_tid);
+
+	fuse_lck_mtx_lock(data->ms_mtx);
+again:
+	if (fdata_get_dead(data)) {
+		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 ?)
+		 */
+		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
+		 */
+		DEBUG2G("reader is to be sacked\n");
+		if (tick) {
+			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 */
+	}
+	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);
+			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)
+{
+	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) {
+		DEBUG("Format error: body size differs from size claimed by header\n");
+		return (EINVAL);
+	}
+	if (uio->uio_resid && ohead->error) {
+		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;
+
+	DEBUG("resid: %zd, iovcnt: %d, thread: %d\n",
+	    uio->uio_resid, uio->uio_iovcnt, uio->uio_td->td_tid);
+
+	data = fuse_get_devdata(dev);
+
+	if (uio->uio_resid < sizeof(struct fuse_out_header)) {
+		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) {
+		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...)
+			 */
+			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 */
+			DEBUG("stuff devalidated, so we drop it\n");
+		}
+		FUSE_ASSERT_AW_DONE(tick);
+		fuse_ticket_drop(tick);
+	} else {
+		/* no callback at all! */
+		DEBUG("erhm, no handler for this response\n");
+		err = EINVAL;
+	}
+
+	return (err);
+}
+
+/*
+ * Modeled after tunclone() of net/if_tun.c ...
+ * boosted with a hack so that devices can be reused.
+ */
+void
+fuse_device_clone(void *arg, struct ucred *cred, char *name, int namelen,
+    struct cdev **dev)
+{
+	/*
+	 * Why cloning? We do need per-open info, but we could as well put our
+	 * hands on the file struct assigned to an open by implementing
+	 * d_fdopen instead of d_open.
+	 *
+	 * From that on, the usual way to per-open (that is, file aware)
+	 * I/O would be pushing our preferred set of ops into the f_op
+	 * field of that file at open time. But that wouldn't work in
+	 * FreeBSD, as the devfs open routine (which is the one who calls
+	 * the device's d_(fd)open) overwrites that f_op with its own
+	 * file ops mercilessly.
+	 *
+	 * Yet... even if we could get devfs to keep our file ops intact,
+	 * I'd still say cloning is better. It makes fuse daemons' identity
+	 * explicit and globally visible to userspace, and we are not forced
+	 * to get the mount done by the daemon itself like in linux (where
+	 * I/O is file aware by default). (The possibilities of getting the
+	 * daemon do the mount or getting the mount util spawn the daemon
+	 * are still open, of course; I guess I will go for the latter
+	 * appcocroach.)
+	 */
+
+	int i, unit;
+
+	if (*dev != NULL)
+		return;
+
+	if (strcmp(name, "fuse") == 0) {
+		struct cdev *xdev;
+
+		unit = -1;
+
+		/*
+		 * Before falling back to the standard routine, we try
+		 * to find an existing free device by ourselves, so that
+		 * it will be reused instead of having the clone machinery
+		 * dummily spawn a new one.
+		 */
+		dev_lock();
+		LIST_FOREACH(xdev, &fuseclones->head, si_clone) {
+			KASSERT(xdev->si_flags & SI_CLONELIST,
+			    ("Dev %p(%s) should be on clonelist", xdev, xdev->si_name));
+
+			if (!xdev->si_drv1) {
+				unit = dev2unit(xdev);
+				break;
+			}
+		}
+		dev_unlock();
+	} else if (dev_stdclone(name, NULL, "fuse", &unit) != 1) {
+		return;
+	}
+	/* find any existing device, or allocate new unit number */
+	i = clone_create(&fuseclones, &fuse_device_cdevsw, &unit, dev, 0);
+	if (i) {
+		*dev = make_dev(&fuse_device_cdevsw,
+		    unit,
+		    UID_ROOT, GID_OPERATOR,
+		    S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
+		    "fuse%d", unit);
+		if (*dev == NULL)
+			return;
+	}
+	KASSERT(*dev, ("no device after apparently successful cloning"));
+	dev_ref(*dev);
+	(*dev)->si_drv1 = NULL;
+	(*dev)->si_flags |= SI_CHEAPCLONE;
+
+	DEBUG("clone done: %d\n", unit);
+}

Added: projects/fuse/sys/fs/fuse/fuse_file.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/fuse/sys/fs/fuse/fuse_file.c	Thu Jul 12 16:47:18 2012	(r238402)
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2007-2009 Google Inc. and Amit Singh <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, "");
+
+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 isdir = 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)) {
+		isdir = 1;
+		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);
+	fuse_vnode_open(vp, foo->open_flags, td);
+

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-projects mailing list