Date: Thu, 12 Jul 2012 16:47:18 +0000 (UTC) From: Attilio Rao <attilio@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r238402 - in projects/fuse/sys: . conf fs/fuse modules/fuse Message-ID: <201207121647.q6CGlIeB018282@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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 ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201207121647.q6CGlIeB018282>