summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2008-06-16 14:16:02 +0000
committerMiklos Szeredi <miklos@szeredi.hu>2008-06-16 14:16:02 +0000
commitc75d6298b4d083b5e8b99117602e75fbe9ddd45b (patch)
tree13b6e2cc0f680e36c140fdcc99a6f27defeae0b4
parent74579f986208b82bda2b3e3d3c4b67f69e69f039 (diff)
downloadfuse-c75d6298b4d083b5e8b99117602e75fbe9ddd45b.tar.gz
Remove fuse kernel module sources
-rw-r--r--ChangeLog5
-rw-r--r--Makefile.am2
-rw-r--r--README21
-rw-r--r--README.NFS15
-rw-r--r--configure.in6
-rw-r--r--include/fuse_kernel.h (renamed from kernel/fuse_kernel.h)0
-rw-r--r--kernel/.cvsignore12
-rw-r--r--kernel/Makefile.in53
-rw-r--r--kernel/configure.ac230
-rw-r--r--kernel/control.c254
-rw-r--r--kernel/dev.c1124
-rw-r--r--kernel/dir.c1377
-rw-r--r--kernel/file.c900
-rw-r--r--kernel/fuse_i.h654
-rw-r--r--kernel/inode.c1101
-rwxr-xr-xmakeconf.sh2
16 files changed, 9 insertions, 5747 deletions
diff --git a/ChangeLog b/ChangeLog
index 18a479a..dee8a3b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2008-06-16 Miklos Szeredi <miklos@szeredi.hu>
+
+ * Remove fuse kernel module sources. Linux 2.6.27 will support
+ NFS exporting.
+
2008-06-10 Miklos Szeredi <miklos@szeredi.hu>
* Fix theoretical infinite loops in libfuse. Reported by Szabolcs
diff --git a/Makefile.am b/Makefile.am
index 06014ee..772dfcc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,6 +1,6 @@
## Process this file with automake to produce Makefile.in
-SUBDIRS = @subdirs@ @subdirs2@
+SUBDIRS = @subdirs2@
EXTRA_DIST = \
fuse.pc.in \
diff --git a/README b/README
index 4d9dd92..398dd65 100644
--- a/README
+++ b/README
@@ -35,25 +35,8 @@ modprobe fuse
You may also need to add '/usr/local/lib' to '/etc/ld.so.conf' and/or
run ldconfig.
-Linux kernels 2.6.14 or later contain FUSE support out of the box. If
-FUSE support is detected, the kernel module in this package will not
-be compiled. It is possible to override this with the
-'--enable-kernel-module' configure option.
-
-If './configure' cannot find the kernel source or it says the kernel
-source should be prepared, you may either try
-
- ./configure --disable-kernel-module
-
-or if your kernel does not already contain FUSE support, do the
-following:
-
- - Extract the kernel source to some directory
-
- - Copy the running kernel's config (usually found in
- /boot/config-X.Y.Z) to .config at the top of the source tree
-
- - Run 'make prepare'
+You'll also need a fuse kernel module, Linux kernels 2.6.14 or later
+contain FUSE support.
For more details see the file 'INSTALL'
diff --git a/README.NFS b/README.NFS
index a6f48c5..b805f39 100644
--- a/README.NFS
+++ b/README.NFS
@@ -1,17 +1,4 @@
-FUSE module in official kernels (>= 2.6.14) don't support NFS
-exporting. In this case if you need NFS exporting capability, use the
-'--enable-kernel-module' configure option to compile the module from
-this package. And make sure, that the FUSE is not compiled into the
-kernel (CONFIG_FUSE_FS must be 'm' or 'n').
+NFS exporting is supported in Linux kernels 2.6.27 or later.
You need to add an fsid=NNN option to /etc/exports to make exporting a
FUSE directory work.
-
-You may get ESTALE (Stale NFS file handle) errors with this. This is
-because the current FUSE kernel API and the userspace library cannot
-handle a situation where the kernel forgets about an inode which is
-still referenced by the remote NFS client. This problem will be
-addressed in a later version.
-
-In the future it planned that NFS exporting will be done solely in
-userspace.
diff --git a/configure.in b/configure.in
index 6c4f484..61d3ca8 100644
--- a/configure.in
+++ b/configure.in
@@ -23,8 +23,6 @@ if test "$ac_env_CFLAGS_set" != set; then
CFLAGS="-Wall -W -Wno-sign-compare -Wstrict-prototypes -Wmissing-declarations -Wwrite-strings -g -O2 -fno-strict-aliasing"
fi
-AC_ARG_ENABLE(kernel-module,
- [ --enable-kernel-module Compile kernel module ])
AC_ARG_ENABLE(lib,
[ --enable-lib Compile with library ])
AC_ARG_ENABLE(util,
@@ -42,10 +40,6 @@ AC_SUBST(pkgconfigdir)
subdirs2="include"
-if test "$arch" = linux -a "$enable_kernel_module" != "no"; then
- AC_CONFIG_SUBDIRS(kernel)
-fi
-
if test "$enable_lib" != "no"; then
subdirs2="$subdirs2 lib";
fi
diff --git a/kernel/fuse_kernel.h b/include/fuse_kernel.h
index c9c4c7e..c9c4c7e 100644
--- a/kernel/fuse_kernel.h
+++ b/include/fuse_kernel.h
diff --git a/kernel/.cvsignore b/kernel/.cvsignore
deleted file mode 100644
index ed24c33..0000000
--- a/kernel/.cvsignore
+++ /dev/null
@@ -1,12 +0,0 @@
-Makefile
-configure
-config.*
-*.cache
-.deps
-.*.cmd
-*.mod.c
-*.ko
-*.s
-.tmp_versions
-.*.d
-*.symvers
diff --git a/kernel/Makefile.in b/kernel/Makefile.in
deleted file mode 100644
index e26c700..0000000
--- a/kernel/Makefile.in
+++ /dev/null
@@ -1,53 +0,0 @@
-# Makefile.in for kernel module
-
-SHELL = /bin/sh
-INSTALL = @INSTALL@
-mkdir_p = mkdir -p
-VERSION = @PACKAGE_VERSION@
-
-DISTFILES = Makefile.in configure.ac configure config.h.in ../install-sh \
- dev.c dir.c file.c inode.c fuse_i.h fuse_kernel.h control.c
-
-fusemoduledir = @kmoduledir@/kernel/fs/fuse
-
-fusemodule := fuse.ko
-
-all: all-@ENABLE_FUSE_MODULE@
-install: install-@ENABLE_FUSE_MODULE@
-uninstall: uninstall-@ENABLE_FUSE_MODULE@
-
-all-n:
-install-n:
-uninstall-n:
-
-all-y: all-spec
-
-install-y: all
- $(mkdir_p) $(DESTDIR)$(fusemoduledir)
- $(INSTALL) -m 644 $(fusemodule) $(DESTDIR)$(fusemoduledir)/$(fusemodule)
- -/sbin/depmod -a
-
-uninstall-y:
- rm -f $(DESTDIR)$(fusemoduledir)/$(fusemodule)
- -/sbin/depmod -a
-
-clean:
- -rm -f $(fusemodule) *.o .*.cmd *.mod.c *.ko *.s */*.o
-
-distclean: clean
- rm -f Makefile
- rm -f config.h config.log config.status config.cache
- rm -rf .tmp_versions
-
-maintainer-clean: distclean
-
-distdir: $(DISTFILES)
- cp -p $(DISTFILES) $(distdir)
-
-EXTRA_CFLAGS += -DFUSE_VERSION=\"$(VERSION)\"
-
-obj-m := fuse.o
-fuse-objs := dev.o dir.o file.o inode.o control.o
-
-all-spec:
- $(MAKE) -C @kernelsrc@ SUBDIRS=`pwd` @KERNELMAKE_PARAMS@ modules
diff --git a/kernel/configure.ac b/kernel/configure.ac
deleted file mode 100644
index fb42264..0000000
--- a/kernel/configure.ac
+++ /dev/null
@@ -1,230 +0,0 @@
-AC_INIT(fuse-kernel, 2.8.0-pre0)
-AC_CONFIG_HEADERS([config.h])
-
-AC_PROG_INSTALL
-
-runver=`uname -r`
-bad_kernel_version=no
-ENABLE_FUSE_MODULE=y
-KERNELCFLAGS=
-
-kernelsrc=
-kernelbuild=
-AC_ARG_WITH(kernel,
- [ --with-kernel=PATH Specify location of kernel source ],
- [kernelsrc="$withval"; kernelbuild="$withval"])
-AC_ARG_WITH(kernel-build,
- [ --with-kernel-build=PATH Specify location of kernel build ],
- [kernelbuild="$withval"])
-AC_ARG_ENABLE(kernel-module,
- [ --enable-kernel-module Compile kernel module ])
-
-if test -z "$enable_kernel_module" -a -z "$kernelbuild" && echo "$runver" | grep -q "^2.6"; then
- checkmodule=no
- AC_MSG_CHECKING([if FUSE is loaded as a module])
- if cat /proc/modules | grep -q "^fuse "; then
- AC_MSG_RESULT([yes])
- checkmodule=yes
- else
- AC_MSG_RESULT([no])
- AC_MSG_CHECKING([if FUSE module is built into the kernel])
- if test -e /sys/class/misc/fuse; then
- AC_MSG_RESULT([yes])
- ENABLE_FUSE_MODULE=n
- else
- AC_MSG_RESULT([no])
- checkmodule=yes
- fi
- fi
- if test "$checkmodule" = yes; then
- AC_MSG_CHECKING([if FUSE module is from official kernel])
- if test ! -f /lib/modules/${runver}/kernel/fs/fuse/fuse.ko; then
- AC_MSG_RESULT([no])
- elif fgrep -q "fuse distribution version: " /lib/modules/${runver}/kernel/fs/fuse/fuse.ko 2> /dev/null; then
- AC_MSG_RESULT([no])
- else
- AC_MSG_RESULT([yes])
- ENABLE_FUSE_MODULE=n
- fi
- fi
-fi
-
-if test "$ENABLE_FUSE_MODULE" = y; then
- AC_MSG_CHECKING([kernel source directory])
- if test -z "$kernelsrc"; then
- kernelbuild=
- sourcelink=/lib/modules/${runver}/source
- buildlink=/lib/modules/${runver}/build
-
- if test -e $sourcelink; then
- kernelsrc=`(cd $sourcelink; /bin/pwd)`
- fi
- if test -e $buildlink; then
- kernelbuild=`(cd $buildlink; /bin/pwd)`
- fi
- if test -z "$kernelsrc"; then
- kernelsrc=$kernelbuild
- fi
- if test -z "$kernelsrc" -o -z "$kernelbuild"; then
- AC_MSG_RESULT([Not found])
- AC_MSG_ERROR([
- *** Please specify the location of the kernel source with
- *** the '--with-kernel=SRCDIR' option])
- fi
- fi
- AC_MSG_RESULT([$kernelsrc])
- AC_MSG_CHECKING([kernel build directory])
- AC_MSG_RESULT([$kernelbuild])
-
- AC_MSG_CHECKING([kernel source version])
- if test -r $kernelbuild/include/linux/version.h && fgrep -q UTS_RELEASE $kernelbuild/include/linux/version.h; then
- kernsrcver=`(echo "#include <linux/version.h>"; echo "kernsrcver=UTS_RELEASE") | cpp -I $kernelbuild/include | grep "^kernsrcver=" | cut -d \" -f 2`
- elif test -r $kernelbuild/include/linux/utsrelease.h && fgrep -q UTS_RELEASE $kernelbuild/include/linux/utsrelease.h; then
- kernsrcver=`(echo "#include <linux/utsrelease.h>"; echo "kernsrcver=UTS_RELEASE") | cpp -I $kernelbuild/include | grep "^kernsrcver=" | cut -d \" -f 2`
- fi
- if test -z "$kernsrcver"; then
- AC_MSG_RESULT([Not found])
- AC_MSG_ERROR([
- *** Cannot determine the version of the linux kernel source. Please
- *** prepare the kernel before running this script])
- fi
- AC_MSG_RESULT([$kernsrcver])
- kmoduledir=${INSTALL_MOD_PATH}/lib/modules/$kernsrcver
- AC_SUBST(kernelsrc)
- AC_SUBST(kmoduledir)
-
- if echo "$kernsrcver" | egrep -q ["^(2.4|2.6.[0-8]([^0-9]|\$))"]; then
- bad_kernel_version=yes
- AC_MSG_NOTICE([
-NOTE: Disabled building the kernel module, because this release only
-NOTE: supports Linux versions 2.6.9 or later. You can use the kernel
-NOTE: module from an earlier FUSE release with the library from this
-NOTE: release.])
- else
- fuse_configured=no
- kernel_autoconf=$kernelbuild/include/linux/autoconf.h
- AC_MSG_CHECKING([if FUSE is configured in the kernel])
- if test -f $kernel_autoconf; then
- if grep -q "^#define CONFIG_FUSE_FS 1" $kernel_autoconf || grep -q "^#define CONFIG_FUSE_FS_MODULE 1" $kernel_autoconf; then
- fuse_configured=yes
- fi
- fi
- AC_MSG_RESULT([$fuse_configured])
- if test -z "$enable_kernel_module" -a "$fuse_configured" = yes; then
- ENABLE_FUSE_MODULE=n
- fi
- fi
-fi
-
-if test "$ENABLE_FUSE_MODULE" = n; then
- AC_MSG_NOTICE([
-NOTE: Detected that FUSE is already present in the kernel, so
-NOTE: building of kernel module is disabled. To force building
-NOTE: of kernel module use the '--enable-kernel-module' option.])
-fi
-
-if test "$enable_kernel_module" = no; then
- ENABLE_FUSE_MODULE=n
-fi
-if test "$bad_kernel_version" = yes; then
- ENABLE_FUSE_MODULE=n
-fi
-
-AC_SUBST(ENABLE_FUSE_MODULE)
-
-if test "$ENABLE_FUSE_MODULE" = y; then
- AC_MSG_CHECKING([if kernel defines kzalloc function])
- if egrep -qw "kzalloc" $kernelsrc/include/linux/slab.h; then
- AC_DEFINE(HAVE_KZALLOC, 1, [kzalloc() is defined])
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no])
- fi
-
- AC_MSG_CHECKING([if kernel defines fs_subsys])
- if egrep -qw "fs_subsys" $kernelsrc/include/linux/fs.h; then
- AC_DEFINE(HAVE_FS_SUBSYS, 1, [fs_subsys is defined])
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no])
- fi
-
- AC_MSG_CHECKING([whether lookup_instantiate_filp is defined])
- if test -f $kernelsrc/include/linux/namei.h && egrep -q "lookup_instantiate_filp" $kernelsrc/include/linux/namei.h; then
- AC_DEFINE(HAVE_LOOKUP_INSTANTIATE_FILP, 1, [lookup_instantiate_filp() is defined])
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no])
- fi
-
- AC_MSG_CHECKING([if umount_begin is passed a vfsmount])
- if egrep -q "\(\*umount_begin\) *\(struct vfsmount \*" $kernelsrc/include/linux/fs.h; then
- AC_DEFINE(UMOUNT_BEGIN_VFSMOUNT, 1, [umount_begin is passed a vfsmount])
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no])
- fi
-
- AC_MSG_CHECKING([if inode has i_blksize field])
- if egrep -qw "i_blksize" $kernelsrc/include/linux/fs.h; then
- AC_DEFINE(HAVE_I_BLKSIZE, 1, [inode has i_blksize field])
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no])
- fi
- AC_MSG_CHECKING([if inode has i_private field])
- if egrep -qw "i_private" $kernelsrc/include/linux/fs.h; then
- AC_DEFINE(HAVE_I_PRIVATE, 1, [inode has i_private field])
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no])
- fi
- AC_MSG_CHECKING([if inode has i_mutex field ])
- if egrep -qw "i_mutex" $kernelsrc/include/linux/fs.h; then
- AC_DEFINE(HAVE_I_MUTEX, 1, [inode has i_mutex field])
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no])
- fi
- AC_MSG_CHECKING([if kernel has mutex.h ])
- if test -f $kernelsrc/include/linux/mutex.h; then
- AC_DEFINE(HAVE_MUTEX_H, 1, [kernel has mutex.h])
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no])
- fi
- AC_MSG_CHECKING([if kernel has exportfs.h ])
- if test -f $kernelsrc/include/linux/exportfs.h; then
- AC_DEFINE(HAVE_EXPORTFS_H, 1, [kernel has exportfs.h])
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no])
- fi
- AC_MSG_CHECKING([if kernel has BLOCK option ])
- if test -f $kernelsrc/block/Kconfig && egrep -q "config *BLOCK" $kernelsrc/block/Kconfig; then
- AC_DEFINE(HAVE_CONFIG_BLOCK, 1, [kernel has BLOCK option])
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no])
- fi
-
- isuml=no
- KERNELMAKE_PARAMS=
- KERNELCPPFLAGS=
- AC_MSG_CHECKING([if this is user mode linux])
- if test -f $kernelbuild/include/linux/autoconf.h && egrep -q "^#define CONFIG_(USERMODE|UML) 1" $kernelbuild/include/linux/autoconf.h; then
- isuml=yes
- KERNELMAKE_PARAMS="ARCH=um"
- KERNELCPPFLAGS="-D__arch_um__ -DSUBARCH=\\\"i386\\\" -D_LARGEFILE64_SOURCE -I${kernelsrc}/arch/um/include -Derrno=kernel_errno -I${kernelsrc}/arch/um/kernel/tt/include -I${kernelsrc}/arch/um/kernel/skas/include"
- fi
- AC_MSG_RESULT([$isuml])
- if test "$kernelbuild" != "$kernelsrc"; then
- KERNELMAKE_PARAMS="$KERNELMAKE_PARAMS O=$kernelbuild"
- fi
- AC_SUBST(KERNELMAKE_PARAMS)
- AC_SUBST(KERNELCPPFLAGS)
- AC_SUBST(KERNELCFLAGS)
-fi
-
-AC_CONFIG_FILES([Makefile])
-AC_OUTPUT
diff --git a/kernel/control.c b/kernel/control.c
deleted file mode 100644
index 5ffe6ba..0000000
--- a/kernel/control.c
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- FUSE: Filesystem in Userspace
- 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.
-*/
-
-#include "fuse_i.h"
-
-#include <linux/init.h>
-#include <linux/module.h>
-
-#define FUSE_CTL_SUPER_MAGIC 0x65735543
-#ifndef HAVE_I_PRIVATE
-#define i_private u.generic_ip
-#endif
-
-/*
- * This is non-NULL when the single instance of the control filesystem
- * exists. Protected by fuse_mutex
- */
-static struct super_block *fuse_control_sb;
-
-static struct fuse_conn *fuse_ctl_file_conn_get(struct file *file)
-{
- struct fuse_conn *fc;
- mutex_lock(&fuse_mutex);
- fc = file->f_dentry->d_inode->i_private;
- if (fc)
- fc = fuse_conn_get(fc);
- mutex_unlock(&fuse_mutex);
- return fc;
-}
-
-static ssize_t fuse_conn_abort_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
- if (fc) {
- fuse_abort_conn(fc);
- fuse_conn_put(fc);
- }
- return count;
-}
-
-static ssize_t fuse_conn_waiting_read(struct file *file, char __user *buf,
- size_t len, loff_t *ppos)
-{
- char tmp[32];
- size_t size;
-
- if (!*ppos) {
- struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
- if (!fc)
- return 0;
-
- file->private_data=(void *)(long)atomic_read(&fc->num_waiting);
- fuse_conn_put(fc);
- }
- size = sprintf(tmp, "%ld\n", (long)file->private_data);
- return simple_read_from_buffer(buf, len, ppos, tmp, size);
-}
-
-static struct file_operations fuse_ctl_abort_ops = {
- .open = nonseekable_open,
- .write = fuse_conn_abort_write,
-};
-
-static struct file_operations fuse_ctl_waiting_ops = {
- .open = nonseekable_open,
- .read = fuse_conn_waiting_read,
-};
-
-#ifndef KERNEL_2_6_10_PLUS
-struct dentry *d_alloc_name(struct dentry *parent, const char *name)
-{
- struct qstr q;
-
- q.name = (const unsigned char *) name;
- q.len = strlen(name);
- q.hash = full_name_hash(q.name, q.len);
- return d_alloc(parent, &q);
-}
-#endif
-static struct dentry *fuse_ctl_add_dentry(struct dentry *parent,
- struct fuse_conn *fc,
- const char *name,
- int mode, int nlink,
-#ifdef KERNEL_2_6_21_PLUS
- const struct inode_operations *iop,
-#else
- struct inode_operations *iop,
-#endif
-#ifdef KERNEL_2_6_17_PLUS
- const struct file_operations *fop
-#else
- struct file_operations *fop
-#endif
-)
-{
- struct dentry *dentry;
- struct inode *inode;
-
- BUG_ON(fc->ctl_ndents >= FUSE_CTL_NUM_DENTRIES);
- dentry = d_alloc_name(parent, name);
- if (!dentry)
- return NULL;
-
- fc->ctl_dentry[fc->ctl_ndents++] = dentry;
- inode = new_inode(fuse_control_sb);
- if (!inode)
- return NULL;
-
- inode->i_mode = mode;
- inode->i_uid = fc->user_id;
- inode->i_gid = fc->group_id;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- /* setting ->i_op to NULL is not allowed */
- if (iop)
- inode->i_op = iop;
- inode->i_fop = fop;
- inode->i_nlink = nlink;
- inode->i_private = fc;
- d_add(dentry, inode);
- return dentry;
-}
-
-/*
- * Add a connection to the control filesystem (if it exists). Caller
- * must hold fuse_mutex
- */
-int fuse_ctl_add_conn(struct fuse_conn *fc)
-{
- struct dentry *parent;
- char name[32];
-
- if (!fuse_control_sb)
- return 0;
-
- parent = fuse_control_sb->s_root;
- inc_nlink(parent->d_inode);
- sprintf(name, "%llu", (unsigned long long) fc->id);
- parent = fuse_ctl_add_dentry(parent, fc, name, S_IFDIR | 0500, 2,
- &simple_dir_inode_operations,
- &simple_dir_operations);
- if (!parent)
- goto err;
-
- if (!fuse_ctl_add_dentry(parent, fc, "waiting", S_IFREG | 0400, 1,
- NULL, &fuse_ctl_waiting_ops) ||
- !fuse_ctl_add_dentry(parent, fc, "abort", S_IFREG | 0200, 1,
- NULL, &fuse_ctl_abort_ops))
- goto err;
-
- return 0;
-
- err:
- fuse_ctl_remove_conn(fc);
- return -ENOMEM;
-}
-
-/*
- * Remove a connection from the control filesystem (if it exists).
- * Caller must hold fuse_mutex
- */
-void fuse_ctl_remove_conn(struct fuse_conn *fc)
-{
- int i;
-
- if (!fuse_control_sb)
- return;
-
- for (i = fc->ctl_ndents - 1; i >= 0; i--) {
- struct dentry *dentry = fc->ctl_dentry[i];
- dentry->d_inode->i_private = NULL;
- d_drop(dentry);
- dput(dentry);
- }
- fuse_control_sb->s_root->d_inode->i_nlink--;
-}
-
-static int fuse_ctl_fill_super(struct super_block *sb, void *data, int silent)
-{
- struct tree_descr empty_descr = {""};
- struct fuse_conn *fc;
- int err;
-
- err = simple_fill_super(sb, FUSE_CTL_SUPER_MAGIC, &empty_descr);
- if (err)
- return err;
-
- mutex_lock(&fuse_mutex);
- BUG_ON(fuse_control_sb);
- fuse_control_sb = sb;
- list_for_each_entry(fc, &fuse_conn_list, entry) {
- err = fuse_ctl_add_conn(fc);
- if (err) {
- fuse_control_sb = NULL;
- mutex_unlock(&fuse_mutex);
- return err;
- }
- }
- mutex_unlock(&fuse_mutex);
-
- return 0;
-}
-
-#ifdef KERNEL_2_6_18_PLUS
-static int fuse_ctl_get_sb(struct file_system_type *fs_type, int flags,
- const char *dev_name, void *raw_data,
- struct vfsmount *mnt)
-{
- return get_sb_single(fs_type, flags, raw_data,
- fuse_ctl_fill_super, mnt);
-}
-#else
-static struct super_block *fuse_ctl_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *raw_data)
-{
- return get_sb_single(fs_type, flags, raw_data, fuse_ctl_fill_super);
-}
-#endif
-
-static void fuse_ctl_kill_sb(struct super_block *sb)
-{
- struct fuse_conn *fc;
-
- mutex_lock(&fuse_mutex);
- fuse_control_sb = NULL;
- list_for_each_entry(fc, &fuse_conn_list, entry)
- fc->ctl_ndents = 0;
- mutex_unlock(&fuse_mutex);
-
- kill_litter_super(sb);
-}
-
-static struct file_system_type fuse_ctl_fs_type = {
- .owner = THIS_MODULE,
- .name = "fusectl",
- .get_sb = fuse_ctl_get_sb,
- .kill_sb = fuse_ctl_kill_sb,
-};
-
-int __init fuse_ctl_init(void)
-{
- return register_filesystem(&fuse_ctl_fs_type);
-}
-
-void fuse_ctl_cleanup(void)
-{
- unregister_filesystem(&fuse_ctl_fs_type);
-}
diff --git a/kernel/dev.c b/kernel/dev.c
deleted file mode 100644
index f8b7f3a..0000000
--- a/kernel/dev.c
+++ /dev/null
@@ -1,1124 +0,0 @@
-/*
- FUSE: Filesystem in Userspace
- 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.
-*/
-
-#include "fuse_i.h"
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/poll.h>
-#include <linux/uio.h>
-#include <linux/miscdevice.h>
-#include <linux/pagemap.h>
-#include <linux/file.h>
-#include <linux/slab.h>
-
-#ifdef MODULE_ALIAS_MISCDEV
-MODULE_ALIAS_MISCDEV(FUSE_MINOR);
-#endif
-
-static struct kmem_cache *fuse_req_cachep;
-
-static struct fuse_conn *fuse_get_conn(struct file *file)
-{
- /*
- * Lockless access is OK, because file->private data is set
- * once during mount and is valid until the file is released.
- */
- return file->private_data;
-}
-
-static void fuse_request_init(struct fuse_req *req)
-{
- memset(req, 0, sizeof(*req));
- INIT_LIST_HEAD(&req->list);
- INIT_LIST_HEAD(&req->intr_entry);
- init_waitqueue_head(&req->waitq);
- atomic_set(&req->count, 1);
-}
-
-struct fuse_req *fuse_request_alloc(void)
-{
- struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, GFP_KERNEL);
- if (req)
- fuse_request_init(req);
- return req;
-}
-
-void fuse_request_free(struct fuse_req *req)
-{
- kmem_cache_free(fuse_req_cachep, req);
-}
-
-static void block_sigs(sigset_t *oldset)
-{
- sigset_t mask;
-
- siginitsetinv(&mask, sigmask(SIGKILL));
- sigprocmask(SIG_BLOCK, &mask, oldset);
-}
-
-static void restore_sigs(sigset_t *oldset)
-{
- sigprocmask(SIG_SETMASK, oldset, NULL);
-}
-
-static void __fuse_get_request(struct fuse_req *req)
-{
- atomic_inc(&req->count);
-}
-
-/* Must be called with > 1 refcount */
-static void __fuse_put_request(struct fuse_req *req)
-{
- BUG_ON(atomic_read(&req->count) < 2);
- atomic_dec(&req->count);
-}
-
-static void fuse_req_init_context(struct fuse_req *req)
-{
- req->in.h.uid = current->fsuid;
- req->in.h.gid = current->fsgid;
- req->in.h.pid = current->pid;
-}
-
-struct fuse_req *fuse_get_req(struct fuse_conn *fc)
-{
- struct fuse_req *req;
- sigset_t oldset;
- int intr;
- int err;
-
- atomic_inc(&fc->num_waiting);
- block_sigs(&oldset);
- intr = wait_event_interruptible(fc->blocked_waitq, !fc->blocked);
- restore_sigs(&oldset);
- err = -EINTR;
- if (intr)
- goto out;
-
- err = -ENOTCONN;
- if (!fc->connected)
- goto out;
-
- req = fuse_request_alloc();
- err = -ENOMEM;
- if (!req)
- goto out;
-
- fuse_req_init_context(req);
- req->waiting = 1;
- return req;
-
- out:
- atomic_dec(&fc->num_waiting);
- return ERR_PTR(err);
-}
-
-/*
- * Return request in fuse_file->reserved_req. However that may
- * currently be in use. If that is the case, wait for it to become
- * available.
- */
-static struct fuse_req *get_reserved_req(struct fuse_conn *fc,
- struct file *file)
-{
- struct fuse_req *req = NULL;
- struct fuse_file *ff = file->private_data;
-
- do {
- wait_event(fc->reserved_req_waitq, ff->reserved_req);
- spin_lock(&fc->lock);
- if (ff->reserved_req) {
- req = ff->reserved_req;
- ff->reserved_req = NULL;
- get_file(file);
- req->stolen_file = file;
- }
- spin_unlock(&fc->lock);
- } while (!req);
-
- return req;
-}
-
-/*
- * Put stolen request back into fuse_file->reserved_req
- */
-static void put_reserved_req(struct fuse_conn *fc, struct fuse_req *req)
-{
- struct file *file = req->stolen_file;
- struct fuse_file *ff = file->private_data;
-
- spin_lock(&fc->lock);
- fuse_request_init(req);
- BUG_ON(ff->reserved_req);
- ff->reserved_req = req;
- wake_up_all(&fc->reserved_req_waitq);
- spin_unlock(&fc->lock);
- fput(file);
-}
-
-/*
- * Gets a requests for a file operation, always succeeds
- *
- * This is used for sending the FLUSH request, which must get to
- * userspace, due to POSIX locks which may need to be unlocked.
- *
- * If allocation fails due to OOM, use the reserved request in
- * fuse_file.
- *
- * This is very unlikely to deadlock accidentally, since the
- * filesystem should not have it's own file open. If deadlock is
- * intentional, it can still be broken by "aborting" the filesystem.
- */
-struct fuse_req *fuse_get_req_nofail(struct fuse_conn *fc, struct file *file)
-{
- struct fuse_req *req;
-
- atomic_inc(&fc->num_waiting);
- wait_event(fc->blocked_waitq, !fc->blocked);
- req = fuse_request_alloc();
- if (!req)
- req = get_reserved_req(fc, file);
-
- fuse_req_init_context(req);
- req->waiting = 1;
- return req;
-}
-
-void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
-{
- if (atomic_dec_and_test(&req->count)) {
- if (req->waiting)
- atomic_dec(&fc->num_waiting);
-
- if (req->stolen_file)
- put_reserved_req(fc, req);
- else
- fuse_request_free(req);
- }
-}
-
-/*
- * This function is called when a request is finished. Either a reply
- * has arrived or it was aborted (and not yet sent) or some error
- * occurred during communication with userspace, or the device file
- * was closed. The requester thread is woken up (if still waiting),
- * the 'end' callback is called if given, else the reference to the
- * request is released
- *
- * Called with fc->lock, unlocks it
- */
-static void request_end(struct fuse_conn *fc, struct fuse_req *req)
-{
- void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
- req->end = NULL;
- list_del(&req->list);
- list_del(&req->intr_entry);
- req->state = FUSE_REQ_FINISHED;
- if (req->background) {
- if (fc->num_background == FUSE_MAX_BACKGROUND) {
- fc->blocked = 0;
- wake_up_all(&fc->blocked_waitq);
- }
- fc->num_background--;
- }
- spin_unlock(&fc->lock);
- dput(req->dentry);
- mntput(req->vfsmount);
- if (req->file)
- fput(req->file);
- wake_up(&req->waitq);
- if (end)
- end(fc, req);
- else
- fuse_put_request(fc, req);
-}
-
-static void wait_answer_interruptible(struct fuse_conn *fc,
- struct fuse_req *req)
-{
- if (signal_pending(current))
- return;
-
- spin_unlock(&fc->lock);
- wait_event_interruptible(req->waitq, req->state == FUSE_REQ_FINISHED);
- spin_lock(&fc->lock);
-}
-
-static void queue_interrupt(struct fuse_conn *fc, struct fuse_req *req)
-{
- list_add_tail(&req->intr_entry, &fc->interrupts);
- wake_up(&fc->waitq);
- kill_fasync(&fc->fasync, SIGIO, POLL_IN);
-}
-
-/* Called with fc->lock held. Releases, and then reacquires it. */
-static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
-{
- if (!fc->no_interrupt) {
- /* Any signal may interrupt this */
- wait_answer_interruptible(fc, req);
-
- if (req->aborted)
- goto aborted;
- if (req->state == FUSE_REQ_FINISHED)
- return;
-
- req->interrupted = 1;
- if (req->state == FUSE_REQ_SENT)
- queue_interrupt(fc, req);
- }
-
- if (req->force) {
- spin_unlock(&fc->lock);
- wait_event(req->waitq, req->state == FUSE_REQ_FINISHED);
- spin_lock(&fc->lock);
- } else {
- sigset_t oldset;
-
- /* Only fatal signals may interrupt this */
- block_sigs(&oldset);
- wait_answer_interruptible(fc, req);
- restore_sigs(&oldset);
- }
-
- if (req->aborted)
- goto aborted;
- if (req->state == FUSE_REQ_FINISHED)
- return;
-
- req->out.h.error = -EINTR;
- req->aborted = 1;
-
- aborted:
- if (req->locked) {
- /* This is uninterruptible sleep, because data is
- being copied to/from the buffers of req. During
- locked state, there mustn't be any filesystem
- operation (e.g. page fault), since that could lead
- to deadlock */
- spin_unlock(&fc->lock);
- wait_event(req->waitq, !req->locked);
- spin_lock(&fc->lock);
- }
- if (req->state == FUSE_REQ_PENDING) {
- list_del(&req->list);
- __fuse_put_request(req);
- } else if (req->state == FUSE_REQ_SENT) {
- spin_unlock(&fc->lock);
- wait_event(req->waitq, req->state == FUSE_REQ_FINISHED);
- spin_lock(&fc->lock);
- }
-}
-
-static unsigned len_args(unsigned numargs, struct fuse_arg *args)
-{
- unsigned nbytes = 0;
- unsigned i;
-
- for (i = 0; i < numargs; i++)
- nbytes += args[i].size;
-
- return nbytes;
-}
-
-static u64 fuse_get_unique(struct fuse_conn *fc)
- {
- fc->reqctr++;
- /* zero is special */
- if (fc->reqctr == 0)
- fc->reqctr = 1;
-
- return fc->reqctr;
-}
-
-static void queue_request(struct fuse_conn *fc, struct fuse_req *req)
-{
- req->in.h.unique = fuse_get_unique(fc);
- req->in.h.len = sizeof(struct fuse_in_header) +
- len_args(req->in.numargs, (struct fuse_arg *) req->in.args);
- list_add_tail(&req->list, &fc->pending);
- req->state = FUSE_REQ_PENDING;
- if (!req->waiting) {
- req->waiting = 1;
- atomic_inc(&fc->num_waiting);
- }
- wake_up(&fc->waitq);
- kill_fasync(&fc->fasync, SIGIO, POLL_IN);
-}
-
-void request_send(struct fuse_conn *fc, struct fuse_req *req)
-{
- req->isreply = 1;
- spin_lock(&fc->lock);
- if (!fc->connected)
- req->out.h.error = -ENOTCONN;
- else if (fc->conn_error)
- req->out.h.error = -ECONNREFUSED;
- else {
- queue_request(fc, req);
- /* acquire extra reference, since request is still needed
- after request_end() */
- __fuse_get_request(req);
-
- request_wait_answer(fc, req);
- }
- spin_unlock(&fc->lock);
-}
-
-static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req)
-{
- spin_lock(&fc->lock);
- if (fc->connected) {
- req->background = 1;
- fc->num_background++;
- if (fc->num_background == FUSE_MAX_BACKGROUND)
- fc->blocked = 1;
-
- queue_request(fc, req);
- spin_unlock(&fc->lock);
- } else {
- req->out.h.error = -ENOTCONN;
- request_end(fc, req);
- }
-}
-
-void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req)
-{
- req->isreply = 0;
- request_send_nowait(fc, req);
-}
-
-void request_send_background(struct fuse_conn *fc, struct fuse_req *req)
-{
- req->isreply = 1;
- request_send_nowait(fc, req);
-}
-
-/*
- * Lock the request. Up to the next unlock_request() there mustn't be
- * anything that could cause a page-fault. If the request was already
- * aborted bail out.
- */
-static int lock_request(struct fuse_conn *fc, struct fuse_req *req)
-{
- int err = 0;
- if (req) {
- spin_lock(&fc->lock);
- if (req->aborted)
- err = -ENOENT;
- else
- req->locked = 1;
- spin_unlock(&fc->lock);
- }
- return err;
-}
-
-/*
- * Unlock request. If it was aborted during being locked, the
- * requester thread is currently waiting for it to be unlocked, so
- * wake it up.
- */
-static void unlock_request(struct fuse_conn *fc, struct fuse_req *req)
-{
- if (req) {
- spin_lock(&fc->lock);
- req->locked = 0;
- if (req->aborted)
- wake_up(&req->waitq);
- spin_unlock(&fc->lock);
- }
-}
-
-struct fuse_copy_state {
- struct fuse_conn *fc;
- int write;
- struct fuse_req *req;
- const struct iovec *iov;
- unsigned long nr_segs;
- unsigned long seglen;
- unsigned long addr;
- struct page *pg;
- void *mapaddr;
- void *buf;
- unsigned len;
-};
-
-static void fuse_copy_init(struct fuse_copy_state *cs, struct fuse_conn *fc,
- int write, struct fuse_req *req,
- const struct iovec *iov, unsigned long nr_segs)
-{
- memset(cs, 0, sizeof(*cs));
- cs->fc = fc;
- cs->write = write;
- cs->req = req;
- cs->iov = iov;
- cs->nr_segs = nr_segs;
-}
-
-/* Unmap and put previous page of userspace buffer */
-static void fuse_copy_finish(struct fuse_copy_state *cs)
-{
- if (cs->mapaddr) {
- kunmap_atomic(cs->mapaddr, KM_USER0);
- if (cs->write) {
- flush_dcache_page(cs->pg);
- set_page_dirty_lock(cs->pg);
- }
- put_page(cs->pg);
- cs->mapaddr = NULL;
- }
-}
-
-/*
- * Get another pagefull of userspace buffer, and map it to kernel
- * address space, and lock request
- */
-static int fuse_copy_fill(struct fuse_copy_state *cs)
-{
- unsigned long offset;
- int err;
-#ifdef DCACHE_BUG
- struct vm_area_struct *vma;
-#endif
-
- unlock_request(cs->fc, cs->req);
- fuse_copy_finish(cs);
- if (!cs->seglen) {
- BUG_ON(!cs->nr_segs);
- cs->seglen = cs->iov[0].iov_len;
- cs->addr = (unsigned long) cs->iov[0].iov_base;
- cs->iov ++;
- cs->nr_segs --;
- }
- down_read(&current->mm->mmap_sem);
-#ifndef DCACHE_BUG
- err = get_user_pages(current, current->mm, cs->addr, 1, cs->write, 0,
- &cs->pg, NULL);
-#else
- err = get_user_pages(current, current->mm, cs->addr, 1, cs->write, 0,
- &cs->pg, &vma);
-#endif
- up_read(&current->mm->mmap_sem);
- if (err < 0)
- return err;
- BUG_ON(err != 1);
- offset = cs->addr % PAGE_SIZE;
- cs->mapaddr = kmap_atomic(cs->pg, KM_USER0);
-#ifdef DCACHE_BUG
- flush_cache_page(vma, cs->addr, page_to_pfn(cs->pg));
-#endif
- cs->buf = cs->mapaddr + offset;
- cs->len = min(PAGE_SIZE - offset, cs->seglen);
- cs->seglen -= cs->len;
- cs->addr += cs->len;
-
- return lock_request(cs->fc, cs->req);
-}
-
-/* Do as much copy to/from userspace buffer as we can */
-static int fuse_copy_do(struct fuse_copy_state *cs, void **val, unsigned *size)
-{
- unsigned ncpy = min(*size, cs->len);
- if (val) {
- if (cs->write)
- memcpy(cs->buf, *val, ncpy);
- else
- memcpy(*val, cs->buf, ncpy);
- *val += ncpy;
- }
- *size -= ncpy;
- cs->len -= ncpy;
- cs->buf += ncpy;
- return ncpy;
-}
-
-/*
- * Copy a page in the request to/from the userspace buffer. Must be
- * done atomically
- */
-static int fuse_copy_page(struct fuse_copy_state *cs, struct page *page,
- unsigned offset, unsigned count, int zeroing)
-{
- if (page && zeroing && count < PAGE_SIZE) {
- void *mapaddr = kmap_atomic(page, KM_USER1);
- memset(mapaddr, 0, PAGE_SIZE);
- kunmap_atomic(mapaddr, KM_USER1);
- }
- while (count) {
- int err;
- if (!cs->len && (err = fuse_copy_fill(cs)))
- return err;
- if (page) {
- void *mapaddr = kmap_atomic(page, KM_USER1);
- void *buf = mapaddr + offset;
- offset += fuse_copy_do(cs, &buf, &count);
- kunmap_atomic(mapaddr, KM_USER1);
- } else
- offset += fuse_copy_do(cs, NULL, &count);
- }
- if (page && !cs->write)
- flush_dcache_page(page);
- return 0;
-}
-
-/* Copy pages in the request to/from userspace buffer */
-static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes,
- int zeroing)
-{
- unsigned i;
- struct fuse_req *req = cs->req;
- unsigned offset = req->page_offset;
- unsigned count = min(nbytes, (unsigned) PAGE_SIZE - offset);
-
- for (i = 0; i < req->num_pages && (nbytes || zeroing); i++) {
- struct page *page = req->pages[i];
- int err = fuse_copy_page(cs, page, offset, count, zeroing);
- if (err)
- return err;
-
- nbytes -= count;
- count = min(nbytes, (unsigned) PAGE_SIZE);
- offset = 0;
- }
- return 0;
-}
-
-/* Copy a single argument in the request to/from userspace buffer */
-static int fuse_copy_one(struct fuse_copy_state *cs, void *val, unsigned size)
-{
- while (size) {
- int err;
- if (!cs->len && (err = fuse_copy_fill(cs)))
- return err;
- fuse_copy_do(cs, &val, &size);
- }
- return 0;
-}
-
-/* Copy request arguments to/from userspace buffer */
-static int fuse_copy_args(struct fuse_copy_state *cs, unsigned numargs,
- unsigned argpages, struct fuse_arg *args,
- int zeroing)
-{
- int err = 0;
- unsigned i;
-
- for (i = 0; !err && i < numargs; i++) {
- struct fuse_arg *arg = &args[i];
- if (i == numargs - 1 && argpages)
- err = fuse_copy_pages(cs, arg->size, zeroing);
- else
- err = fuse_copy_one(cs, arg->value, arg->size);
- }
- return err;
-}
-
-static int request_pending(struct fuse_conn *fc)
-{
- return !list_empty(&fc->pending) || !list_empty(&fc->interrupts);
-}
-
-/* Wait until a request is available on the pending list */
-static void request_wait(struct fuse_conn *fc)
-{
- DECLARE_WAITQUEUE(wait, current);
-
- add_wait_queue_exclusive(&fc->waitq, &wait);
- while (fc->connected && !request_pending(fc)) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (signal_pending(current))
- break;
-
- spin_unlock(&fc->lock);
- schedule();
- spin_lock(&fc->lock);
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&fc->waitq, &wait);
-}
-
-/*
- * Transfer an interrupt request to userspace
- *
- * Unlike other requests this is assembled on demand, without a need
- * to allocate a separate fuse_req structure.
- *
- * Called with fc->lock held, releases it
- */
-static int fuse_read_interrupt(struct fuse_conn *fc, struct fuse_req *req,
- const struct iovec *iov, unsigned long nr_segs)
-{
- struct fuse_copy_state cs;
- struct fuse_in_header ih;
- struct fuse_interrupt_in arg;
- unsigned reqsize = sizeof(ih) + sizeof(arg);
- int err;
-
- list_del_init(&req->intr_entry);
- req->intr_unique = fuse_get_unique(fc);
- memset(&ih, 0, sizeof(ih));
- memset(&arg, 0, sizeof(arg));
- ih.len = reqsize;
- ih.opcode = FUSE_INTERRUPT;
- ih.unique = req->intr_unique;
- arg.unique = req->in.h.unique;
-
- spin_unlock(&fc->lock);
- if (iov_length(iov, nr_segs) < reqsize)
- return -EINVAL;
-
- fuse_copy_init(&cs, fc, 1, NULL, iov, nr_segs);
- err = fuse_copy_one(&cs, &ih, sizeof(ih));
- if (!err)
- err = fuse_copy_one(&cs, &arg, sizeof(arg));
- fuse_copy_finish(&cs);
-
- return err ? err : reqsize;
-}
-
-/*
- * Read a single request into the userspace filesystem's buffer. This
- * function waits until a request is available, then removes it from
- * the pending list and copies request data to userspace buffer. If
- * no reply is needed (FORGET) or request has been aborted or there
- * was an error during the copying then it's finished by calling
- * request_end(). Otherwise add it to the processing list, and set
- * the 'sent' flag.
- */
-static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov,
- unsigned long nr_segs, loff_t *off)
-{
- int err;
- struct fuse_req *req;
- struct fuse_in *in;
- struct fuse_copy_state cs;
- unsigned reqsize;
- struct fuse_conn *fc = fuse_get_conn(file);
- if (!fc)
- return -EPERM;
-
- restart:
- spin_lock(&fc->lock);
- err = -EAGAIN;
- if ((file->f_flags & O_NONBLOCK) && fc->connected &&
- !request_pending(fc))
- goto err_unlock;
-
- request_wait(fc);
- err = -ENODEV;
- if (!fc->connected)
- goto err_unlock;
- err = -ERESTARTSYS;
- if (!request_pending(fc))
- goto err_unlock;
-
- if (!list_empty(&fc->interrupts)) {
- req = list_entry(fc->interrupts.next, struct fuse_req,
- intr_entry);
- return fuse_read_interrupt(fc, req, iov, nr_segs);
- }
-
- req = list_entry(fc->pending.next, struct fuse_req, list);
- req->state = FUSE_REQ_READING;
- list_move(&req->list, &fc->io);
-
- in = &req->in;
- reqsize = in->h.len;
- /* If request is too large, reply with an error and restart the read */
- if (iov_length(iov, nr_segs) < reqsize) {
- req->out.h.error = -EIO;
- /* SETXATTR is special, since it may contain too large data */
- if (in->h.opcode == FUSE_SETXATTR)
- req->out.h.error = -E2BIG;
- request_end(fc, req);
- goto restart;
- }
- spin_unlock(&fc->lock);
- fuse_copy_init(&cs, fc, 1, req, iov, nr_segs);
- err = fuse_copy_one(&cs, &in->h, sizeof(in->h));
- if (!err)
- err = fuse_copy_args(&cs, in->numargs, in->argpages,
- (struct fuse_arg *) in->args, 0);
- fuse_copy_finish(&cs);
- spin_lock(&fc->lock);
- req->locked = 0;
- if (!err && req->aborted)
- err = -ENOENT;
- if (err) {
- if (!req->aborted)
- req->out.h.error = -EIO;
- request_end(fc, req);
- return err;
- }
- if (!req->isreply)
- request_end(fc, req);
- else {
- req->state = FUSE_REQ_SENT;
- list_move_tail(&req->list, &fc->processing);
- if (req->interrupted)
- queue_interrupt(fc, req);
- spin_unlock(&fc->lock);
- }
- return reqsize;
-
- err_unlock:
- spin_unlock(&fc->lock);
- return err;
-}
-
-#ifndef KERNEL_2_6_19_PLUS
-static ssize_t fuse_dev_read(struct file *file, char __user *buf,
- size_t nbytes, loff_t *off)
-{
- struct iovec iov;
- iov.iov_len = nbytes;
- iov.iov_base = buf;
- return fuse_dev_readv(file, &iov, 1, off);
-}
-#else
-static ssize_t fuse_dev_read(struct kiocb *iocb, const struct iovec *iov,
- unsigned long nr_segs, loff_t pos)
-{
- return fuse_dev_readv(iocb->ki_filp, iov, nr_segs, &pos);
-}
-#endif
-
-/* Look up request on processing list by unique ID */
-static struct fuse_req *request_find(struct fuse_conn *fc, u64 unique)
-{
- struct list_head *entry;
-
- list_for_each(entry, &fc->processing) {
- struct fuse_req *req;
- req = list_entry(entry, struct fuse_req, list);
- if (req->in.h.unique == unique || req->intr_unique == unique)
- return req;
- }
- return NULL;
-}
-
-static int copy_out_args(struct fuse_copy_state *cs, struct fuse_out *out,
- unsigned nbytes)
-{
- unsigned reqsize = sizeof(struct fuse_out_header);
-
- if (out->h.error)
- return nbytes != reqsize ? -EINVAL : 0;
-
- reqsize += len_args(out->numargs, out->args);
-
- if (reqsize < nbytes || (reqsize > nbytes && !out->argvar))
- return -EINVAL;
- else if (reqsize > nbytes) {
- struct fuse_arg *lastarg = &out->args[out->numargs-1];
- unsigned diffsize = reqsize - nbytes;
- if (diffsize > lastarg->size)
- return -EINVAL;
- lastarg->size -= diffsize;
- }
- return fuse_copy_args(cs, out->numargs, out->argpages, out->args,
- out->page_zeroing);
-}
-
-/*
- * Write a single reply to a request. First the header is copied from
- * the write buffer. The request is then searched on the processing
- * list by the unique ID found in the header. If found, then remove
- * it from the list and copy the rest of the buffer to the request.
- * The request is finished by calling request_end()
- */
-static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov,
- unsigned long nr_segs, loff_t *off)
-{
- int err;
- unsigned nbytes = iov_length(iov, nr_segs);
- struct fuse_req *req;
- struct fuse_out_header oh;
- struct fuse_copy_state cs;
- struct fuse_conn *fc = fuse_get_conn(file);
- if (!fc)
- return -EPERM;
-
- fuse_copy_init(&cs, fc, 0, NULL, iov, nr_segs);
- if (nbytes < sizeof(struct fuse_out_header))
- return -EINVAL;
-
- err = fuse_copy_one(&cs, &oh, sizeof(oh));
- if (err)
- goto err_finish;
- err = -EINVAL;
- if (!oh.unique || oh.error <= -1000 || oh.error > 0 ||
- oh.len != nbytes)
- goto err_finish;
-
- spin_lock(&fc->lock);
- err = -ENOENT;
- if (!fc->connected)
- goto err_unlock;
-
- req = request_find(fc, oh.unique);
- if (!req)
- goto err_unlock;
-
- if (req->aborted) {
- spin_unlock(&fc->lock);
- fuse_copy_finish(&cs);
- spin_lock(&fc->lock);
- request_end(fc, req);
- return -ENOENT;
- }
- /* Is it an interrupt reply? */
- if (req->intr_unique == oh.unique) {
- err = -EINVAL;
- if (nbytes != sizeof(struct fuse_out_header))
- goto err_unlock;
-
- if (oh.error == -ENOSYS)
- fc->no_interrupt = 1;
- else if (oh.error == -EAGAIN)
- queue_interrupt(fc, req);
-
- spin_unlock(&fc->lock);
- fuse_copy_finish(&cs);
- return nbytes;
- }
-
- req->state = FUSE_REQ_WRITING;
- list_move(&req->list, &fc->io);
- req->out.h = oh;
- req->locked = 1;
- cs.req = req;
- spin_unlock(&fc->lock);
-
- err = copy_out_args(&cs, &req->out, nbytes);
- fuse_copy_finish(&cs);
-
- spin_lock(&fc->lock);
- req->locked = 0;
- if (!err) {
- if (req->aborted)
- err = -ENOENT;
- } else if (!req->aborted)
- req->out.h.error = -EIO;
- request_end(fc, req);
-
- return err ? err : nbytes;
-
- err_unlock:
- spin_unlock(&fc->lock);
- err_finish:
- fuse_copy_finish(&cs);
- return err;
-}
-
-#ifndef KERNEL_2_6_19_PLUS
-static ssize_t fuse_dev_write(struct file *file, const char __user *buf,
- size_t nbytes, loff_t *off)
-{
- struct iovec iov;
- iov.iov_len = nbytes;
- iov.iov_base = (char __user *) buf;
- return fuse_dev_writev(file, &iov, 1, off);
-}
-#else
-static ssize_t fuse_dev_write(struct kiocb *iocb, const struct iovec *iov,
- unsigned long nr_segs, loff_t pos)
-{
- return fuse_dev_writev(iocb->ki_filp, iov, nr_segs, &pos);
-}
-#endif
-
-static unsigned fuse_dev_poll(struct file *file, poll_table *wait)
-{
- unsigned mask = POLLOUT | POLLWRNORM;
- struct fuse_conn *fc = fuse_get_conn(file);
- if (!fc)
- return POLLERR;
-
- poll_wait(file, &fc->waitq, wait);
-
- spin_lock(&fc->lock);
- if (!fc->connected)
- mask = POLLERR;
- else if (request_pending(fc))
- mask |= POLLIN | POLLRDNORM;
- spin_unlock(&fc->lock);
-
- return mask;
-}
-
-/*
- * Abort all requests on the given list (pending or processing)
- *
- * This function releases and reacquires fc->lock
- */
-static void end_requests(struct fuse_conn *fc, struct list_head *head)
-{
- while (!list_empty(head)) {
- struct fuse_req *req;
- req = list_entry(head->next, struct fuse_req, list);
- req->out.h.error = -ECONNABORTED;
- request_end(fc, req);
- spin_lock(&fc->lock);
- }
-}
-
-/*
- * Abort requests under I/O
- *
- * The requests are set to aborted and finished, and the request
- * waiter is woken up. This will make request_wait_answer() wait
- * until the request is unlocked and then return.
- *
- * If the request is asynchronous, then the end function needs to be
- * called after waiting for the request to be unlocked (if it was
- * locked).
- */
-static void end_io_requests(struct fuse_conn *fc)
-{
- while (!list_empty(&fc->io)) {
- struct fuse_req *req =
- list_entry(fc->io.next, struct fuse_req, list);
- void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
-
- req->aborted = 1;
- req->out.h.error = -ECONNABORTED;
- req->state = FUSE_REQ_FINISHED;
- list_del_init(&req->list);
- wake_up(&req->waitq);
- if (end) {
- req->end = NULL;
- /* The end function will consume this reference */
- __fuse_get_request(req);
- spin_unlock(&fc->lock);
- wait_event(req->waitq, !req->locked);
- end(fc, req);
- spin_lock(&fc->lock);
- }
- }
-}
-
-/*
- * Abort all requests.
- *
- * Emergency exit in case of a malicious or accidental deadlock, or
- * just a hung filesystem.
- *
- * The same effect is usually achievable through killing the
- * filesystem daemon and all users of the filesystem. The exception
- * is the combination of an asynchronous request and the tricky
- * deadlock (see Documentation/filesystems/fuse.txt).
- *
- * During the aborting, progression of requests from the pending and
- * processing lists onto the io list, and progression of new requests
- * onto the pending list is prevented by req->connected being false.
- *
- * Progression of requests under I/O to the processing list is
- * prevented by the req->aborted flag being true for these requests.
- * For this reason requests on the io list must be aborted first.
- */
-void fuse_abort_conn(struct fuse_conn *fc)
-{
- spin_lock(&fc->lock);
- if (fc->connected) {
- fc->connected = 0;
- fc->blocked = 0;
- end_io_requests(fc);
- end_requests(fc, &fc->pending);
- end_requests(fc, &fc->processing);
- wake_up_all(&fc->waitq);
- wake_up_all(&fc->blocked_waitq);
- kill_fasync(&fc->fasync, SIGIO, POLL_IN);
- }
- spin_unlock(&fc->lock);
-}
-
-static int fuse_dev_release(struct inode *inode, struct file *file)
-{
- struct fuse_conn *fc = fuse_get_conn(file);
- if (fc) {
- spin_lock(&fc->lock);
- fc->connected = 0;
- end_requests(fc, &fc->pending);
- end_requests(fc, &fc->processing);
- spin_unlock(&fc->lock);
- fasync_helper(-1, file, 0, &fc->fasync);
- fuse_conn_put(fc);
- }
-
- return 0;
-}
-
-static int fuse_dev_fasync(int fd, struct file *file, int on)
-{
- struct fuse_conn *fc = fuse_get_conn(file);
- if (!fc)
- return -EPERM;
-
- /* No locking - fasync_helper does its own locking */
- return fasync_helper(fd, file, on, &fc->fasync);
-}
-
-struct file_operations fuse_dev_operations = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
-#ifndef KERNEL_2_6_19_PLUS
- .read = fuse_dev_read,
- .readv = fuse_dev_readv,
- .write = fuse_dev_write,
- .writev = fuse_dev_writev,
-#else
- .read = do_sync_read,
- .aio_read = fuse_dev_read,
- .write = do_sync_write,
- .aio_write = fuse_dev_write,
-#endif
- .poll = fuse_dev_poll,
- .release = fuse_dev_release,
- .fasync = fuse_dev_fasync,
-};
-
-static struct miscdevice fuse_miscdevice = {
- .minor = FUSE_MINOR,
- .name = "fuse",
- .fops = &fuse_dev_operations,
-};
-
-int __init fuse_dev_init(void)
-{
- int err = -ENOMEM;
-#ifdef KERNEL_2_6_23_PLUS
- fuse_req_cachep = kmem_cache_create("fuse_request",
- sizeof(struct fuse_req),
- 0, 0, NULL);
-#else
- fuse_req_cachep = kmem_cache_create("fuse_request",
- sizeof(struct fuse_req),
- 0, 0, NULL, NULL);
-#endif
- if (!fuse_req_cachep)
- goto out;
-
- err = misc_register(&fuse_miscdevice);
- if (err)
- goto out_cache_clean;
-
- return 0;
-
- out_cache_clean:
- kmem_cache_destroy(fuse_req_cachep);
- out:
- return err;
-}
-
-void fuse_dev_cleanup(void)
-{
- misc_deregister(&fuse_miscdevice);
- kmem_cache_destroy(fuse_req_cachep);
-}
diff --git a/kernel/dir.c b/kernel/dir.c
deleted file mode 100644
index b1fe4c6..0000000
--- a/kernel/dir.c
+++ /dev/null
@@ -1,1377 +0,0 @@
-/*
- FUSE: Filesystem in Userspace
- 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.
-*/
-
-#include "fuse_i.h"
-
-#include <linux/pagemap.h>
-#include <linux/file.h>
-#include <linux/gfp.h>
-#include <linux/sched.h>
-#include <linux/namei.h>
-
-#if BITS_PER_LONG >= 64
-static inline void fuse_dentry_settime(struct dentry *entry, u64 time)
-{
- entry->d_time = time;
-}
-
-static inline u64 fuse_dentry_time(struct dentry *entry)
-{
- return entry->d_time;
-}
-#else
-/*
- * On 32 bit archs store the high 32 bits of time in d_fsdata
- */
-static void fuse_dentry_settime(struct dentry *entry, u64 time)
-{
- entry->d_time = time;
- entry->d_fsdata = (void *) (unsigned long) (time >> 32);
-}
-
-static u64 fuse_dentry_time(struct dentry *entry)
-{
- return (u64) entry->d_time +
- ((u64) (unsigned long) entry->d_fsdata << 32);
-}
-#endif
-
-/*
- * FUSE caches dentries and attributes with separate timeout. The
- * time in jiffies until the dentry/attributes are valid is stored in
- * dentry->d_time and fuse_inode->i_time respectively.
- */
-
-/*
- * Calculate the time in jiffies until a dentry/attributes are valid
- */
-static u64 time_to_jiffies(unsigned long sec, unsigned long nsec)
-{
- if (sec || nsec) {
- struct timespec ts = {sec, nsec};
- return get_jiffies_64() + timespec_to_jiffies(&ts);
- } else
- return 0;
-}
-
-/*
- * Set dentry and possibly attribute timeouts from the lookup/mk*
- * replies
- */
-static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o)
-{
- fuse_dentry_settime(entry,
- time_to_jiffies(o->entry_valid, o->entry_valid_nsec));
- if (entry->d_inode)
- get_fuse_inode(entry->d_inode)->i_time =
- time_to_jiffies(o->attr_valid, o->attr_valid_nsec);
-}
-
-/*
- * Mark the attributes as stale, so that at the next call to
- * ->getattr() they will be fetched from userspace
- */
-void fuse_invalidate_attr(struct inode *inode)
-{
- get_fuse_inode(inode)->i_time = 0;
-}
-
-/*
- * Just mark the entry as stale, so that a next attempt to look it up
- * will result in a new lookup call to userspace
- *
- * This is called when a dentry is about to become negative and the
- * timeout is unknown (unlink, rmdir, rename and in some cases
- * lookup)
- */
-static void fuse_invalidate_entry_cache(struct dentry *entry)
-{
- fuse_dentry_settime(entry, 0);
-}
-
-/*
- * Same as fuse_invalidate_entry_cache(), but also try to remove the
- * dentry from the hash
- */
-static void fuse_invalidate_entry(struct dentry *entry)
-{
- d_invalidate(entry);
- fuse_invalidate_entry_cache(entry);
-}
-
-static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
- struct dentry *entry,
- struct fuse_entry_out *outarg)
-{
- req->in.h.opcode = FUSE_LOOKUP;
- req->in.h.nodeid = get_node_id(dir);
- req->in.numargs = 1;
- req->in.args[0].size = entry->d_name.len + 1;
- req->in.args[0].value = entry->d_name.name;
- req->out.numargs = 1;
- req->out.args[0].size = sizeof(struct fuse_entry_out);
- req->out.args[0].value = outarg;
-}
-
-/*
- * Check whether the dentry is still valid
- *
- * If the entry validity timeout has expired and the dentry is
- * positive, try to redo the lookup. If the lookup results in a
- * different inode, then let the VFS invalidate the dentry and redo
- * the lookup once more. If the lookup results in the same inode,
- * then refresh the attributes, timeouts and mark the dentry valid.
- */
-static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
-{
- struct inode *inode = entry->d_inode;
-
- if (inode && is_bad_inode(inode))
- return 0;
- else if (fuse_dentry_time(entry) < get_jiffies_64()) {
- int err;
- struct fuse_entry_out outarg;
- struct fuse_conn *fc;
- struct fuse_req *req;
- struct fuse_req *forget_req;
- struct dentry *parent;
-
- /* For negative dentries, always do a fresh lookup */
- if (!inode)
- return 0;
-
- fc = get_fuse_conn(inode);
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return 0;
-
- forget_req = fuse_get_req(fc);
- if (IS_ERR(forget_req)) {
- fuse_put_request(fc, req);
- return 0;
- }
-
- parent = dget_parent(entry);
- fuse_lookup_init(req, parent->d_inode, entry, &outarg);
- request_send(fc, req);
- dput(parent);
- err = req->out.h.error;
- fuse_put_request(fc, req);
- /* Zero nodeid is same as -ENOENT */
- if (!err && !outarg.nodeid)
- err = -ENOENT;
- if (!err) {
- struct fuse_inode *fi = get_fuse_inode(inode);
- if (outarg.nodeid != get_node_id(inode)) {
- fuse_send_forget(fc, forget_req,
- outarg.nodeid, 1);
- return 0;
- }
- spin_lock(&fc->lock);
- fi->nlookup ++;
- spin_unlock(&fc->lock);
- }
- fuse_put_request(fc, forget_req);
- if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
- return 0;
-
- fuse_change_attributes(inode, &outarg.attr);
- fuse_change_timeout(entry, &outarg);
- }
- return 1;
-}
-
-static int invalid_nodeid(u64 nodeid)
-{
- return !nodeid || nodeid == FUSE_ROOT_ID;
-}
-
-struct dentry_operations fuse_dentry_operations = {
- .d_revalidate = fuse_dentry_revalidate,
-};
-
-int fuse_valid_type(int m)
-{
- return S_ISREG(m) || S_ISDIR(m) || S_ISLNK(m) || S_ISCHR(m) ||
- S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m);
-}
-
-/*
- * Add a directory inode to a dentry, ensuring that no other dentry
- * refers to this inode. Called with fc->inst_mutex.
- */
-static struct dentry *fuse_d_add_directory(struct dentry *entry,
- struct inode *inode)
-{
- struct dentry *alias = d_find_alias(inode);
- if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) {
- /* This tries to shrink the subtree below alias */
- fuse_invalidate_entry(alias);
- dput(alias);
- if (!list_empty(&inode->i_dentry))
- return ERR_PTR(-EBUSY);
- } else
- dput(alias);
- return d_splice_alias(inode, entry);
-}
-
-static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
- struct nameidata *nd)
-{
- int err;
- struct fuse_entry_out outarg;
- struct inode *inode = NULL;
- struct dentry *newent;
- struct fuse_conn *fc = get_fuse_conn(dir);
- struct fuse_req *req;
- struct fuse_req *forget_req;
-
- if (entry->d_name.len > FUSE_NAME_MAX)
- return ERR_PTR(-ENAMETOOLONG);
-
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return ERR_PTR(PTR_ERR(req));
-
- forget_req = fuse_get_req(fc);
- if (IS_ERR(forget_req)) {
- fuse_put_request(fc, req);
- return ERR_PTR(PTR_ERR(forget_req));
- }
-
- fuse_lookup_init(req, dir, entry, &outarg);
- request_send(fc, req);
- err = req->out.h.error;
- fuse_put_request(fc, req);
- /* Zero nodeid is same as -ENOENT, but with valid timeout */
- if (!err && outarg.nodeid &&
- (invalid_nodeid(outarg.nodeid) ||
- !fuse_valid_type(outarg.attr.mode)))
- err = -EIO;
- if (!err && outarg.nodeid) {
- inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
- &outarg.attr);
- if (!inode) {
- fuse_send_forget(fc, forget_req, outarg.nodeid, 1);
- return ERR_PTR(-ENOMEM);
- }
- }
- fuse_put_request(fc, forget_req);
- if (err && err != -ENOENT)
- return ERR_PTR(err);
-
- if (inode && S_ISDIR(inode->i_mode)) {
- mutex_lock(&fc->inst_mutex);
- newent = fuse_d_add_directory(entry, inode);
- mutex_unlock(&fc->inst_mutex);
- if (IS_ERR(newent)) {
- iput(inode);
- return newent;
- }
- } else
- newent = d_splice_alias(inode, entry);
-
- entry = newent ? newent : entry;
- entry->d_op = &fuse_dentry_operations;
- if (!err)
- fuse_change_timeout(entry, &outarg);
- else
- fuse_invalidate_entry_cache(entry);
- return newent;
-}
-
-#ifdef HAVE_LOOKUP_INSTANTIATE_FILP
-/*
- * Synchronous release for the case when something goes wrong in CREATE_OPEN
- */
-static void fuse_sync_release(struct fuse_conn *fc, struct fuse_file *ff,
- u64 nodeid, int flags)
-{
- struct fuse_req *req;
-
- req = fuse_release_fill(ff, nodeid, flags, FUSE_RELEASE);
- req->force = 1;
- request_send(fc, req);
- fuse_put_request(fc, req);
-}
-
-/*
- * Atomic create+open operation
- *
- * If the filesystem doesn't support this, then fall back to separate
- * 'mknod' + 'open' requests.
- */
-static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
- struct nameidata *nd)
-{
- int err;
- struct inode *inode;
- struct fuse_conn *fc = get_fuse_conn(dir);
- struct fuse_req *req;
- struct fuse_req *forget_req;
- struct fuse_open_in inarg;
- struct fuse_open_out outopen;
- struct fuse_entry_out outentry;
- struct fuse_file *ff;
- struct file *file;
- int flags = nd->intent.open.flags - 1;
-
- if (fc->no_create)
- return -ENOSYS;
-
- forget_req = fuse_get_req(fc);
- if (IS_ERR(forget_req))
- return PTR_ERR(forget_req);
-
- req = fuse_get_req(fc);
- err = PTR_ERR(req);
- if (IS_ERR(req))
- goto out_put_forget_req;
-
- err = -ENOMEM;
- ff = fuse_file_alloc();
- if (!ff)
- goto out_put_request;
-
- flags &= ~O_NOCTTY;
- memset(&inarg, 0, sizeof(inarg));
- inarg.flags = flags;
- inarg.mode = mode;
- req->in.h.opcode = FUSE_CREATE;
- req->in.h.nodeid = get_node_id(dir);
- req->in.numargs = 2;
- req->in.args[0].size = sizeof(inarg);
- req->in.args[0].value = &inarg;
- req->in.args[1].size = entry->d_name.len + 1;
- req->in.args[1].value = entry->d_name.name;
- req->out.numargs = 2;
- req->out.args[0].size = sizeof(outentry);
- req->out.args[0].value = &outentry;
- req->out.args[1].size = sizeof(outopen);
- req->out.args[1].value = &outopen;
- request_send(fc, req);
- err = req->out.h.error;
- if (err) {
- if (err == -ENOSYS)
- fc->no_create = 1;
- goto out_free_ff;
- }
-
- err = -EIO;
- if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
- goto out_free_ff;
-
- fuse_put_request(fc, req);
- inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
- &outentry.attr);
- if (!inode) {
- flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
- ff->fh = outopen.fh;
- fuse_sync_release(fc, ff, outentry.nodeid, flags);
- fuse_send_forget(fc, forget_req, outentry.nodeid, 1);
- return -ENOMEM;
- }
- fuse_put_request(fc, forget_req);
- d_instantiate(entry, inode);
- fuse_invalidate_attr(dir);
- fuse_change_timeout(entry, &outentry);
- file = lookup_instantiate_filp(nd, entry, generic_file_open);
- if (IS_ERR(file)) {
- ff->fh = outopen.fh;
- fuse_sync_release(fc, ff, outentry.nodeid, flags);
- return PTR_ERR(file);
- }
- fuse_finish_open(inode, file, ff, &outopen);
- return 0;
-
- out_free_ff:
- fuse_file_free(ff);
- out_put_request:
- fuse_put_request(fc, req);
- out_put_forget_req:
- fuse_put_request(fc, forget_req);
- return err;
-}
-#endif
-
-/*
- * Code shared between mknod, mkdir, symlink and link
- */
-static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
- struct inode *dir, struct dentry *entry,
- int mode)
-{
- struct fuse_entry_out outarg;
- struct inode *inode;
- int err;
- struct fuse_req *forget_req;
-
- forget_req = fuse_get_req(fc);
- if (IS_ERR(forget_req)) {
- fuse_put_request(fc, req);
- return PTR_ERR(forget_req);
- }
-
- req->in.h.nodeid = get_node_id(dir);
- req->out.numargs = 1;
- req->out.args[0].size = sizeof(outarg);
- req->out.args[0].value = &outarg;
- request_send(fc, req);
- err = req->out.h.error;
- fuse_put_request(fc, req);
- if (err)
- goto out_put_forget_req;
-
- err = -EIO;
- if (invalid_nodeid(outarg.nodeid))
- goto out_put_forget_req;
-
- if ((outarg.attr.mode ^ mode) & S_IFMT)
- goto out_put_forget_req;
-
- inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
- &outarg.attr);
- if (!inode) {
- fuse_send_forget(fc, forget_req, outarg.nodeid, 1);
- return -ENOMEM;
- }
- fuse_put_request(fc, forget_req);
-
- if (S_ISDIR(inode->i_mode)) {
- struct dentry *alias;
- mutex_lock(&fc->inst_mutex);
- alias = d_find_alias(inode);
- if (alias) {
- /* New directory must have moved since mkdir */
- mutex_unlock(&fc->inst_mutex);
- dput(alias);
- iput(inode);
- return -EBUSY;
- }
- d_instantiate(entry, inode);
- mutex_unlock(&fc->inst_mutex);
- } else
- d_instantiate(entry, inode);
-
- fuse_change_timeout(entry, &outarg);
- fuse_invalidate_attr(dir);
- return 0;
-
- out_put_forget_req:
- fuse_put_request(fc, forget_req);
- return err;
-}
-
-static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
- dev_t rdev)
-{
- struct fuse_mknod_in inarg;
- struct fuse_conn *fc = get_fuse_conn(dir);
- struct fuse_req *req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- memset(&inarg, 0, sizeof(inarg));
- inarg.mode = mode;
- inarg.rdev = new_encode_dev(rdev);
- req->in.h.opcode = FUSE_MKNOD;
- req->in.numargs = 2;
- req->in.args[0].size = sizeof(inarg);
- req->in.args[0].value = &inarg;
- req->in.args[1].size = entry->d_name.len + 1;
- req->in.args[1].value = entry->d_name.name;
- return create_new_entry(fc, req, dir, entry, mode);
-}
-
-static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
- struct nameidata *nd)
-{
-#ifdef HAVE_LOOKUP_INSTANTIATE_FILP
- if (nd && (nd->flags & LOOKUP_OPEN)) {
- int err = fuse_create_open(dir, entry, mode, nd);
- if (err != -ENOSYS)
- return err;
- /* Fall back on mknod */
- }
-#endif
- return fuse_mknod(dir, entry, mode, 0);
-}
-
-static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
-{
- struct fuse_mkdir_in inarg;
- struct fuse_conn *fc = get_fuse_conn(dir);
- struct fuse_req *req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- memset(&inarg, 0, sizeof(inarg));
- inarg.mode = mode;
- req->in.h.opcode = FUSE_MKDIR;
- req->in.numargs = 2;
- req->in.args[0].size = sizeof(inarg);
- req->in.args[0].value = &inarg;
- req->in.args[1].size = entry->d_name.len + 1;
- req->in.args[1].value = entry->d_name.name;
- return create_new_entry(fc, req, dir, entry, S_IFDIR);
-}
-
-static int fuse_symlink(struct inode *dir, struct dentry *entry,
- const char *link)
-{
- struct fuse_conn *fc = get_fuse_conn(dir);
- unsigned len = strlen(link) + 1;
- struct fuse_req *req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- req->in.h.opcode = FUSE_SYMLINK;
- req->in.numargs = 2;
- req->in.args[0].size = entry->d_name.len + 1;
- req->in.args[0].value = entry->d_name.name;
- req->in.args[1].size = len;
- req->in.args[1].value = link;
- return create_new_entry(fc, req, dir, entry, S_IFLNK);
-}
-
-static int fuse_unlink(struct inode *dir, struct dentry *entry)
-{
- int err;
- struct fuse_conn *fc = get_fuse_conn(dir);
- struct fuse_req *req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- req->in.h.opcode = FUSE_UNLINK;
- req->in.h.nodeid = get_node_id(dir);
- req->in.numargs = 1;
- req->in.args[0].size = entry->d_name.len + 1;
- req->in.args[0].value = entry->d_name.name;
- request_send(fc, req);
- err = req->out.h.error;
- fuse_put_request(fc, req);
- if (!err) {
- struct inode *inode = entry->d_inode;
-
- /* Set nlink to zero so the inode can be cleared, if
- the inode does have more links this will be
- discovered at the next lookup/getattr */
- clear_nlink(inode);
- fuse_invalidate_attr(inode);
- fuse_invalidate_attr(dir);
- fuse_invalidate_entry_cache(entry);
- } else if (err == -EINTR)
- fuse_invalidate_entry(entry);
- return err;
-}
-
-static int fuse_rmdir(struct inode *dir, struct dentry *entry)
-{
- int err;
- struct fuse_conn *fc = get_fuse_conn(dir);
- struct fuse_req *req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- req->in.h.opcode = FUSE_RMDIR;
- req->in.h.nodeid = get_node_id(dir);
- req->in.numargs = 1;
- req->in.args[0].size = entry->d_name.len + 1;
- req->in.args[0].value = entry->d_name.name;
- request_send(fc, req);
- err = req->out.h.error;
- fuse_put_request(fc, req);
- if (!err) {
- clear_nlink(entry->d_inode);
- fuse_invalidate_attr(dir);
- fuse_invalidate_entry_cache(entry);
- } else if (err == -EINTR)
- fuse_invalidate_entry(entry);
- return err;
-}
-
-static int fuse_rename(struct inode *olddir, struct dentry *oldent,
- struct inode *newdir, struct dentry *newent)
-{
- int err;
- struct fuse_rename_in inarg;
- struct fuse_conn *fc = get_fuse_conn(olddir);
- struct fuse_req *req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- memset(&inarg, 0, sizeof(inarg));
- inarg.newdir = get_node_id(newdir);
- req->in.h.opcode = FUSE_RENAME;
- req->in.h.nodeid = get_node_id(olddir);
- req->in.numargs = 3;
- req->in.args[0].size = sizeof(inarg);
- req->in.args[0].value = &inarg;
- req->in.args[1].size = oldent->d_name.len + 1;
- req->in.args[1].value = oldent->d_name.name;
- req->in.args[2].size = newent->d_name.len + 1;
- req->in.args[2].value = newent->d_name.name;
- request_send(fc, req);
- err = req->out.h.error;
- fuse_put_request(fc, req);
- if (!err) {
- /* ctime changes */
- fuse_invalidate_attr(oldent->d_inode);
-
- fuse_invalidate_attr(olddir);
- if (olddir != newdir)
- fuse_invalidate_attr(newdir);
-
- /* newent will end up negative */
- if (newent->d_inode)
- fuse_invalidate_entry_cache(newent);
- } else if (err == -EINTR) {
- /* If request was interrupted, DEITY only knows if the
- rename actually took place. If the invalidation
- fails (e.g. some process has CWD under the renamed
- directory), then there can be inconsistency between
- the dcache and the real filesystem. Tough luck. */
- fuse_invalidate_entry(oldent);
- if (newent->d_inode)
- fuse_invalidate_entry(newent);
- }
-
- return err;
-}
-
-static int fuse_link(struct dentry *entry, struct inode *newdir,
- struct dentry *newent)
-{
- int err;
- struct fuse_link_in inarg;
- struct inode *inode = entry->d_inode;
- struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_req *req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- memset(&inarg, 0, sizeof(inarg));
- inarg.oldnodeid = get_node_id(inode);
- req->in.h.opcode = FUSE_LINK;
- req->in.numargs = 2;
- req->in.args[0].size = sizeof(inarg);
- req->in.args[0].value = &inarg;
- req->in.args[1].size = newent->d_name.len + 1;
- req->in.args[1].value = newent->d_name.name;
- err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
- /* Contrary to "normal" filesystems it can happen that link
- makes two "logical" inodes point to the same "physical"
- inode. We invalidate the attributes of the old one, so it
- will reflect changes in the backing inode (link count,
- etc.)
- */
- if (!err || err == -EINTR)
- fuse_invalidate_attr(inode);
- return err;
-}
-
-int fuse_do_getattr(struct inode *inode)
-{
- int err;
- struct fuse_attr_out arg;
- struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_req *req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- req->in.h.opcode = FUSE_GETATTR;
- req->in.h.nodeid = get_node_id(inode);
- req->out.numargs = 1;
- req->out.args[0].size = sizeof(arg);
- req->out.args[0].value = &arg;
- request_send(fc, req);
- err = req->out.h.error;
- fuse_put_request(fc, req);
- if (!err) {
- if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) {
-#ifndef KERNEL_2_6_12_PLUS
- if (get_node_id(inode) != FUSE_ROOT_ID)
- make_bad_inode(inode);
-#else
- make_bad_inode(inode);
-#endif
- err = -EIO;
- } else {
- struct fuse_inode *fi = get_fuse_inode(inode);
- fuse_change_attributes(inode, &arg.attr);
- fi->i_time = time_to_jiffies(arg.attr_valid,
- arg.attr_valid_nsec);
- }
- }
- return err;
-}
-
-/*
- * Calling into a user-controlled filesystem gives the filesystem
- * daemon ptrace-like capabilities over the requester process. This
- * means, that the filesystem daemon is able to record the exact
- * filesystem operations performed, and can also control the behavior
- * of the requester process in otherwise impossible ways. For example
- * it can delay the operation for arbitrary length of time allowing
- * DoS against the requester.
- *
- * For this reason only those processes can call into the filesystem,
- * for which the owner of the mount has ptrace privilege. This
- * excludes processes started by other users, suid or sgid processes.
- */
-int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
-{
- if (fc->flags & FUSE_ALLOW_OTHER)
- return 1;
-
- if (task->euid == fc->user_id &&
- task->suid == fc->user_id &&
- task->uid == fc->user_id &&
- task->egid == fc->group_id &&
- task->sgid == fc->group_id &&
- task->gid == fc->group_id)
- return 1;
-
- return 0;
-}
-
-/*
- * Check whether the inode attributes are still valid
- *
- * If the attribute validity timeout has expired, then fetch the fresh
- * attributes with a 'getattr' request
- *
- * I'm not sure why cached attributes are never returned for the root
- * inode, this is probably being too cautious.
- */
-static int fuse_revalidate(struct dentry *entry)
-{
- struct inode *inode = entry->d_inode;
- struct fuse_inode *fi = get_fuse_inode(inode);
- struct fuse_conn *fc = get_fuse_conn(inode);
-
- if (!fuse_allow_task(fc, current))
- return -EACCES;
- if (get_node_id(inode) != FUSE_ROOT_ID &&
- fi->i_time >= get_jiffies_64())
- return 0;
-
- return fuse_do_getattr(inode);
-}
-
-static int fuse_access(struct inode *inode, int mask)
-{
- struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_req *req;
- struct fuse_access_in inarg;
- int err;
-
- if (fc->no_access)
- return 0;
-
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- memset(&inarg, 0, sizeof(inarg));
- inarg.mask = mask;
- req->in.h.opcode = FUSE_ACCESS;
- req->in.h.nodeid = get_node_id(inode);
- req->in.numargs = 1;
- req->in.args[0].size = sizeof(inarg);
- req->in.args[0].value = &inarg;
- request_send(fc, req);
- err = req->out.h.error;
- fuse_put_request(fc, req);
- if (err == -ENOSYS) {
- fc->no_access = 1;
- err = 0;
- }
- return err;
-}
-
-/*
- * Check permission. The two basic access models of FUSE are:
- *
- * 1) Local access checking ('default_permissions' mount option) based
- * on file mode. This is the plain old disk filesystem permission
- * modell.
- *
- * 2) "Remote" access checking, where server is responsible for
- * checking permission in each inode operation. An exception to this
- * is if ->permission() was invoked from sys_access() in which case an
- * access request is sent. Execute permission is still checked
- * locally based on file mode.
- */
-static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
-{
- struct fuse_conn *fc = get_fuse_conn(inode);
-
- if (!fuse_allow_task(fc, current))
- return -EACCES;
- else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
-#ifdef KERNEL_2_6_10_PLUS
- int err = generic_permission(inode, mask, NULL);
-#else
- int err = vfs_permission(inode, mask);
-#endif
-
- /* If permission is denied, try to refresh file
- attributes. This is also needed, because the root
- node will at first have no permissions */
- if (err == -EACCES) {
- err = fuse_do_getattr(inode);
- if (!err)
-#ifdef KERNEL_2_6_10_PLUS
- err = generic_permission(inode, mask, NULL);
-#else
- err = vfs_permission(inode, mask);
-#endif
- }
-
- /* Note: the opposite of the above test does not
- exist. So if permissions are revoked this won't be
- noticed immediately, only after the attribute
- timeout has expired */
-
- return err;
- } else {
- int mode = inode->i_mode;
-#ifndef KERNEL_2_6_11_PLUS
- if ((mask & MAY_WRITE) && IS_RDONLY(inode) &&
- (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
- return -EROFS;
-#endif
- if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
- return -EACCES;
-
-#ifndef LOOKUP_CHDIR
-#define LOOKUP_CHDIR 0
-#endif
- if (nd && (nd->flags & (LOOKUP_ACCESS | LOOKUP_CHDIR)))
- return fuse_access(inode, mask);
- return 0;
- }
-}
-
-static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
- void *dstbuf, filldir_t filldir)
-{
- while (nbytes >= FUSE_NAME_OFFSET) {
- struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
- size_t reclen = FUSE_DIRENT_SIZE(dirent);
- int over;
- if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
- return -EIO;
- if (reclen > nbytes)
- break;
-
- over = filldir(dstbuf, dirent->name, dirent->namelen,
- file->f_pos, dirent->ino, dirent->type);
- if (over)
- break;
-
- buf += reclen;
- nbytes -= reclen;
- file->f_pos = dirent->off;
- }
-
- return 0;
-}
-
-static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
-{
- int err;
- size_t nbytes;
- struct page *page;
- struct inode *inode = file->f_dentry->d_inode;
- struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_req *req;
-
- if (is_bad_inode(inode))
- return -EIO;
-
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- page = alloc_page(GFP_KERNEL);
- if (!page) {
- fuse_put_request(fc, req);
- return -ENOMEM;
- }
- req->num_pages = 1;
- req->pages[0] = page;
- fuse_read_fill(req, file, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR);
- request_send(fc, req);
- nbytes = req->out.args[0].size;
- err = req->out.h.error;
- fuse_put_request(fc, req);
- if (!err)
- err = parse_dirfile(page_address(page), nbytes, file, dstbuf,
- filldir);
-
- __free_page(page);
- fuse_invalidate_attr(inode); /* atime changed */
- return err;
-}
-
-static char *read_link(struct dentry *dentry)
-{
- struct inode *inode = dentry->d_inode;
- struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_req *req = fuse_get_req(fc);
- char *link;
-
- if (IS_ERR(req))
- return ERR_PTR(PTR_ERR(req));
-
- link = (char *) __get_free_page(GFP_KERNEL);
- if (!link) {
- link = ERR_PTR(-ENOMEM);
- goto out;
- }
- req->in.h.opcode = FUSE_READLINK;
- req->in.h.nodeid = get_node_id(inode);
- req->out.argvar = 1;
- req->out.numargs = 1;
- req->out.args[0].size = PAGE_SIZE - 1;
- req->out.args[0].value = link;
- request_send(fc, req);
- if (req->out.h.error) {
- free_page((unsigned long) link);
- link = ERR_PTR(req->out.h.error);
- } else
- link[req->out.args[0].size] = '\0';
- out:
- fuse_put_request(fc, req);
- fuse_invalidate_attr(inode); /* atime changed */
- return link;
-}
-
-static void free_link(char *link)
-{
- if (!IS_ERR(link))
- free_page((unsigned long) link);
-}
-
-#ifdef KERNEL_2_6_13_PLUS
-static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
-{
- nd_set_link(nd, read_link(dentry));
- return NULL;
-}
-
-static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
-{
- free_link(nd_get_link(nd));
-}
-#else
-static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
-{
- nd_set_link(nd, read_link(dentry));
- return 0;
-}
-
-static void fuse_put_link(struct dentry *dentry, struct nameidata *nd)
-{
- free_link(nd_get_link(nd));
-}
-#endif
-
-static int fuse_dir_open(struct inode *inode, struct file *file)
-{
- return fuse_open_common(inode, file, 1);
-}
-
-static int fuse_dir_release(struct inode *inode, struct file *file)
-{
- return fuse_release_common(inode, file, 1);
-}
-
-static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
-{
- /* nfsd can call this with no file */
- return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
-}
-
-static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
-{
- unsigned ivalid = iattr->ia_valid;
-
- if (ivalid & ATTR_MODE)
- arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode;
- if (ivalid & ATTR_UID)
- arg->valid |= FATTR_UID, arg->uid = iattr->ia_uid;
- if (ivalid & ATTR_GID)
- arg->valid |= FATTR_GID, arg->gid = iattr->ia_gid;
- if (ivalid & ATTR_SIZE)
- arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size;
- /* You can only _set_ these together (they may change by themselves) */
- if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
- arg->valid |= FATTR_ATIME | FATTR_MTIME;
- arg->atime = iattr->ia_atime.tv_sec;
- arg->mtime = iattr->ia_mtime.tv_sec;
- }
-#ifdef ATTR_FILE
- if (ivalid & ATTR_FILE) {
- struct fuse_file *ff = iattr->ia_file->private_data;
- arg->valid |= FATTR_FH;
- arg->fh = ff->fh;
- }
-#endif
-}
-
-static void fuse_vmtruncate(struct inode *inode, loff_t offset)
-{
- struct fuse_conn *fc = get_fuse_conn(inode);
- int need_trunc;
-
- spin_lock(&fc->lock);
- need_trunc = inode->i_size > offset;
- i_size_write(inode, offset);
- spin_unlock(&fc->lock);
-
- if (need_trunc) {
- struct address_space *mapping = inode->i_mapping;
- unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
- truncate_inode_pages(mapping, offset);
- }
-}
-
-/*
- * Set attributes, and at the same time refresh them.
- *
- * Truncation is slightly complicated, because the 'truncate' request
- * may fail, in which case we don't want to touch the mapping.
- * vmtruncate() doesn't allow for this case, so do the rlimit checking
- * and the actual truncation by hand.
- */
-static int fuse_setattr(struct dentry *entry, struct iattr *attr)
-{
- struct inode *inode = entry->d_inode;
- struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_inode *fi = get_fuse_inode(inode);
- struct fuse_req *req;
- struct fuse_setattr_in inarg;
- struct fuse_attr_out outarg;
- int err;
- int is_truncate = 0;
-
- if (!fuse_allow_task(fc, current))
- return -EACCES;
-
- if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
- err = inode_change_ok(inode, attr);
- if (err)
- return err;
- }
-
- if (attr->ia_valid & ATTR_SIZE) {
- unsigned long limit;
- is_truncate = 1;
- if (IS_SWAPFILE(inode))
- return -ETXTBSY;
-#ifdef KERNEL_2_6_10_PLUS
- limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
-#else
- limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
-#endif
- if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
- send_sig(SIGXFSZ, current, 0);
- return -EFBIG;
- }
- }
-
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- memset(&inarg, 0, sizeof(inarg));
- iattr_to_fattr(attr, &inarg);
- /* Defend against future expansion of ATTR_FILE use */
- if (S_ISDIR(inode->i_mode))
- inarg.valid &= ~FATTR_FH;
- req->in.h.opcode = FUSE_SETATTR;
- req->in.h.nodeid = get_node_id(inode);
- req->in.numargs = 1;
- req->in.args[0].size = sizeof(inarg);
- req->in.args[0].value = &inarg;
- req->out.numargs = 1;
- req->out.args[0].size = sizeof(outarg);
- req->out.args[0].value = &outarg;
- request_send(fc, req);
- err = req->out.h.error;
- fuse_put_request(fc, req);
- if (!err) {
- if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
-#ifndef KERNEL_2_6_12_PLUS
- if (get_node_id(inode) != FUSE_ROOT_ID)
- make_bad_inode(inode);
-#else
- make_bad_inode(inode);
-#endif
- err = -EIO;
- } else {
- if (is_truncate)
- fuse_vmtruncate(inode, outarg.attr.size);
- fuse_change_attributes(inode, &outarg.attr);
- fi->i_time = time_to_jiffies(outarg.attr_valid,
- outarg.attr_valid_nsec);
- }
- } else if (err == -EINTR)
- fuse_invalidate_attr(inode);
-
- return err;
-}
-
-static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
- struct kstat *stat)
-{
- struct inode *inode = entry->d_inode;
- int err = fuse_revalidate(entry);
- if (!err)
- /* FIXME: may want specialized function because of
- st_blksize on block devices on 2.6.19+ */
- generic_fillattr(inode, stat);
-
- return err;
-}
-
-static int fuse_setxattr(struct dentry *entry, const char *name,
- const void *value, size_t size, int flags)
-{
- struct inode *inode = entry->d_inode;
- struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_req *req;
- struct fuse_setxattr_in inarg;
- int err;
-
- if (fc->no_setxattr)
- return -EOPNOTSUPP;
-
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- memset(&inarg, 0, sizeof(inarg));
- inarg.size = size;
- inarg.flags = flags;
- req->in.h.opcode = FUSE_SETXATTR;
- req->in.h.nodeid = get_node_id(inode);
- req->in.numargs = 3;
- req->in.args[0].size = sizeof(inarg);
- req->in.args[0].value = &inarg;
- req->in.args[1].size = strlen(name) + 1;
- req->in.args[1].value = name;
- req->in.args[2].size = size;
- req->in.args[2].value = value;
- request_send(fc, req);
- err = req->out.h.error;
- fuse_put_request(fc, req);
- if (err == -ENOSYS) {
- fc->no_setxattr = 1;
- err = -EOPNOTSUPP;
- }
- return err;
-}
-
-static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
- void *value, size_t size)
-{
- struct inode *inode = entry->d_inode;
- struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_req *req;
- struct fuse_getxattr_in inarg;
- struct fuse_getxattr_out outarg;
- ssize_t ret;
-
- if (fc->no_getxattr)
- return -EOPNOTSUPP;
-
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- memset(&inarg, 0, sizeof(inarg));
- inarg.size = size;
- req->in.h.opcode = FUSE_GETXATTR;
- req->in.h.nodeid = get_node_id(inode);
- req->in.numargs = 2;
- req->in.args[0].size = sizeof(inarg);
- req->in.args[0].value = &inarg;
- req->in.args[1].size = strlen(name) + 1;
- req->in.args[1].value = name;
- /* This is really two different operations rolled into one */
- req->out.numargs = 1;
- if (size) {
- req->out.argvar = 1;
- req->out.args[0].size = size;
- req->out.args[0].value = value;
- } else {
- req->out.args[0].size = sizeof(outarg);
- req->out.args[0].value = &outarg;
- }
- request_send(fc, req);
- ret = req->out.h.error;
- if (!ret)
- ret = size ? req->out.args[0].size : outarg.size;
- else {
- if (ret == -ENOSYS) {
- fc->no_getxattr = 1;
- ret = -EOPNOTSUPP;
- }
- }
- fuse_put_request(fc, req);
- return ret;
-}
-
-static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
-{
- struct inode *inode = entry->d_inode;
- struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_req *req;
- struct fuse_getxattr_in inarg;
- struct fuse_getxattr_out outarg;
- ssize_t ret;
-
- if (!fuse_allow_task(fc, current))
- return -EACCES;
-
- if (fc->no_listxattr)
- return -EOPNOTSUPP;
-
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- memset(&inarg, 0, sizeof(inarg));
- inarg.size = size;
- req->in.h.opcode = FUSE_LISTXATTR;
- req->in.h.nodeid = get_node_id(inode);
- req->in.numargs = 1;
- req->in.args[0].size = sizeof(inarg);
- req->in.args[0].value = &inarg;
- /* This is really two different operations rolled into one */
- req->out.numargs = 1;
- if (size) {
- req->out.argvar = 1;
- req->out.args[0].size = size;
- req->out.args[0].value = list;
- } else {
- req->out.args[0].size = sizeof(outarg);
- req->out.args[0].value = &outarg;
- }
- request_send(fc, req);
- ret = req->out.h.error;
- if (!ret)
- ret = size ? req->out.args[0].size : outarg.size;
- else {
- if (ret == -ENOSYS) {
- fc->no_listxattr = 1;
- ret = -EOPNOTSUPP;
- }
- }
- fuse_put_request(fc, req);
- return ret;
-}
-
-static int fuse_removexattr(struct dentry *entry, const char *name)
-{
- struct inode *inode = entry->d_inode;
- struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_req *req;
- int err;
-
- if (fc->no_removexattr)
- return -EOPNOTSUPP;
-
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- req->in.h.opcode = FUSE_REMOVEXATTR;
- req->in.h.nodeid = get_node_id(inode);
- req->in.numargs = 1;
- req->in.args[0].size = strlen(name) + 1;
- req->in.args[0].value = name;
- request_send(fc, req);
- err = req->out.h.error;
- fuse_put_request(fc, req);
- if (err == -ENOSYS) {
- fc->no_removexattr = 1;
- err = -EOPNOTSUPP;
- }
- return err;
-}
-
-static struct inode_operations fuse_dir_inode_operations = {
- .lookup = fuse_lookup,
- .mkdir = fuse_mkdir,
- .symlink = fuse_symlink,
- .unlink = fuse_unlink,
- .rmdir = fuse_rmdir,
- .rename = fuse_rename,
- .link = fuse_link,
- .setattr = fuse_setattr,
- .create = fuse_create,
- .mknod = fuse_mknod,
- .permission = fuse_permission,
- .getattr = fuse_getattr,
- .setxattr = fuse_setxattr,
- .getxattr = fuse_getxattr,
- .listxattr = fuse_listxattr,
- .removexattr = fuse_removexattr,
-};
-
-static struct file_operations fuse_dir_operations = {
- .llseek = generic_file_llseek,
- .read = generic_read_dir,
- .readdir = fuse_readdir,
- .open = fuse_dir_open,
- .release = fuse_dir_release,
- .fsync = fuse_dir_fsync,
-};
-
-static struct inode_operations fuse_common_inode_operations = {
- .setattr = fuse_setattr,
- .permission = fuse_permission,
- .getattr = fuse_getattr,
- .setxattr = fuse_setxattr,
- .getxattr = fuse_getxattr,
- .listxattr = fuse_listxattr,
- .removexattr = fuse_removexattr,
-};
-
-static struct inode_operations fuse_symlink_inode_operations = {
- .setattr = fuse_setattr,
- .follow_link = fuse_follow_link,
- .put_link = fuse_put_link,
- .readlink = generic_readlink,
- .getattr = fuse_getattr,
- .setxattr = fuse_setxattr,
- .getxattr = fuse_getxattr,
- .listxattr = fuse_listxattr,
- .removexattr = fuse_removexattr,
-};
-
-void fuse_init_common(struct inode *inode)
-{
- inode->i_op = &fuse_common_inode_operations;
-}
-
-void fuse_init_dir(struct inode *inode)
-{
- inode->i_op = &fuse_dir_inode_operations;
- inode->i_fop = &fuse_dir_operations;
-}
-
-void fuse_init_symlink(struct inode *inode)
-{
- inode->i_op = &fuse_symlink_inode_operations;
-}
diff --git a/kernel/file.c b/kernel/file.c
deleted file mode 100644
index 16a2d02..0000000
--- a/kernel/file.c
+++ /dev/null
@@ -1,900 +0,0 @@
-/*
- FUSE: Filesystem in Userspace
- 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.
-*/
-
-#include "fuse_i.h"
-
-#include <linux/pagemap.h>
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-
-#ifndef KERNEL_2_6_11_PLUS
-static inline loff_t page_offset(struct page *page)
-{
- return ((loff_t)page->index) << PAGE_CACHE_SHIFT;
-}
-#endif
-static struct file_operations fuse_direct_io_file_operations;
-
-static int fuse_send_open(struct inode *inode, struct file *file, int isdir,
- struct fuse_open_out *outargp)
-{
- struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_open_in inarg;
- struct fuse_req *req;
- int err;
-
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- memset(&inarg, 0, sizeof(inarg));
- inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
- req->in.h.opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN;
- req->in.h.nodeid = get_node_id(inode);
- req->in.numargs = 1;
- req->in.args[0].size = sizeof(inarg);
- req->in.args[0].value = &inarg;
- req->out.numargs = 1;
- req->out.args[0].size = sizeof(*outargp);
- req->out.args[0].value = outargp;
- request_send(fc, req);
- err = req->out.h.error;
- fuse_put_request(fc, req);
-
- return err;
-}
-
-struct fuse_file *fuse_file_alloc(void)
-{
- struct fuse_file *ff;
- ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL);
- if (ff) {
- ff->reserved_req = fuse_request_alloc();
- if (!ff->reserved_req) {
- kfree(ff);
- ff = NULL;
- }
- }
- return ff;
-}
-
-void fuse_file_free(struct fuse_file *ff)
-{
- fuse_request_free(ff->reserved_req);
- kfree(ff);
-}
-
-void fuse_finish_open(struct inode *inode, struct file *file,
- struct fuse_file *ff, struct fuse_open_out *outarg)
-{
- if (outarg->open_flags & FOPEN_DIRECT_IO)
- file->f_op = &fuse_direct_io_file_operations;
- if (!(outarg->open_flags & FOPEN_KEEP_CACHE))
-#ifdef KERNEL_2_6_21_PLUS
- invalidate_mapping_pages(inode->i_mapping, 0, -1);
-#else
- invalidate_inode_pages(inode->i_mapping);
-#endif
- ff->fh = outarg->fh;
- file->private_data = ff;
-}
-
-int fuse_open_common(struct inode *inode, struct file *file, int isdir)
-{
- struct fuse_open_out outarg;
- struct fuse_file *ff;
- int err;
-
- /* VFS checks this, but only _after_ ->open() */
- if (file->f_flags & O_DIRECT)
- return -EINVAL;
-
- err = generic_file_open(inode, file);
- if (err)
- return err;
-
- /* If opening the root node, no lookup has been performed on
- it, so the attributes must be refreshed */
- if (get_node_id(inode) == FUSE_ROOT_ID) {
- err = fuse_do_getattr(inode);
- if (err)
- return err;
- }
-
- ff = fuse_file_alloc();
- if (!ff)
- return -ENOMEM;
-
- err = fuse_send_open(inode, file, isdir, &outarg);
- if (err)
- fuse_file_free(ff);
- else {
- if (isdir)
- outarg.open_flags &= ~FOPEN_DIRECT_IO;
- fuse_finish_open(inode, file, ff, &outarg);
- }
-
- return err;
-}
-
-struct fuse_req *fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags,
- int opcode)
-{
- struct fuse_req *req = ff->reserved_req;
- struct fuse_release_in *inarg = &req->misc.release_in;
-
- inarg->fh = ff->fh;
- inarg->flags = flags;
- req->in.h.opcode = opcode;
- req->in.h.nodeid = nodeid;
- req->in.numargs = 1;
- req->in.args[0].size = sizeof(struct fuse_release_in);
- req->in.args[0].value = inarg;
- kfree(ff);
-
- return req;
-}
-
-int fuse_release_common(struct inode *inode, struct file *file, int isdir)
-{
- struct fuse_file *ff = file->private_data;
- if (ff) {
- struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_req *req;
-
- req = fuse_release_fill(ff, get_node_id(inode), file->f_flags,
- isdir ? FUSE_RELEASEDIR : FUSE_RELEASE);
-
- /* Hold vfsmount and dentry until release is finished */
- req->vfsmount = mntget(file->f_vfsmnt);
- req->dentry = dget(file->f_dentry);
- request_send_background(fc, req);
- }
-
- /* Return value is ignored by VFS */
- return 0;
-}
-
-static int fuse_open(struct inode *inode, struct file *file)
-{
- return fuse_open_common(inode, file, 0);
-}
-
-static int fuse_release(struct inode *inode, struct file *file)
-{
- return fuse_release_common(inode, file, 0);
-}
-
-/*
- * Scramble the ID space with XTEA, so that the value of the files_struct
- * pointer is not exposed to userspace.
- */
-static u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id)
-{
- u32 *k = fc->scramble_key;
- u64 v = (unsigned long) id;
- u32 v0 = v;
- u32 v1 = v >> 32;
- u32 sum = 0;
- int i;
-
- for (i = 0; i < 32; i++) {
- v0 += ((v1 << 4 ^ v1 >> 5) + v1) ^ (sum + k[sum & 3]);
- sum += 0x9E3779B9;
- v1 += ((v0 << 4 ^ v0 >> 5) + v0) ^ (sum + k[sum>>11 & 3]);
- }
-
- return (u64) v0 + ((u64) v1 << 32);
-}
-
-#ifdef KERNEL_2_6_18_PLUS
-static int fuse_flush(struct file *file, fl_owner_t id)
-#else
-static int fuse_flush(struct file *file)
-#endif
-{
- struct inode *inode = file->f_dentry->d_inode;
- struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_file *ff = file->private_data;
- struct fuse_req *req;
- struct fuse_flush_in inarg;
- int err;
-
- if (is_bad_inode(inode))
- return -EIO;
-
- if (fc->no_flush)
- return 0;
-
- req = fuse_get_req_nofail(fc, file);
- memset(&inarg, 0, sizeof(inarg));
- inarg.fh = ff->fh;
-#ifdef KERNEL_2_6_18_PLUS
- inarg.lock_owner = fuse_lock_owner_id(fc, id);
-#else
- inarg.lock_owner = fuse_lock_owner_id(fc, NULL);
-#endif
- req->in.h.opcode = FUSE_FLUSH;
- req->in.h.nodeid = get_node_id(inode);
- req->in.numargs = 1;
- req->in.args[0].size = sizeof(inarg);
- req->in.args[0].value = &inarg;
- req->force = 1;
- request_send(fc, req);
- err = req->out.h.error;
- fuse_put_request(fc, req);
- if (err == -ENOSYS) {
- fc->no_flush = 1;
- err = 0;
- }
- return err;
-}
-
-int fuse_fsync_common(struct file *file, struct dentry *de, int datasync,
- int isdir)
-{
- struct inode *inode = de->d_inode;
- struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_file *ff = file->private_data;
- struct fuse_req *req;
- struct fuse_fsync_in inarg;
- int err;
-
- if (is_bad_inode(inode))
- return -EIO;
-
- if ((!isdir && fc->no_fsync) || (isdir && fc->no_fsyncdir))
- return 0;
-
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- memset(&inarg, 0, sizeof(inarg));
- inarg.fh = ff->fh;
- inarg.fsync_flags = datasync ? 1 : 0;
- req->in.h.opcode = isdir ? FUSE_FSYNCDIR : FUSE_FSYNC;
- req->in.h.nodeid = get_node_id(inode);
- req->in.numargs = 1;
- req->in.args[0].size = sizeof(inarg);
- req->in.args[0].value = &inarg;
- request_send(fc, req);
- err = req->out.h.error;
- fuse_put_request(fc, req);
- if (err == -ENOSYS) {
- if (isdir)
- fc->no_fsyncdir = 1;
- else
- fc->no_fsync = 1;
- err = 0;
- }
- return err;
-}
-
-static int fuse_fsync(struct file *file, struct dentry *de, int datasync)
-{
- return fuse_fsync_common(file, de, datasync, 0);
-}
-
-void fuse_read_fill(struct fuse_req *req, struct file *file,
- struct inode *inode, loff_t pos, size_t count, int opcode)
-{
- struct fuse_file *ff = file->private_data;
- struct fuse_read_in *inarg = &req->misc.read_in;
-
- inarg->fh = ff->fh;
- inarg->offset = pos;
- inarg->size = count;
- req->in.h.opcode = opcode;
- req->in.h.nodeid = get_node_id(inode);
- req->in.numargs = 1;
- req->in.args[0].size = sizeof(struct fuse_read_in);
- req->in.args[0].value = inarg;
- req->out.argpages = 1;
- req->out.argvar = 1;
- req->out.numargs = 1;
- req->out.args[0].size = count;
-}
-
-static size_t fuse_send_read(struct fuse_req *req, struct file *file,
- struct inode *inode, loff_t pos, size_t count)
-{
- struct fuse_conn *fc = get_fuse_conn(inode);
- fuse_read_fill(req, file, inode, pos, count, FUSE_READ);
- request_send(fc, req);
- return req->out.args[0].size;
-}
-
-static int fuse_readpage(struct file *file, struct page *page)
-{
- struct inode *inode = page->mapping->host;
- struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_req *req;
- int err;
-
- err = -EIO;
- if (is_bad_inode(inode))
- goto out;
-
- req = fuse_get_req(fc);
- err = PTR_ERR(req);
- if (IS_ERR(req))
- goto out;
-
- req->out.page_zeroing = 1;
- req->num_pages = 1;
- req->pages[0] = page;
- fuse_send_read(req, file, inode, page_offset(page), PAGE_CACHE_SIZE);
- err = req->out.h.error;
- fuse_put_request(fc, req);
- if (!err)
- SetPageUptodate(page);
- fuse_invalidate_attr(inode); /* atime changed */
- out:
- unlock_page(page);
- return err;
-}
-
-static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req)
-{
- int i;
-
- fuse_invalidate_attr(req->pages[0]->mapping->host); /* atime changed */
-
- for (i = 0; i < req->num_pages; i++) {
- struct page *page = req->pages[i];
- if (!req->out.h.error)
- SetPageUptodate(page);
- else
- SetPageError(page);
- unlock_page(page);
- }
- fuse_put_request(fc, req);
-}
-
-static void fuse_send_readpages(struct fuse_req *req, struct file *file,
- struct inode *inode)
-{
- struct fuse_conn *fc = get_fuse_conn(inode);
- loff_t pos = page_offset(req->pages[0]);
- size_t count = req->num_pages << PAGE_CACHE_SHIFT;
- req->out.page_zeroing = 1;
- fuse_read_fill(req, file, inode, pos, count, FUSE_READ);
- if (fc->async_read) {
- get_file(file);
- req->file = file;
- req->end = fuse_readpages_end;
- request_send_background(fc, req);
- } else {
- request_send(fc, req);
- fuse_readpages_end(fc, req);
- }
-}
-
-struct fuse_readpages_data {
- struct fuse_req *req;
- struct file *file;
- struct inode *inode;
-};
-
-static int fuse_readpages_fill(void *_data, struct page *page)
-{
- struct fuse_readpages_data *data = _data;
- struct fuse_req *req = data->req;
- struct inode *inode = data->inode;
- struct fuse_conn *fc = get_fuse_conn(inode);
- int err;
-
- if (req && req->num_pages &&
- (req->num_pages == FUSE_MAX_PAGES_PER_REQ ||
- (req->num_pages + 1) * PAGE_CACHE_SIZE > fc->max_read ||
- req->pages[req->num_pages - 1]->index + 1 != page->index)) {
- fuse_send_readpages(req, data->file, inode);
- req = NULL;
- }
- if (!req) {
- err = -EIO;
- if (is_bad_inode(inode))
- goto out_unlock_page;
-
- data->req = req = fuse_get_req(fc);
- err = PTR_ERR(req);
- if (IS_ERR(req))
- goto out_unlock_page;
- }
- req->pages[req->num_pages] = page;
- req->num_pages ++;
- return 0;
-
- out_unlock_page:
- unlock_page(page);
- return err;
-}
-
-static int fuse_readpages(struct file *file, struct address_space *mapping,
- struct list_head *pages, unsigned nr_pages)
-{
- struct inode *inode = mapping->host;
- struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_readpages_data data;
- int err;
-
- data.file = file;
- data.inode = inode;
- data.req = NULL;
-
- err = read_cache_pages(mapping, pages, fuse_readpages_fill, &data);
- if (!err && data.req) {
- if (data.req->num_pages)
- fuse_send_readpages(data.req, file, inode);
- else
- fuse_put_request(fc, data.req);
- }
- return err;
-}
-
-static size_t fuse_send_write(struct fuse_req *req, struct file *file,
- struct inode *inode, loff_t pos, size_t count)
-{
- struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_file *ff = file->private_data;
- struct fuse_write_in inarg;
- struct fuse_write_out outarg;
-
- memset(&inarg, 0, sizeof(struct fuse_write_in));
- inarg.fh = ff->fh;
- inarg.offset = pos;
- inarg.size = count;
- req->in.h.opcode = FUSE_WRITE;
- req->in.h.nodeid = get_node_id(inode);
- req->in.argpages = 1;
- req->in.numargs = 2;
- req->in.args[0].size = sizeof(struct fuse_write_in);
- req->in.args[0].value = &inarg;
- req->in.args[1].size = count;
- req->out.numargs = 1;
- req->out.args[0].size = sizeof(struct fuse_write_out);
- req->out.args[0].value = &outarg;
- request_send(fc, req);
- return outarg.size;
-}
-
-static int fuse_prepare_write(struct file *file, struct page *page,
- unsigned offset, unsigned to)
-{
- /* No op */
- return 0;
-}
-
-static int fuse_commit_write(struct file *file, struct page *page,
- unsigned offset, unsigned to)
-{
- int err;
- size_t nres;
- unsigned count = to - offset;
- struct inode *inode = page->mapping->host;
- struct fuse_conn *fc = get_fuse_conn(inode);
- loff_t pos = page_offset(page) + offset;
- struct fuse_req *req;
-
- if (is_bad_inode(inode))
- return -EIO;
-
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- req->num_pages = 1;
- req->pages[0] = page;
- req->page_offset = offset;
- nres = fuse_send_write(req, file, inode, pos, count);
- err = req->out.h.error;
- fuse_put_request(fc, req);
- if (!err && nres != count)
- err = -EIO;
- if (!err) {
- pos += count;
- spin_lock(&fc->lock);
- if (pos > inode->i_size)
- i_size_write(inode, pos);
- spin_unlock(&fc->lock);
-
- if (offset == 0 && to == PAGE_CACHE_SIZE)
- SetPageUptodate(page);
- }
- fuse_invalidate_attr(inode);
- return err;
-}
-
-static void fuse_release_user_pages(struct fuse_req *req, int write)
-{
- unsigned i;
-
- for (i = 0; i < req->num_pages; i++) {
- struct page *page = req->pages[i];
- if (write)
- set_page_dirty_lock(page);
- put_page(page);
- }
-}
-
-static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf,
- unsigned nbytes, int write)
-{
- unsigned long user_addr = (unsigned long) buf;
- unsigned offset = user_addr & ~PAGE_MASK;
- int npages;
-
- /* This doesn't work with nfsd */
- if (!current->mm)
- return -EPERM;
-
- nbytes = min(nbytes, (unsigned) FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT);
- npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
- npages = max(npages, 1);
- npages = min(npages, FUSE_MAX_PAGES_PER_REQ);
- down_read(&current->mm->mmap_sem);
- npages = get_user_pages(current, current->mm, user_addr, npages, write,
- 0, req->pages, NULL);
- up_read(&current->mm->mmap_sem);
- if (npages < 0)
- return npages;
-
- req->num_pages = npages;
- req->page_offset = offset;
- return 0;
-}
-
-static ssize_t fuse_direct_io(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos, int write)
-{
- struct inode *inode = file->f_dentry->d_inode;
- struct fuse_conn *fc = get_fuse_conn(inode);
- size_t nmax = write ? fc->max_write : fc->max_read;
- loff_t pos = *ppos;
- ssize_t res = 0;
- struct fuse_req *req;
-
- if (is_bad_inode(inode))
- return -EIO;
-
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- while (count) {
- size_t nres;
- size_t nbytes = min(count, nmax);
- int err = fuse_get_user_pages(req, buf, nbytes, !write);
- if (err) {
- res = err;
- break;
- }
- nbytes = (req->num_pages << PAGE_SHIFT) - req->page_offset;
- nbytes = min(count, nbytes);
- if (write)
- nres = fuse_send_write(req, file, inode, pos, nbytes);
- else
- nres = fuse_send_read(req, file, inode, pos, nbytes);
- fuse_release_user_pages(req, !write);
- if (req->out.h.error) {
- if (!res)
- res = req->out.h.error;
- break;
- } else if (nres > nbytes) {
- res = -EIO;
- break;
- }
- count -= nres;
- res += nres;
- pos += nres;
- buf += nres;
- if (nres != nbytes)
- break;
- if (count) {
- fuse_put_request(fc, req);
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- break;
- }
- }
- fuse_put_request(fc, req);
- if (res > 0) {
- if (write) {
- spin_lock(&fc->lock);
- if (pos > inode->i_size)
- i_size_write(inode, pos);
- spin_unlock(&fc->lock);
- }
- *ppos = pos;
- }
- fuse_invalidate_attr(inode);
-
- return res;
-}
-
-static ssize_t fuse_direct_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- return fuse_direct_io(file, buf, count, ppos, 0);
-}
-
-static ssize_t fuse_direct_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct inode *inode = file->f_dentry->d_inode;
- ssize_t res;
- /* Don't allow parallel writes to the same file */
- mutex_lock(&inode->i_mutex);
- res = generic_write_checks(file, ppos, &count, 0);
- if (!res)
- res = fuse_direct_io(file, buf, count, ppos, 1);
- mutex_unlock(&inode->i_mutex);
- return res;
-}
-
-static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma)
-{
- if ((vma->vm_flags & VM_SHARED)) {
- if ((vma->vm_flags & VM_WRITE))
- return -ENODEV;
- else
- vma->vm_flags &= ~VM_MAYWRITE;
- }
- return generic_file_mmap(file, vma);
-}
-
-static int fuse_set_page_dirty(struct page *page)
-{
- printk("fuse_set_page_dirty: should not happen\n");
- dump_stack();
- return 0;
-}
-
-static int convert_fuse_file_lock(const struct fuse_file_lock *ffl,
- struct file_lock *fl)
-{
- switch (ffl->type) {
- case F_UNLCK:
- break;
-
- case F_RDLCK:
- case F_WRLCK:
- if (ffl->start > OFFSET_MAX || ffl->end > OFFSET_MAX ||
- ffl->end < ffl->start)
- return -EIO;
-
- fl->fl_start = ffl->start;
- fl->fl_end = ffl->end;
- fl->fl_pid = ffl->pid;
- break;
-
- default:
- return -EIO;
- }
- fl->fl_type = ffl->type;
- return 0;
-}
-
-static void fuse_lk_fill(struct fuse_req *req, struct file *file,
- const struct file_lock *fl, int opcode, pid_t pid)
-{
- struct inode *inode = file->f_dentry->d_inode;
- struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_file *ff = file->private_data;
- struct fuse_lk_in *arg = &req->misc.lk_in;
-
- arg->fh = ff->fh;
- arg->owner = fuse_lock_owner_id(fc, fl->fl_owner);
- arg->lk.start = fl->fl_start;
- arg->lk.end = fl->fl_end;
- arg->lk.type = fl->fl_type;
- arg->lk.pid = pid;
- req->in.h.opcode = opcode;
- req->in.h.nodeid = get_node_id(inode);
- req->in.numargs = 1;
- req->in.args[0].size = sizeof(*arg);
- req->in.args[0].value = arg;
-}
-
-static int fuse_getlk(struct file *file, struct file_lock *fl)
-{
- struct inode *inode = file->f_dentry->d_inode;
- struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_req *req;
- struct fuse_lk_out outarg;
- int err;
-
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- fuse_lk_fill(req, file, fl, FUSE_GETLK, 0);
- req->out.numargs = 1;
- req->out.args[0].size = sizeof(outarg);
- req->out.args[0].value = &outarg;
- request_send(fc, req);
- err = req->out.h.error;
- fuse_put_request(fc, req);
- if (!err)
- err = convert_fuse_file_lock(&outarg.lk, fl);
-
- return err;
-}
-
-static int fuse_setlk(struct file *file, struct file_lock *fl)
-{
- struct inode *inode = file->f_dentry->d_inode;
- struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_req *req;
- int opcode = (fl->fl_flags & FL_SLEEP) ? FUSE_SETLKW : FUSE_SETLK;
- pid_t pid = fl->fl_type != F_UNLCK ? current->tgid : 0;
- int err;
-
-#ifdef KERNEL_2_6_18_PLUS
- /* Unlock on close is handled by the flush method */
- if (fl->fl_flags & FL_CLOSE)
- return 0;
-
- req = fuse_get_req(fc);
-#else
- /* If it's (possibly) unlock on close, don't fail the allocation */
- if (fl->fl_type == F_UNLCK && fl->fl_start == 0 &&
- fl->fl_end == OFFSET_MAX)
- req = fuse_get_req_nofail(fc, file);
- else {
- /* Hack: add dummy lock, otherwise unlock on close is
- optimized away */
- struct file_lock **flp;
- for (flp = &inode->i_flock;
- *flp && !((*flp)->fl_flags & FL_POSIX);
- flp = &(*flp)->fl_next);
- if (!*flp) {
- struct file_lock *dummy =
- kmalloc(sizeof(struct file_lock), GFP_KERNEL);
- if (!dummy)
- return -ENOLCK;
- locks_init_lock(dummy);
- dummy->fl_flags |= FL_POSIX;
- *flp = dummy;
- }
- req = fuse_get_req(fc);
- }
-#endif
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- fuse_lk_fill(req, file, fl, opcode, pid);
- request_send(fc, req);
- err = req->out.h.error;
- /* locking is restartable */
- if (err == -EINTR)
- err = -ERESTARTSYS;
- fuse_put_request(fc, req);
- return err;
-}
-
-static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl)
-{
- struct inode *inode = file->f_dentry->d_inode;
- struct fuse_conn *fc = get_fuse_conn(inode);
- int err;
-
- if (cmd == F_GETLK) {
- if (fc->no_lock) {
-#ifdef KERNEL_2_6_22_PLUS
- posix_test_lock(file, fl);
-#elif defined(KERNEL_2_6_17_PLUS)
- if (!posix_test_lock(file, fl, fl))
- fl->fl_type = F_UNLCK;
-#else
- struct file_lock *cfl = posix_test_lock(file, fl);
- if (!cfl)
- fl->fl_type = F_UNLCK;
- else
- *fl = *cfl;
-#endif
- err = 0;
- } else
- err = fuse_getlk(file, fl);
- } else {
- if (fc->no_lock)
- err = posix_lock_file_wait(file, fl);
- else
- err = fuse_setlk(file, fl);
- }
- return err;
-}
-
-static sector_t fuse_bmap(struct address_space *mapping, sector_t block)
-{
- struct inode *inode = mapping->host;
- struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_req *req;
- struct fuse_bmap_in inarg;
- struct fuse_bmap_out outarg;
- int err;
-
- if (!inode->i_sb->s_bdev || fc->no_bmap)
- return 0;
-
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return 0;
-
- memset(&inarg, 0, sizeof(inarg));
- inarg.block = block;
- inarg.blocksize = inode->i_sb->s_blocksize;
- req->in.h.opcode = FUSE_BMAP;
- req->in.h.nodeid = get_node_id(inode);
- req->in.numargs = 1;
- req->in.args[0].size = sizeof(inarg);
- req->in.args[0].value = &inarg;
- req->out.numargs = 1;
- req->out.args[0].size = sizeof(outarg);
- req->out.args[0].value = &outarg;
- request_send(fc, req);
- err = req->out.h.error;
- fuse_put_request(fc, req);
- if (err == -ENOSYS)
- fc->no_bmap = 1;
-
- return err ? 0 : outarg.block;
-}
-
-static struct file_operations fuse_file_operations = {
- .llseek = generic_file_llseek,
-#ifndef KERNEL_2_6_19_PLUS
- .read = generic_file_read,
- .write = generic_file_write,
-#else
- .read = do_sync_read,
- .aio_read = generic_file_aio_read,
- .write = do_sync_write,
- .aio_write = generic_file_aio_write,
-#endif
- .mmap = fuse_file_mmap,
- .open = fuse_open,
- .flush = fuse_flush,
- .release = fuse_release,
- .fsync = fuse_fsync,
- .lock = fuse_file_lock,
-#ifdef KERNEL_2_6_23_PLUS
- .splice_read = generic_file_splice_read,
-#else
- .sendfile = generic_file_sendfile,
-#endif
-};
-
-static struct file_operations fuse_direct_io_file_operations = {
- .llseek = generic_file_llseek,
- .read = fuse_direct_read,
- .write = fuse_direct_write,
- .open = fuse_open,
- .flush = fuse_flush,
- .release = fuse_release,
- .fsync = fuse_fsync,
- .lock = fuse_file_lock,
- /* no mmap and sendfile */
-};
-
-static struct address_space_operations fuse_file_aops = {
- .readpage = fuse_readpage,
- .prepare_write = fuse_prepare_write,
- .commit_write = fuse_commit_write,
- .readpages = fuse_readpages,
- .set_page_dirty = fuse_set_page_dirty,
- .bmap = fuse_bmap,
-};
-
-void fuse_init_file_inode(struct inode *inode)
-{
- inode->i_fop = &fuse_file_operations;
- inode->i_data.a_ops = &fuse_file_aops;
-}
diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h
deleted file mode 100644
index a43fc97..0000000
--- a/kernel/fuse_i.h
+++ /dev/null
@@ -1,654 +0,0 @@
-/*
- FUSE: Filesystem in Userspace
- 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.
-*/
-
-#ifdef FUSE_MAINLINE
-#include <linux/fuse.h>
-#else
-#include <linux/version.h>
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
-#error Kernel versions earlier than 2.6.9 are not supported
-#endif
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
-# define KERNEL_2_6_10_PLUS
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
-# define KERNEL_2_6_11_PLUS
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
-# define KERNEL_2_6_12_PLUS
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
-# define KERNEL_2_6_13_PLUS
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
-# define KERNEL_2_6_16_PLUS
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
-# define KERNEL_2_6_17_PLUS
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
-# define KERNEL_2_6_18_PLUS
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
-# define KERNEL_2_6_19_PLUS
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
-# define KERNEL_2_6_21_PLUS
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-# define KERNEL_2_6_22_PLUS
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
-# define KERNEL_2_6_23_PLUS
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
-# define KERNEL_2_6_24_PLUS
-#endif
-
-#if defined(__arm__) && LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
-#define DCACHE_BUG
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
-#define kmem_cache kmem_cache_s
-#endif
-
-#include "fuse_kernel.h"
-#include "config.h"
-#endif /* FUSE_MAINLINE */
-#include <linux/fs.h>
-#include <linux/mount.h>
-#include <linux/wait.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
-#include <linux/backing-dev.h>
-#ifdef HAVE_MUTEX_H
-#include <linux/mutex.h>
-#else
-#include <asm/semaphore.h>
-#define DEFINE_MUTEX(m) DECLARE_MUTEX(m)
-#define mutex_init(m) init_MUTEX(m)
-#define mutex_destroy(m) do { } while (0)
-#define mutex_lock(m) down(m)
-#define mutex_unlock(m) up(m)
-#define mutex semaphore
-#endif
-#ifndef HAVE_I_MUTEX
-#ifndef mutex_destroy
-/* Some RHEL kernels include a backported mutex.h, which lacks mutex_destroy */
-#define mutex_destroy(m) do { } while (0)
-#endif
-#define i_mutex i_sem /* Hack for struct inode */
-#endif
-#ifndef KERNEL_2_6_19_PLUS
-#define clear_nlink(inode) (inode)->i_nlink = 0
-#define inc_nlink(inode) (inode)->i_nlink++
-#endif
-#ifndef HAVE_CONFIG_BLOCK
-#define CONFIG_BLOCK
-#endif
-#ifndef FS_HAS_SUBTYPE
-#define FS_HAS_SUBTYPE 0
-#endif
-#ifndef FS_SAFE
-#define FS_SAFE 0
-#endif
-
-/** Max number of pages that can be used in a single read request */
-#define FUSE_MAX_PAGES_PER_REQ 32
-
-/** Maximum number of outstanding background requests */
-#define FUSE_MAX_BACKGROUND 10
-
-/** It could be as large as PATH_MAX, but would that have any uses? */
-#define FUSE_NAME_MAX 1024
-
-/** Number of dentries for each connection in the control filesystem */
-#define FUSE_CTL_NUM_DENTRIES 3
-
-/** If the FUSE_DEFAULT_PERMISSIONS flag is given, the filesystem
- module will check permissions based on the file mode. Otherwise no
- permission checking is done in the kernel */
-#define FUSE_DEFAULT_PERMISSIONS (1 << 0)
-
-/** If the FUSE_ALLOW_OTHER flag is given, then not only the user
- doing the mount will be allowed to access the filesystem */
-#define FUSE_ALLOW_OTHER (1 << 1)
-
-/** List of active connections */
-extern struct list_head fuse_conn_list;
-
-/** Global mutex protecting fuse_conn_list and the control filesystem */
-extern struct mutex fuse_mutex;
-
-/** FUSE inode */
-struct fuse_inode {
- /** Inode data */
- struct inode inode;
-
- /** Unique ID, which identifies the inode between userspace
- * and kernel */
- u64 nodeid;
-
- /** Number of lookups on this inode */
- u64 nlookup;
-
- /** The request used for sending the FORGET message */
- struct fuse_req *forget_req;
-
- /** Time in jiffies until the file attributes are valid */
- u64 i_time;
-};
-
-/** FUSE specific file data */
-struct fuse_file {
- /** Request reserved for flush and release */
- struct fuse_req *reserved_req;
-
- /** File handle used by userspace */
- u64 fh;
-};
-
-/** One input argument of a request */
-struct fuse_in_arg {
- unsigned size;
- const void *value;
-};
-
-/** The request input */
-struct fuse_in {
- /** The request header */
- struct fuse_in_header h;
-
- /** True if the data for the last argument is in req->pages */
- unsigned argpages:1;
-
- /** Number of arguments */
- unsigned numargs;
-
- /** Array of arguments */
- struct fuse_in_arg args[3];
-};
-
-/** One output argument of a request */
-struct fuse_arg {
- unsigned size;
- void *value;
-};
-
-/** The request output */
-struct fuse_out {
- /** Header returned from userspace */
- struct fuse_out_header h;
-
- /*
- * The following bitfields are not changed during the request
- * processing
- */
-
- /** Last argument is variable length (can be shorter than
- arg->size) */
- unsigned argvar:1;
-
- /** Last argument is a list of pages to copy data to */
- unsigned argpages:1;
-
- /** Zero partially or not copied pages */
- unsigned page_zeroing:1;
-
- /** Number or arguments */
- unsigned numargs;
-
- /** Array of arguments */
- struct fuse_arg args[3];
-};
-
-/** The request state */
-enum fuse_req_state {
- FUSE_REQ_INIT = 0,
- FUSE_REQ_PENDING,
- FUSE_REQ_READING,
- FUSE_REQ_SENT,
- FUSE_REQ_WRITING,
- FUSE_REQ_FINISHED
-};
-
-struct fuse_conn;
-
-/**
- * A request to the client
- */
-struct fuse_req {
- /** This can be on either pending processing or io lists in
- fuse_conn */
- struct list_head list;
-
- /** Entry on the interrupts list */
- struct list_head intr_entry;
-
- /** refcount */
- atomic_t count;
-
- /** Unique ID for the interrupt request */
- u64 intr_unique;
-
- /*
- * The following bitfields are either set once before the
- * request is queued or setting/clearing them is protected by
- * fuse_conn->lock
- */
-
- /** True if the request has reply */
- unsigned isreply:1;
-
- /** Force sending of the request even if interrupted */
- unsigned force:1;
-
- /** The request was aborted */
- unsigned aborted:1;
-
- /** Request is sent in the background */
- unsigned background:1;
-
- /** The request has been interrupted */
- unsigned interrupted:1;
-
- /** Data is being copied to/from the request */
- unsigned locked:1;
-
- /** Request is counted as "waiting" */
- unsigned waiting:1;
-
- /** State of the request */
- enum fuse_req_state state;
-
- /** The request input */
- struct fuse_in in;
-
- /** The request output */
- struct fuse_out out;
-
- /** Used to wake up the task waiting for completion of request*/
- wait_queue_head_t waitq;
-
- /** Data for asynchronous requests */
- union {
- struct fuse_forget_in forget_in;
- struct fuse_release_in release_in;
- struct fuse_init_in init_in;
- struct fuse_init_out init_out;
- struct fuse_read_in read_in;
- struct fuse_lk_in lk_in;
- } misc;
-
- /** page vector */
- struct page *pages[FUSE_MAX_PAGES_PER_REQ];
-
- /** number of pages in vector */
- unsigned num_pages;
-
- /** offset of data on first page */
- unsigned page_offset;
-
- /** File used in the request (or NULL) */
- struct file *file;
-
- /** vfsmount used in release */
- struct vfsmount *vfsmount;
-
- /** dentry used in release */
- struct dentry *dentry;
-
- /** Request completion callback */
- void (*end)(struct fuse_conn *, struct fuse_req *);
-
- /** Request is stolen from fuse_file->reserved_req */
- struct file *stolen_file;
-};
-
-/**
- * A Fuse connection.
- *
- * This structure is created, when the filesystem is mounted, and is
- * destroyed, when the client device is closed and the filesystem is
- * unmounted.
- */
-struct fuse_conn {
- /** Lock protecting accessess to members of this structure */
- spinlock_t lock;
-
- /** Mutex protecting against directory alias creation */
- struct mutex inst_mutex;
-
- /** Refcount */
- atomic_t count;
-
- /** The user id for this mount */
- uid_t user_id;
-
- /** The group id for this mount */
- gid_t group_id;
-
- /** The fuse mount flags for this mount */
- unsigned flags;
-
- /** Maximum read size */
- unsigned max_read;
-
- /** Maximum write size */
- unsigned max_write;
-
- /** Readers of the connection are waiting on this */
- wait_queue_head_t waitq;
-
- /** The list of pending requests */
- struct list_head pending;
-
- /** The list of requests being processed */
- struct list_head processing;
-
- /** The list of requests under I/O */
- struct list_head io;
-
- /** Number of requests currently in the background */
- unsigned num_background;
-
- /** Pending interrupts */
- struct list_head interrupts;
-
- /** Flag indicating if connection is blocked. This will be
- the case before the INIT reply is received, and if there
- are too many outstading backgrounds requests */
- int blocked;
-
- /** waitq for blocked connection */
- wait_queue_head_t blocked_waitq;
-
- /** waitq for reserved requests */
- wait_queue_head_t reserved_req_waitq;
-
- /** The next unique request id */
- u64 reqctr;
-
- /** Connection established, cleared on umount, connection
- abort and device release */
- unsigned connected;
-
- /** Connection failed (version mismatch). Cannot race with
- setting other bitfields since it is only set once in INIT
- reply, before any other request, and never cleared */
- unsigned conn_error : 1;
-
- /** Connection successful. Only set in INIT */
- unsigned conn_init : 1;
-
- /** Do readpages asynchronously? Only set in INIT */
- unsigned async_read : 1;
-
- /*
- * The following bitfields are only for optimization purposes
- * and hence races in setting them will not cause malfunction
- */
-
- /** Is fsync not implemented by fs? */
- unsigned no_fsync : 1;
-
- /** Is fsyncdir not implemented by fs? */
- unsigned no_fsyncdir : 1;
-
- /** Is flush not implemented by fs? */
- unsigned no_flush : 1;
-
- /** Is setxattr not implemented by fs? */
- unsigned no_setxattr : 1;
-
- /** Is getxattr not implemented by fs? */
- unsigned no_getxattr : 1;
-
- /** Is listxattr not implemented by fs? */
- unsigned no_listxattr : 1;
-
- /** Is removexattr not implemented by fs? */
- unsigned no_removexattr : 1;
-
- /** Are file locking primitives not implemented by fs? */
- unsigned no_lock : 1;
-
- /** Is access not implemented by fs? */
- unsigned no_access : 1;
-
- /** Is create not implemented by fs? */
- unsigned no_create : 1;
-
- /** Is interrupt not implemented by fs? */
- unsigned no_interrupt : 1;
-
- /** Is bmap not implemented by fs? */
- unsigned no_bmap : 1;
-
- /** The number of requests waiting for completion */
- atomic_t num_waiting;
-
- /** Negotiated minor version */
- unsigned minor;
-
- /** Backing dev info */
- struct backing_dev_info bdi;
-
- /** Entry on the fuse_conn_list */
- struct list_head entry;
-
- /** Unique ID */
- u64 id;
-
- /** Dentries in the control filesystem */
- struct dentry *ctl_dentry[FUSE_CTL_NUM_DENTRIES];
-
- /** number of dentries used in the above array */
- int ctl_ndents;
-
- /** O_ASYNC requests */
- struct fasync_struct *fasync;
-
- /** Key for lock owner ID scrambling */
- u32 scramble_key[4];
-
- /** Reserved request for the DESTROY message */
- struct fuse_req *destroy_req;
-};
-
-static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb)
-{
- return sb->s_fs_info;
-}
-
-static inline struct fuse_conn *get_fuse_conn(struct inode *inode)
-{
- return get_fuse_conn_super(inode->i_sb);
-}
-
-static inline struct fuse_inode *get_fuse_inode(struct inode *inode)
-{
- return container_of(inode, struct fuse_inode, inode);
-}
-
-static inline u64 get_node_id(struct inode *inode)
-{
- return get_fuse_inode(inode)->nodeid;
-}
-
-/** Device operations */
-extern struct file_operations fuse_dev_operations;
-
-/**
- * Get a filled in inode
- */
-struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
- int generation, struct fuse_attr *attr);
-
-/**
- * Send FORGET command
- */
-void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
- unsigned long nodeid, u64 nlookup);
-
-/**
- * Initialize READ or READDIR request
- */
-void fuse_read_fill(struct fuse_req *req, struct file *file,
- struct inode *inode, loff_t pos, size_t count, int opcode);
-
-/**
- * Send OPEN or OPENDIR request
- */
-int fuse_open_common(struct inode *inode, struct file *file, int isdir);
-
-struct fuse_file *fuse_file_alloc(void);
-void fuse_file_free(struct fuse_file *ff);
-void fuse_finish_open(struct inode *inode, struct file *file,
- struct fuse_file *ff, struct fuse_open_out *outarg);
-
-/** */
-struct fuse_req *fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags,
- int opcode);
-/**
- * Send RELEASE or RELEASEDIR request
- */
-int fuse_release_common(struct inode *inode, struct file *file, int isdir);
-
-/**
- * Send FSYNC or FSYNCDIR request
- */
-int fuse_fsync_common(struct file *file, struct dentry *de, int datasync,
- int isdir);
-
-/**
- * Initialize file operations on a regular file
- */
-void fuse_init_file_inode(struct inode *inode);
-
-/**
- * Initialize inode operations on regular files and special files
- */
-void fuse_init_common(struct inode *inode);
-
-/**
- * Initialize inode and file operations on a directory
- */
-void fuse_init_dir(struct inode *inode);
-
-/**
- * Initialize inode operations on a symlink
- */
-void fuse_init_symlink(struct inode *inode);
-
-/**
- * Change attributes of an inode
- */
-void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr);
-
-/**
- * Initialize the client device
- */
-int fuse_dev_init(void);
-
-/**
- * Cleanup the client device
- */
-void fuse_dev_cleanup(void);
-
-int fuse_ctl_init(void);
-void fuse_ctl_cleanup(void);
-
-/**
- * Allocate a request
- */
-struct fuse_req *fuse_request_alloc(void);
-
-/**
- * Free a request
- */
-void fuse_request_free(struct fuse_req *req);
-
-/**
- * Get a request, may fail with -ENOMEM
- */
-struct fuse_req *fuse_get_req(struct fuse_conn *fc);
-
-/**
- * Gets a requests for a file operation, always succeeds
- */
-struct fuse_req *fuse_get_req_nofail(struct fuse_conn *fc, struct file *file);
-
-/**
- * Decrement reference count of a request. If count goes to zero free
- * the request.
- */
-void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req);
-
-/**
- * Send a request (synchronous)
- */
-void request_send(struct fuse_conn *fc, struct fuse_req *req);
-
-/**
- * Send a request with no reply
- */
-void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req);
-
-/**
- * Send a request in the background
- */
-void request_send_background(struct fuse_conn *fc, struct fuse_req *req);
-
-/* Abort all requests */
-void fuse_abort_conn(struct fuse_conn *fc);
-
-/**
- * Get the attributes of a file
- */
-int fuse_do_getattr(struct inode *inode);
-
-/**
- * Invalidate inode attributes
- */
-void fuse_invalidate_attr(struct inode *inode);
-
-/**
- * Acquire reference to fuse_conn
- */
-struct fuse_conn *fuse_conn_get(struct fuse_conn *fc);
-
-/**
- * Release reference to fuse_conn
- */
-void fuse_conn_put(struct fuse_conn *fc);
-
-/**
- * Add connection to control filesystem
- */
-int fuse_ctl_add_conn(struct fuse_conn *fc);
-
-/**
- * Remove connection from control filesystem
- */
-void fuse_ctl_remove_conn(struct fuse_conn *fc);
-
-/**
- * Is file type valid?
- */
-int fuse_valid_type(int m);
-
-/**
- * Is task allowed to perform filesystem operation?
- */
-int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task);
-
-extern struct dentry_operations fuse_dentry_operations;
diff --git a/kernel/inode.c b/kernel/inode.c
deleted file mode 100644
index 0a5900e..0000000
--- a/kernel/inode.c
+++ /dev/null
@@ -1,1101 +0,0 @@
-/*
- FUSE: Filesystem in Userspace
- 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.
-*/
-
-#include "fuse_i.h"
-
-#include <linux/pagemap.h>
-#include <linux/slab.h>
-#include <linux/file.h>
-#include <linux/seq_file.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/parser.h>
-#include <linux/statfs.h>
-#include <linux/random.h>
-#include <linux/sched.h>
-
-MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
-MODULE_DESCRIPTION("Filesystem in Userspace");
-#ifdef MODULE_LICENSE
-MODULE_LICENSE("GPL");
-#endif
-
-static struct kmem_cache *fuse_inode_cachep;
-struct list_head fuse_conn_list;
-DEFINE_MUTEX(fuse_mutex);
-
-#define FUSE_SUPER_MAGIC 0x65735546
-
-#ifndef MAX_LFS_FILESIZE
-#define MAX_LFS_FILESIZE (((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1)
-#endif
-struct fuse_mount_data {
- int fd;
- unsigned rootmode;
- unsigned user_id;
- unsigned group_id;
- unsigned fd_present : 1;
- unsigned rootmode_present : 1;
- unsigned user_id_present : 1;
- unsigned group_id_present : 1;
- unsigned flags;
- unsigned max_read;
- unsigned blksize;
-};
-
-static struct inode *fuse_alloc_inode(struct super_block *sb)
-{
- struct inode *inode;
- struct fuse_inode *fi;
-
- inode = kmem_cache_alloc(fuse_inode_cachep, GFP_KERNEL);
- if (!inode)
- return NULL;
-
- fi = get_fuse_inode(inode);
- fi->i_time = 0;
- fi->nodeid = 0;
- fi->nlookup = 0;
- fi->forget_req = fuse_request_alloc();
- if (!fi->forget_req) {
- kmem_cache_free(fuse_inode_cachep, inode);
- return NULL;
- }
-
- return inode;
-}
-
-static void fuse_destroy_inode(struct inode *inode)
-{
- struct fuse_inode *fi = get_fuse_inode(inode);
- if (fi->forget_req)
- fuse_request_free(fi->forget_req);
-#ifndef KERNEL_2_6_18_PLUS
- if (inode->i_flock) {
- WARN_ON(inode->i_flock->fl_next);
- kfree(inode->i_flock);
- inode->i_flock = NULL;
- }
-#endif
- kmem_cache_free(fuse_inode_cachep, inode);
-}
-
-static void fuse_read_inode(struct inode *inode)
-{
- /* No op */
-}
-
-void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
- unsigned long nodeid, u64 nlookup)
-{
- struct fuse_forget_in *inarg = &req->misc.forget_in;
- inarg->nlookup = nlookup;
- req->in.h.opcode = FUSE_FORGET;
- req->in.h.nodeid = nodeid;
- req->in.numargs = 1;
- req->in.args[0].size = sizeof(struct fuse_forget_in);
- req->in.args[0].value = inarg;
- request_send_noreply(fc, req);
-}
-
-static void fuse_clear_inode(struct inode *inode)
-{
- if (inode->i_sb->s_flags & MS_ACTIVE) {
- struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_inode *fi = get_fuse_inode(inode);
- fuse_send_forget(fc, fi->forget_req, fi->nodeid, fi->nlookup);
- fi->forget_req = NULL;
- }
-}
-
-static int fuse_remount_fs(struct super_block *sb, int *flags, char *data)
-{
- if (*flags & MS_MANDLOCK)
- return -EINVAL;
-
- return 0;
-}
-
-void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
-{
- struct fuse_conn *fc = get_fuse_conn(inode);
- if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size)
-#ifdef KERNEL_2_6_21_PLUS
- invalidate_mapping_pages(inode->i_mapping, 0, -1);
-#else
- invalidate_inode_pages(inode->i_mapping);
-#endif
-
- inode->i_ino = attr->ino;
- inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777);
- inode->i_nlink = attr->nlink;
- inode->i_uid = attr->uid;
- inode->i_gid = attr->gid;
- spin_lock(&fc->lock);
- i_size_write(inode, attr->size);
- spin_unlock(&fc->lock);
-#ifdef HAVE_I_BLKSIZE
- inode->i_blksize = PAGE_CACHE_SIZE;
-#endif
- inode->i_blocks = attr->blocks;
- inode->i_atime.tv_sec = attr->atime;
- inode->i_atime.tv_nsec = attr->atimensec;
- inode->i_mtime.tv_sec = attr->mtime;
- inode->i_mtime.tv_nsec = attr->mtimensec;
- inode->i_ctime.tv_sec = attr->ctime;
- inode->i_ctime.tv_nsec = attr->ctimensec;
-}
-
-static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
-{
- inode->i_mode = attr->mode & S_IFMT;
- inode->i_size = attr->size;
- if (S_ISREG(inode->i_mode)) {
- fuse_init_common(inode);
- fuse_init_file_inode(inode);
- } else if (S_ISDIR(inode->i_mode))
- fuse_init_dir(inode);
- else if (S_ISLNK(inode->i_mode))
- fuse_init_symlink(inode);
- else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
- S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
- fuse_init_common(inode);
- init_special_inode(inode, inode->i_mode,
- new_decode_dev(attr->rdev));
- } else
- BUG();
-}
-
-static int fuse_inode_eq(struct inode *inode, void *_nodeidp)
-{
- unsigned long nodeid = *(unsigned long *) _nodeidp;
- if (get_node_id(inode) == nodeid)
- return 1;
- else
- return 0;
-}
-
-static int fuse_inode_set(struct inode *inode, void *_nodeidp)
-{
- unsigned long nodeid = *(unsigned long *) _nodeidp;
- get_fuse_inode(inode)->nodeid = nodeid;
- return 0;
-}
-
-struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
- int generation, struct fuse_attr *attr)
-{
- struct inode *inode;
- struct fuse_inode *fi;
- struct fuse_conn *fc = get_fuse_conn_super(sb);
-
- retry:
- inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid);
- if (!inode)
- return NULL;
-
- if ((inode->i_state & I_NEW)) {
- inode->i_flags |= S_NOATIME|S_NOCMTIME;
- inode->i_generation = generation;
- inode->i_data.backing_dev_info = &fc->bdi;
- fuse_init_inode(inode, attr);
- unlock_new_inode(inode);
- } else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
- /* Inode has changed type, any I/O on the old should fail */
- make_bad_inode(inode);
- iput(inode);
- goto retry;
- }
-
- fi = get_fuse_inode(inode);
- spin_lock(&fc->lock);
- fi->nlookup ++;
- spin_unlock(&fc->lock);
- fuse_change_attributes(inode, attr);
- return inode;
-}
-
-#ifdef UMOUNT_BEGIN_VFSMOUNT
-static void fuse_umount_begin(struct vfsmount *vfsmnt, int flags)
-{
- if (flags & MNT_FORCE)
- fuse_abort_conn(get_fuse_conn_super(vfsmnt->mnt_sb));
-}
-#else
-static void fuse_umount_begin(struct super_block *sb)
-{
- fuse_abort_conn(get_fuse_conn_super(sb));
-}
-#endif
-
-static void fuse_send_destroy(struct fuse_conn *fc)
-{
- struct fuse_req *req = fc->destroy_req;
- if (req && fc->conn_init) {
- fc->destroy_req = NULL;
- req->in.h.opcode = FUSE_DESTROY;
- req->force = 1;
- request_send(fc, req);
- fuse_put_request(fc, req);
- }
-}
-
-static void fuse_put_super(struct super_block *sb)
-{
- struct fuse_conn *fc = get_fuse_conn_super(sb);
-
- fuse_send_destroy(fc);
- spin_lock(&fc->lock);
- fc->connected = 0;
- fc->blocked = 0;
- spin_unlock(&fc->lock);
- /* Flush all readers on this fs */
- kill_fasync(&fc->fasync, SIGIO, POLL_IN);
- wake_up_all(&fc->waitq);
- wake_up_all(&fc->blocked_waitq);
- wake_up_all(&fc->reserved_req_waitq);
- mutex_lock(&fuse_mutex);
- list_del(&fc->entry);
- fuse_ctl_remove_conn(fc);
- mutex_unlock(&fuse_mutex);
- fuse_conn_put(fc);
-}
-
-static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr)
-{
- stbuf->f_type = FUSE_SUPER_MAGIC;
- stbuf->f_bsize = attr->bsize;
- stbuf->f_frsize = attr->frsize;
- stbuf->f_blocks = attr->blocks;
- stbuf->f_bfree = attr->bfree;
- stbuf->f_bavail = attr->bavail;
- stbuf->f_files = attr->files;
- stbuf->f_ffree = attr->ffree;
- stbuf->f_namelen = attr->namelen;
- /* fsid is left zero */
-}
-
-#ifdef KERNEL_2_6_18_PLUS
-static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf)
-#else
-static int fuse_statfs(struct super_block *sb, struct kstatfs *buf)
-#endif
-{
-#ifdef KERNEL_2_6_18_PLUS
- struct super_block *sb = dentry->d_sb;
-#endif
- struct fuse_conn *fc = get_fuse_conn_super(sb);
- struct fuse_req *req;
- struct fuse_statfs_out outarg;
- int err;
-
- if (!fuse_allow_task(fc, current)) {
- buf->f_type = FUSE_SUPER_MAGIC;
- return 0;
- }
-
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- memset(&outarg, 0, sizeof(outarg));
- req->in.numargs = 0;
- req->in.h.opcode = FUSE_STATFS;
-#ifdef KERNEL_2_6_18_PLUS
- req->in.h.nodeid = get_node_id(dentry->d_inode);
-#endif
- req->out.numargs = 1;
- req->out.args[0].size =
- fc->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(outarg);
- req->out.args[0].value = &outarg;
- request_send(fc, req);
- err = req->out.h.error;
- if (!err)
- convert_fuse_statfs(buf, &outarg.st);
- fuse_put_request(fc, req);
- return err;
-}
-
-enum {
- OPT_FD,
- OPT_ROOTMODE,
- OPT_USER_ID,
- OPT_GROUP_ID,
- OPT_DEFAULT_PERMISSIONS,
- OPT_ALLOW_OTHER,
- OPT_MAX_READ,
- OPT_BLKSIZE,
- OPT_ERR
-};
-
-static match_table_t tokens = {
- {OPT_FD, "fd=%u"},
- {OPT_ROOTMODE, "rootmode=%o"},
- {OPT_USER_ID, "user_id=%u"},
- {OPT_GROUP_ID, "group_id=%u"},
- {OPT_DEFAULT_PERMISSIONS, "default_permissions"},
- {OPT_ALLOW_OTHER, "allow_other"},
- {OPT_MAX_READ, "max_read=%u"},
- {OPT_BLKSIZE, "blksize=%u"},
- {OPT_ERR, NULL}
-};
-
-static int parse_fuse_opt(char *opt, struct fuse_mount_data *d, int is_bdev)
-{
- char *p;
- memset(d, 0, sizeof(struct fuse_mount_data));
- d->max_read = ~0;
- d->blksize = 512;
-
- /*
- * For unprivileged mounts use current uid/gid. Still allow
- * "user_id" and "group_id" options for compatibility, but
- * only if they match these values.
- */
- if (!capable(CAP_SYS_ADMIN)) {
- d->user_id = current->uid;
- d->user_id_present = 1;
- d->group_id = current->gid;
- d->group_id_present = 1;
-
- }
-
- while ((p = strsep(&opt, ",")) != NULL) {
- int token;
- int value;
- substring_t args[MAX_OPT_ARGS];
- if (!*p)
- continue;
-
- token = match_token(p, tokens, args);
- switch (token) {
- case OPT_FD:
- if (match_int(&args[0], &value))
- return 0;
- d->fd = value;
- d->fd_present = 1;
- break;
-
- case OPT_ROOTMODE:
- if (match_octal(&args[0], &value))
- return 0;
- if (!fuse_valid_type(value))
- return 0;
- d->rootmode = value;
- d->rootmode_present = 1;
- break;
-
- case OPT_USER_ID:
- if (match_int(&args[0], &value))
- return 0;
- if (d->user_id_present && d->user_id != value)
- return 0;
- d->user_id = value;
- d->user_id_present = 1;
- break;
-
- case OPT_GROUP_ID:
- if (match_int(&args[0], &value))
- return 0;
- if (d->group_id_present && d->group_id != value)
- return 0;
- d->group_id = value;
- d->group_id_present = 1;
- break;
-
- case OPT_DEFAULT_PERMISSIONS:
- d->flags |= FUSE_DEFAULT_PERMISSIONS;
- break;
-
- case OPT_ALLOW_OTHER:
- d->flags |= FUSE_ALLOW_OTHER;
- break;
-
- case OPT_MAX_READ:
- if (match_int(&args[0], &value))
- return 0;
- d->max_read = value;
- break;
-
- case OPT_BLKSIZE:
- if (!is_bdev || match_int(&args[0], &value))
- return 0;
- d->blksize = value;
- break;
-
- default:
- return 0;
- }
- }
-
- if (!d->fd_present || !d->rootmode_present ||
- !d->user_id_present || !d->group_id_present)
- return 0;
-
- return 1;
-}
-
-static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
-{
- struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb);
-
- seq_printf(m, ",user_id=%u", fc->user_id);
- seq_printf(m, ",group_id=%u", fc->group_id);
- if (fc->flags & FUSE_DEFAULT_PERMISSIONS)
- seq_puts(m, ",default_permissions");
- if (fc->flags & FUSE_ALLOW_OTHER)
- seq_puts(m, ",allow_other");
- if (fc->max_read != ~0)
- seq_printf(m, ",max_read=%u", fc->max_read);
- return 0;
-}
-
-#ifndef HAVE_KZALLOC
-static void *kzalloc(size_t size, int flags)
-{
- void *ret = kmalloc(size, flags);
- if (ret)
- memset(ret, 0, size);
- return ret;
-}
-#endif
-static struct fuse_conn *new_conn(void)
-{
- struct fuse_conn *fc;
-
- fc = kzalloc(sizeof(*fc), GFP_KERNEL);
- if (fc) {
- spin_lock_init(&fc->lock);
- mutex_init(&fc->inst_mutex);
- atomic_set(&fc->count, 1);
- init_waitqueue_head(&fc->waitq);
- init_waitqueue_head(&fc->blocked_waitq);
- init_waitqueue_head(&fc->reserved_req_waitq);
- INIT_LIST_HEAD(&fc->pending);
- INIT_LIST_HEAD(&fc->processing);
- INIT_LIST_HEAD(&fc->io);
- INIT_LIST_HEAD(&fc->interrupts);
- atomic_set(&fc->num_waiting, 0);
- fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
- fc->bdi.unplug_io_fn = default_unplug_io_fn;
- fc->reqctr = 0;
- fc->blocked = 1;
- get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
- }
- return fc;
-}
-
-void fuse_conn_put(struct fuse_conn *fc)
-{
- if (atomic_dec_and_test(&fc->count)) {
- if (fc->destroy_req)
- fuse_request_free(fc->destroy_req);
- mutex_destroy(&fc->inst_mutex);
- kfree(fc);
- }
-}
-
-struct fuse_conn *fuse_conn_get(struct fuse_conn *fc)
-{
- atomic_inc(&fc->count);
- return fc;
-}
-
-static struct inode *get_root_inode(struct super_block *sb, unsigned mode)
-{
- struct fuse_attr attr;
- memset(&attr, 0, sizeof(attr));
-
- attr.mode = mode;
- attr.ino = FUSE_ROOT_ID;
- attr.nlink = 1;
- return fuse_iget(sb, 1, 0, &attr);
-}
-#ifndef FUSE_MAINLINE
-#ifdef HAVE_EXPORTFS_H
-#include <linux/exportfs.h>
-#endif
-
-struct fuse_inode_handle
-{
- u64 nodeid;
- u32 generation;
-};
-
-static struct dentry *fuse_get_dentry(struct super_block *sb,
- struct fuse_inode_handle *handle)
-{
- struct inode *inode;
- struct dentry *entry;
-
- if (handle->nodeid == 0)
- return ERR_PTR(-ESTALE);
-
- inode = ilookup5(sb, handle->nodeid, fuse_inode_eq, &handle->nodeid);
- if (!inode)
- return ERR_PTR(-ESTALE);
- if (inode->i_generation != handle->generation) {
- iput(inode);
- return ERR_PTR(-ESTALE);
- }
-
- entry = d_alloc_anon(inode);
- if (!entry) {
- iput(inode);
- return ERR_PTR(-ENOMEM);
- }
- entry->d_op = &fuse_dentry_operations;
-
- return entry;
-}
-
-static int fuse_encode_fh(struct dentry *dentry, u32 *fh, int *max_len,
- int connectable)
-{
- struct inode *inode = dentry->d_inode;
- int len = *max_len;
- int type = 1;
- u64 nodeid;
- u32 generation;
-
- if (len < 3 || (connectable && len < 6))
- return 255;
-
- nodeid = get_fuse_inode(inode)->nodeid;
- generation = inode->i_generation;
-
- len = 3;
- fh[0] = (u32)(nodeid >> 32);
- fh[1] = (u32)(nodeid & 0xffffffff);
- fh[2] = generation;
-
- if (connectable && !S_ISDIR(inode->i_mode)) {
- struct inode *parent;
-
- spin_lock(&dentry->d_lock);
- parent = dentry->d_parent->d_inode;
- nodeid = get_fuse_inode(parent)->nodeid;
- generation = parent->i_generation;
-
- fh[3] = (u32)(nodeid >> 32);
- fh[4] = (u32)(nodeid & 0xffffffff);
- fh[5] = generation;
- spin_unlock(&dentry->d_lock);
-
- len = 6;
- type = 2;
- }
-
- *max_len = len;
- return type;
-}
-
-#ifdef KERNEL_2_6_24_PLUS
-static struct dentry *fuse_fh_to_dentry(struct super_block *sb,
- struct fid *fid, int fh_len, int fh_type)
-{
- struct fuse_inode_handle handle;
-
- if (fh_len < 3 || fh_type > 2)
- return NULL;
-
- handle.nodeid = (u64) fid->raw[0] << 32;
- handle.nodeid |= (u64) fid->raw[1];
- handle.generation = fid->raw[2];
- return fuse_get_dentry(sb, &handle);
-}
-
-static struct dentry *fuse_fh_to_parent(struct super_block *sb,
- struct fid *fid, int fh_len, int fh_type)
-{
- struct fuse_inode_handle parent;
-
- if (fh_type != 2 || fh_len < 6)
- return NULL;
-
- parent.nodeid = (u64) fid->raw[3] << 32;
- parent.nodeid |= (u64) fid->raw[4];
- parent.generation = fid->raw[5];
- return fuse_get_dentry(sb, &parent);
-}
-
-
-static const struct export_operations fuse_export_operations = {
- .fh_to_dentry = fuse_fh_to_dentry,
- .fh_to_parent = fuse_fh_to_parent,
- .encode_fh = fuse_encode_fh,
-};
-#else
-static struct dentry *fuse_get_dentry_old(struct super_block *sb, void *objp)
-{
- return fuse_get_dentry(sb, objp);
-}
-
-static struct export_operations fuse_export_operations;
-
-static struct dentry *fuse_decode_fh(struct super_block *sb, u32 *fh,
- int fh_len, int fileid_type,
- int (*acceptable)(void *context, struct dentry *de),
- void *context)
-{
- struct fuse_inode_handle handle;
- struct fuse_inode_handle parent;
-
- if (fh_len < 3 || fileid_type > 2)
- return NULL;
-
- if (fileid_type == 2) {
- if (fh_len < 6)
- return NULL;
-
- parent.nodeid = (u64) fh[3] << 32;
- parent.nodeid |= (u64) fh[4];
- parent.generation = fh[5];
- } else {
- parent.nodeid = 0;
- parent.generation = 0;
- }
-
- handle.nodeid = (u64) fh[0] << 32;
- handle.nodeid |= (u64) fh[1];
- handle.generation = fh[2];
-
- return fuse_export_operations.
- find_exported_dentry(sb, &handle, &parent, acceptable, context);
-}
-
-static struct export_operations fuse_export_operations = {
- .get_dentry = fuse_get_dentry_old,
- .encode_fh = fuse_encode_fh,
- .decode_fh = fuse_decode_fh,
-};
-#endif
-#endif
-
-static struct super_operations fuse_super_operations = {
- .alloc_inode = fuse_alloc_inode,
- .destroy_inode = fuse_destroy_inode,
- .read_inode = fuse_read_inode,
- .clear_inode = fuse_clear_inode,
- .drop_inode = generic_delete_inode,
- .remount_fs = fuse_remount_fs,
- .put_super = fuse_put_super,
- .umount_begin = fuse_umount_begin,
- .statfs = fuse_statfs,
- .show_options = fuse_show_options,
-};
-
-static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
-{
- struct fuse_init_out *arg = &req->misc.init_out;
-
- if (req->out.h.error || arg->major != FUSE_KERNEL_VERSION)
- fc->conn_error = 1;
- else {
- unsigned long ra_pages;
-
- if (arg->minor >= 6) {
- ra_pages = arg->max_readahead / PAGE_CACHE_SIZE;
- if (arg->flags & FUSE_ASYNC_READ)
- fc->async_read = 1;
- if (!(arg->flags & FUSE_POSIX_LOCKS))
- fc->no_lock = 1;
- } else {
- ra_pages = fc->max_read / PAGE_CACHE_SIZE;
- fc->no_lock = 1;
- }
-
- fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages);
- fc->minor = arg->minor;
- fc->max_write = arg->minor < 5 ? 4096 : arg->max_write;
- fc->conn_init = 1;
- }
- fuse_put_request(fc, req);
- fc->blocked = 0;
- wake_up_all(&fc->blocked_waitq);
-}
-
-static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
-{
- struct fuse_init_in *arg = &req->misc.init_in;
-
- arg->major = FUSE_KERNEL_VERSION;
- arg->minor = FUSE_KERNEL_MINOR_VERSION;
- arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE;
- arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS;
- req->in.h.opcode = FUSE_INIT;
- req->in.numargs = 1;
- req->in.args[0].size = sizeof(*arg);
- req->in.args[0].value = arg;
- req->out.numargs = 1;
- /* Variable length arguement used for backward compatibility
- with interface version < 7.5. Rest of init_out is zeroed
- by do_get_request(), so a short reply is not a problem */
- req->out.argvar = 1;
- req->out.args[0].size = sizeof(struct fuse_init_out);
- req->out.args[0].value = &req->misc.init_out;
- req->end = process_init_reply;
- request_send_background(fc, req);
-}
-
-static u64 conn_id(void)
-{
- static u64 ctr = 1;
- return ctr++;
-}
-
-static int fuse_fill_super(struct super_block *sb, void *data, int silent)
-{
- struct fuse_conn *fc;
- struct inode *root;
- struct fuse_mount_data d;
- struct file *file;
- struct dentry *root_dentry;
- struct fuse_req *init_req;
- int err;
- int is_bdev = sb->s_bdev != NULL;
-
- if (sb->s_flags & MS_MANDLOCK)
- return -EINVAL;
-
- if (!parse_fuse_opt((char *) data, &d, is_bdev))
- return -EINVAL;
-
- /* This is a privileged option */
- if ((d.flags & FUSE_ALLOW_OTHER) && !capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- if (is_bdev) {
-#ifdef CONFIG_BLOCK
- if (!sb_set_blocksize(sb, d.blksize))
- return -EINVAL;
-#endif
- } else {
- sb->s_blocksize = PAGE_CACHE_SIZE;
- sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
- }
- sb->s_magic = FUSE_SUPER_MAGIC;
- sb->s_op = &fuse_super_operations;
- sb->s_maxbytes = MAX_LFS_FILESIZE;
-#ifndef FUSE_MAINLINE
- sb->s_export_op = &fuse_export_operations;
-#endif
-
- file = fget(d.fd);
- if (!file)
- return -EINVAL;
-
- if (file->f_op != &fuse_dev_operations)
- return -EINVAL;
-
- fc = new_conn();
- if (!fc)
- return -ENOMEM;
-
- fc->flags = d.flags;
- fc->user_id = d.user_id;
- fc->group_id = d.group_id;
- fc->max_read = d.max_read;
-
- /* Used by get_root_inode() */
- sb->s_fs_info = fc;
-
- err = -ENOMEM;
- root = get_root_inode(sb, d.rootmode);
- if (!root)
- goto err;
-
- root_dentry = d_alloc_root(root);
- if (!root_dentry) {
- iput(root);
- goto err;
- }
-
- init_req = fuse_request_alloc();
- if (!init_req)
- goto err_put_root;
-
- if (is_bdev) {
- fc->destroy_req = fuse_request_alloc();
- if (!fc->destroy_req)
- goto err_put_root;
- }
-
- mutex_lock(&fuse_mutex);
- err = -EINVAL;
- if (file->private_data)
- goto err_unlock;
-
- fc->id = conn_id();
- err = fuse_ctl_add_conn(fc);
- if (err)
- goto err_unlock;
-
- list_add_tail(&fc->entry, &fuse_conn_list);
- sb->s_root = root_dentry;
- fc->connected = 1;
- file->private_data = fuse_conn_get(fc);
- mutex_unlock(&fuse_mutex);
- /*
- * atomic_dec_and_test() in fput() provides the necessary
- * memory barrier for file->private_data to be visible on all
- * CPUs after this
- */
- fput(file);
-
- fuse_send_init(fc, init_req);
-
- return 0;
-
- err_unlock:
- mutex_unlock(&fuse_mutex);
- fuse_request_free(init_req);
- err_put_root:
- dput(root_dentry);
- err:
- fput(file);
- fuse_conn_put(fc);
- return err;
-}
-
-#ifdef KERNEL_2_6_18_PLUS
-static int fuse_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *raw_data, struct vfsmount *mnt)
-{
- return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super, mnt);
-}
-#else
-static struct super_block *fuse_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *raw_data)
-{
- return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super);
-}
-#endif
-
-static struct file_system_type fuse_fs_type = {
- .owner = THIS_MODULE,
- .name = "fuse",
- .get_sb = fuse_get_sb,
- .kill_sb = kill_anon_super,
- .fs_flags = FS_HAS_SUBTYPE | FS_SAFE,
-};
-
-#ifdef CONFIG_BLOCK
-#ifdef KERNEL_2_6_18_PLUS
-static int fuse_get_sb_blk(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *raw_data, struct vfsmount *mnt)
-{
- return get_sb_bdev(fs_type, flags, dev_name, raw_data, fuse_fill_super,
- mnt);
-}
-#else
-static struct super_block *fuse_get_sb_blk(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *raw_data)
-{
- return get_sb_bdev(fs_type, flags, dev_name, raw_data,
- fuse_fill_super);
-}
-#endif
-
-static struct file_system_type fuseblk_fs_type = {
- .owner = THIS_MODULE,
- .name = "fuseblk",
- .get_sb = fuse_get_sb_blk,
- .kill_sb = kill_block_super,
- .fs_flags = FS_REQUIRES_DEV | FS_HAS_SUBTYPE,
-};
-
-static inline int register_fuseblk(void)
-{
- return register_filesystem(&fuseblk_fs_type);
-}
-
-static inline void unregister_fuseblk(void)
-{
- unregister_filesystem(&fuseblk_fs_type);
-}
-#else
-static inline int register_fuseblk(void)
-{
- return 0;
-}
-
-static inline void unregister_fuseblk(void)
-{
-}
-#endif
-
-#ifndef HAVE_FS_SUBSYS
-static decl_subsys(fs, NULL, NULL);
-#endif
-static decl_subsys(fuse, NULL, NULL);
-static decl_subsys(connections, NULL, NULL);
-
-#ifdef KERNEL_2_6_24_PLUS
-static void fuse_inode_init_once(struct kmem_cache *cachep, void *foo)
-#else
-static void fuse_inode_init_once(void *foo, struct kmem_cache *cachep,
- unsigned long flags)
-#endif
-{
- struct inode * inode = foo;
-
-#ifndef KERNEL_2_6_22_PLUS
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
-#endif
- inode_init_once(inode);
-}
-
-static int __init fuse_fs_init(void)
-{
- int err;
-
- err = register_filesystem(&fuse_fs_type);
- if (err)
- goto out;
-
- err = register_fuseblk();
- if (err)
- goto out_unreg;
-
-#ifdef KERNEL_2_6_23_PLUS
- fuse_inode_cachep = kmem_cache_create("fuse_inode",
- sizeof(struct fuse_inode),
- 0, SLAB_HWCACHE_ALIGN,
- fuse_inode_init_once);
-#else
- fuse_inode_cachep = kmem_cache_create("fuse_inode",
- sizeof(struct fuse_inode),
- 0, SLAB_HWCACHE_ALIGN,
- fuse_inode_init_once, NULL);
-#endif
-
- err = -ENOMEM;
- if (!fuse_inode_cachep)
- goto out_unreg2;
-
- return 0;
-
- out_unreg2:
- unregister_fuseblk();
- out_unreg:
- unregister_filesystem(&fuse_fs_type);
- out:
- return err;
-}
-
-static void fuse_fs_cleanup(void)
-{
- unregister_filesystem(&fuse_fs_type);
- unregister_fuseblk();
- kmem_cache_destroy(fuse_inode_cachep);
-}
-
-static int fuse_sysfs_init(void)
-{
- int err;
-
-#ifndef HAVE_FS_SUBSYS
- err = subsystem_register(&fs_subsys);
- if (err)
- return err;
-#endif
-#ifdef KERNEL_2_6_22_PLUS
- kobj_set_kset_s(&fuse_subsys, fs_subsys);
-#else
- kset_set_kset_s(&fuse_subsys, fs_subsys);
-#endif
- err = subsystem_register(&fuse_subsys);
- if (err)
- goto out_err;
-
-#ifdef KERNEL_2_6_22_PLUS
- kobj_set_kset_s(&connections_subsys, fuse_subsys);
-#else
- kset_set_kset_s(&connections_subsys, fuse_subsys);
-#endif
- err = subsystem_register(&connections_subsys);
- if (err)
- goto out_fuse_unregister;
-
- return 0;
-
- out_fuse_unregister:
- subsystem_unregister(&fuse_subsys);
- out_err:
-#ifndef HAVE_FS_SUBSYS
- subsystem_unregister(&fs_subsys);
-#endif
- return err;
-}
-
-static void fuse_sysfs_cleanup(void)
-{
- subsystem_unregister(&connections_subsys);
- subsystem_unregister(&fuse_subsys);
-#ifndef HAVE_FS_SUBSYS
- subsystem_unregister(&fs_subsys);
-#endif
-}
-
-static int __init fuse_init(void)
-{
- int res;
-
- printk("fuse init (API version %i.%i)\n",
- FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
-#ifndef FUSE_MAINLINE
- printk("fuse distribution version: %s\n", FUSE_VERSION);
-#endif
-
- INIT_LIST_HEAD(&fuse_conn_list);
- res = fuse_fs_init();
- if (res)
- goto err;
-
- res = fuse_dev_init();
- if (res)
- goto err_fs_cleanup;
-
- res = fuse_sysfs_init();
- if (res)
- goto err_dev_cleanup;
-
- res = fuse_ctl_init();
- if (res)
- goto err_sysfs_cleanup;
-
- return 0;
-
- err_sysfs_cleanup:
- fuse_sysfs_cleanup();
- err_dev_cleanup:
- fuse_dev_cleanup();
- err_fs_cleanup:
- fuse_fs_cleanup();
- err:
- return res;
-}
-
-static void __exit fuse_exit(void)
-{
- printk(KERN_DEBUG "fuse exit\n");
-
- fuse_ctl_cleanup();
- fuse_sysfs_cleanup();
- fuse_fs_cleanup();
- fuse_dev_cleanup();
-}
-
-module_init(fuse_init);
-module_exit(fuse_exit);
diff --git a/makeconf.sh b/makeconf.sh
index 179cd68..6678bdd 100755
--- a/makeconf.sh
+++ b/makeconf.sh
@@ -40,8 +40,6 @@ else
autoconf
)
fi
-echo Linking kernel header file...
-ln -sf ../kernel/fuse_kernel.h `dirname $0`/include
rm -f config.cache config.status
echo "To compile run './configure', and then 'make'."