aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog15
-rwxr-xr-xkernel/cleanup.sh16
-rw-r--r--kernel/dev.c275
-rw-r--r--kernel/dir.c137
-rw-r--r--kernel/file.c368
-rw-r--r--kernel/fuse_i.h63
-rw-r--r--kernel/inode.c150
-rw-r--r--kernel/linux/fuse.h6
-rw-r--r--kernel/util.c15
9 files changed, 585 insertions, 460 deletions
diff --git a/ChangeLog b/ChangeLog
index 1f905b1..f50741c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2004-11-19 Miklos Szeredi <miklos@szeredi.hu>
+
+ * Cleaned up kernel in preparation for merge into mainline:
+
+ * Use /sys/fs/fuse/version instead of /proc/fs/fuse/version
+
+ * Use real device (/dev/fuse) instead of /proc/fs/fuse/dev
+
+ * __user annotations for sparse
+
+ * allocate individual pages instead of kmalloc in fuse_readdir,
+ fuse_read and fuse_write.
+
+ * Fix NFS export in case "use_ino" mount option is given
+
2004-11-14 Miklos Szeredi <miklos@szeredi.hu>
* Released 2.1-pre1
diff --git a/kernel/cleanup.sh b/kernel/cleanup.sh
new file mode 100755
index 0000000..6255cb2
--- /dev/null
+++ b/kernel/cleanup.sh
@@ -0,0 +1,16 @@
+#! /bin/sh
+
+destdir=$1
+
+if test ! -d "$destdir"; then
+ printf "Usage: %s destination_directory\n" $0
+ exit 1
+fi
+if test "$destdir" = "."; then
+ echo "Not overwriting contents of original directory"
+ exit 1
+fi
+
+for f in dev.c dir.c file.c inode.c util.c fuse_i.h; do
+ unifdef -DKERNEL_2_6 -DKERNEL_2_6_6_PLUS -DKERNEL_2_6_10_PLUS -DHAVE_KERNEL_XATTR -DFS_SAFE -DMAX_LFS_FILESIZE -DFUSE_MAINLINE -DBUG_ON -D__user -DMODULE_LICENSE $f > $destdir/$f
+done
diff --git a/kernel/dev.c b/kernel/dev.c
index d353c7f..7261770 100644
--- a/kernel/dev.c
+++ b/kernel/dev.c
@@ -8,19 +8,23 @@
#include "fuse_i.h"
+#include <linux/module.h>
#include <linux/poll.h>
+#ifdef KERNEL_2_6
+#include <linux/kobject.h>
+#include <linux/miscdevice.h>
+#else
#include <linux/proc_fs.h>
+#endif
#include <linux/file.h>
-static struct proc_dir_entry *proc_fs_fuse;
-struct proc_dir_entry *proc_fuse_dev;
static kmem_cache_t *fuse_req_cachep;
static inline struct fuse_conn *fuse_get_conn(struct file *file)
{
struct fuse_conn *fc;
spin_lock(&fuse_lock);
- fc = (struct fuse_conn *) file->private_data;
+ fc = file->private_data;
if (fc && !fc->sb)
fc = NULL;
spin_unlock(&fuse_lock);
@@ -29,15 +33,12 @@ static inline struct fuse_conn *fuse_get_conn(struct file *file)
struct fuse_req *fuse_request_alloc(void)
{
- struct fuse_req *req;
-
- req = (struct fuse_req *) kmem_cache_alloc(fuse_req_cachep, SLAB_KERNEL);
+ struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, SLAB_KERNEL);
if (req) {
memset(req, 0, sizeof(*req));
INIT_LIST_HEAD(&req->list);
init_waitqueue_head(&req->waitq);
}
-
return req;
}
@@ -46,68 +47,19 @@ void fuse_request_free(struct fuse_req *req)
kmem_cache_free(fuse_req_cachep, req);
}
-static int request_restartable(enum fuse_opcode opcode)
-{
- switch (opcode) {
- case FUSE_LOOKUP:
- case FUSE_GETATTR:
- case FUSE_SETATTR:
- case FUSE_READLINK:
- case FUSE_GETDIR:
- case FUSE_OPEN:
- case FUSE_READ:
- case FUSE_WRITE:
- case FUSE_STATFS:
- case FUSE_FSYNC:
- case FUSE_GETXATTR:
- case FUSE_SETXATTR:
- case FUSE_LISTXATTR:
- return 1;
-
- default:
- return 0;
- }
-}
-
/* Called with fuse_lock held. Releases, and then reaquires it. */
-static void request_wait_answer(struct fuse_req *req, int interruptible)
+static void request_wait_answer(struct fuse_req *req)
{
- int intr;
-
spin_unlock(&fuse_lock);
- if (interruptible)
- intr = wait_event_interruptible(req->waitq, req->finished);
- else {
- wait_event(req->waitq, req->finished);
- intr = 0;
- }
+ wait_event(req->waitq, req->finished);
spin_lock(&fuse_lock);
- if (!intr)
- return;
-
- /* Request interrupted... Wait for it to be unlocked */
- while (req->locked) {
- req->interrupted = 1;
- spin_unlock(&fuse_lock);
- wait_event(req->waitq, !req->locked);
- spin_lock(&fuse_lock);
- }
- if (req->finished)
- return;
-
- /* Operations which modify the filesystem cannot safely be
- restarted, because it is uncertain whether the operation has
- completed or not... */
- if (req->sent && !request_restartable(req->in.h.opcode))
- req->out.h.error = -EINTR;
- else
- req->out.h.error = -ERESTARTSYS;
}
static int get_unique(struct fuse_conn *fc)
{
- do fc->reqctr++;
- while (!fc->reqctr);
+ fc->reqctr++;
+ if (fc->reqctr == 0)
+ fc->reqctr = 1;
return fc->reqctr;
}
@@ -183,10 +135,9 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
}
}
-static void __request_send(struct fuse_conn *fc, struct fuse_req *req,
- int interruptible)
+void request_send(struct fuse_conn *fc, struct fuse_req *req)
{
- req->issync = 1;
+ req->isreply = 1;
req->end = NULL;
spin_lock(&fuse_lock);
@@ -195,27 +146,15 @@ static void __request_send(struct fuse_conn *fc, struct fuse_req *req,
req->in.h.unique = get_unique(fc);
list_add_tail(&req->list, &fc->pending);
wake_up(&fc->waitq);
- request_wait_answer(req, interruptible);
+ request_wait_answer(req);
list_del(&req->list);
}
spin_unlock(&fuse_lock);
}
-void request_send(struct fuse_conn *fc, struct fuse_req *req)
-{
- /* There are problems with interrupted requests so it's
- disabled for now */
- __request_send(fc, req, 0);
-}
-
-void request_send_nonint(struct fuse_conn *fc, struct fuse_req *req)
-{
- __request_send(fc, req, 0);
-}
-
void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req)
{
- req->issync = 0;
+ req->isreply = 0;
spin_lock(&fuse_lock);
if (fc->file) {
@@ -228,12 +167,12 @@ void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req)
}
}
-void request_send_nonblock(struct fuse_conn *fc, struct fuse_req *req,
+void request_send_async(struct fuse_conn *fc, struct fuse_req *req,
fuse_reqend_t end, void *data)
{
req->end = end;
req->data = data;
- req->issync = 1;
+ req->isreply = 1;
spin_lock(&fuse_lock);
if (fc->file) {
@@ -265,8 +204,8 @@ static void request_wait(struct fuse_conn *fc)
remove_wait_queue(&fc->waitq, &wait);
}
-static inline int copy_in_one(const void *src, size_t srclen, char **dstp,
- size_t *dstlenp)
+static inline int copy_in_one(const void *src, size_t srclen,
+ char __user **dstp, size_t *dstlenp)
{
if (*dstlenp < srclen) {
printk("fuse_dev_read: buffer too small\n");
@@ -282,7 +221,8 @@ static inline int copy_in_one(const void *src, size_t srclen, char **dstp,
return 0;
}
-static inline int copy_in_args(struct fuse_in *in, char *buf, size_t nbytes)
+static inline int copy_in_args(struct fuse_in *in, char __user *buf,
+ size_t nbytes)
{
int err;
int i;
@@ -302,15 +242,15 @@ static inline int copy_in_args(struct fuse_in *in, char *buf, size_t nbytes)
return orignbytes - nbytes;
}
-static ssize_t fuse_dev_read(struct file *file, char *buf, size_t nbytes,
- loff_t *off)
+static ssize_t fuse_dev_read(struct file *file, char __user *buf,
+ size_t nbytes, loff_t *off)
{
ssize_t ret;
struct fuse_conn *fc;
struct fuse_req *req = NULL;
spin_lock(&fuse_lock);
- fc = (struct fuse_conn *) file->private_data;
+ fc = file->private_data;
if (!fc) {
spin_unlock(&fuse_lock);
return -EPERM;
@@ -331,7 +271,7 @@ static ssize_t fuse_dev_read(struct file *file, char *buf, size_t nbytes,
ret = copy_in_args(&req->in, buf, nbytes);
spin_lock(&fuse_lock);
- if (req->issync) {
+ if (req->isreply) {
if (ret < 0) {
req->out.h.error = -EPROTO;
req->finished = 1;
@@ -371,12 +311,12 @@ static struct fuse_req *request_find(struct fuse_conn *fc, unsigned int unique)
static void process_getdir(struct fuse_req *req)
{
- struct fuse_getdir_out_i *arg;
- arg = (struct fuse_getdir_out_i *) req->out.args[0].value;
+ struct fuse_getdir_out_i *arg = req->out.args[0].value;
arg->file = fget(arg->fd);
}
-static inline int copy_out_one(struct fuse_out_arg *arg, const char **srcp,
+static inline int copy_out_one(struct fuse_out_arg *arg,
+ const char __user **srcp,
size_t *srclenp, int allowvar)
{
size_t dstlen = arg->size;
@@ -398,7 +338,7 @@ static inline int copy_out_one(struct fuse_out_arg *arg, const char **srcp,
return 0;
}
-static inline int copy_out_args(struct fuse_req *req, const char *buf,
+static inline int copy_out_args(struct fuse_req *req, const char __user *buf,
size_t nbytes)
{
struct fuse_out *out = &req->out;
@@ -436,8 +376,8 @@ static inline int copy_out_args(struct fuse_req *req, const char *buf,
return 0;
}
-static inline int copy_out_header(struct fuse_out_header *oh, const char *buf,
- size_t nbytes)
+static inline int copy_out_header(struct fuse_out_header *oh,
+ const char __user *buf, size_t nbytes)
{
if (nbytes < sizeof(struct fuse_out_header)) {
printk("fuse_dev_write: write is short\n");
@@ -456,7 +396,12 @@ static int fuse_invalidate(struct fuse_conn *fc, struct fuse_user_header *uh)
down(&fc->sb_sem);
err = -ENODEV;
if (fc->sb) {
- struct inode *inode = fuse_ilookup(fc, uh->ino, uh->nodeid);
+ struct inode *inode;
+#ifdef KERNEL_2_6
+ inode = fuse_ilookup(fc->sb, uh->nodeid);
+#else
+ inode = fuse_ilookup(fc->sb, uh->ino, uh->nodeid);
+#endif
err = -ENOENT;
if (inode) {
fuse_sync_inode(inode);
@@ -474,7 +419,7 @@ static int fuse_invalidate(struct fuse_conn *fc, struct fuse_user_header *uh)
return err;
}
-static int fuse_user_request(struct fuse_conn *fc, const char *buf,
+static int fuse_user_request(struct fuse_conn *fc, const char __user *buf,
size_t nbytes)
{
struct fuse_user_header uh;
@@ -499,8 +444,7 @@ static int fuse_user_request(struct fuse_conn *fc, const char *buf,
return err;
}
-
-static ssize_t fuse_dev_write(struct file *file, const char *buf,
+static ssize_t fuse_dev_write(struct file *file, const char __user *buf,
size_t nbytes, loff_t *off)
{
int err;
@@ -558,7 +502,6 @@ static ssize_t fuse_dev_write(struct file *file, const char *buf,
return err;
}
-
static unsigned int fuse_dev_poll(struct file *file, poll_table *wait)
{
struct fuse_conn *fc = fuse_get_conn(file);
@@ -583,7 +526,7 @@ static void end_requests(struct fuse_conn *fc, struct list_head *head)
struct fuse_req *req;
req = list_entry(head->next, struct fuse_req, list);
list_del_init(&req->list);
- if (req->issync) {
+ if (req->isreply) {
req->out.h.error = -ECONNABORTED;
req->finished = 1;
/* Unlocks fuse_lock: */
@@ -602,7 +545,7 @@ static int fuse_dev_release(struct inode *inode, struct file *file)
struct fuse_conn *fc;
spin_lock(&fuse_lock);
- fc = (struct fuse_conn *) file->private_data;
+ fc = file->private_data;
if (fc) {
fc->file = NULL;
end_requests(fc, &fc->pending);
@@ -613,7 +556,7 @@ static int fuse_dev_release(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations fuse_dev_operations = {
+struct file_operations fuse_dev_operations = {
.owner = THIS_MODULE,
.read = fuse_dev_read,
.write = fuse_dev_write,
@@ -621,6 +564,81 @@ static struct file_operations fuse_dev_operations = {
.release = fuse_dev_release,
};
+#ifdef KERNEL_2_6
+#define FUSE_MINOR MISC_DYNAMIC_MINOR
+
+#ifndef FUSE_MAINLINE
+static decl_subsys(fs, NULL, NULL);
+#endif
+static decl_subsys(fuse, NULL, NULL);
+
+static ssize_t version_show(struct subsystem *subsys, char *buf)
+{
+ return sprintf(buf, "%i.%i\n", FUSE_KERNEL_VERSION,
+ FUSE_KERNEL_MINOR_VERSION);
+}
+static struct subsys_attribute fuse_attr_version = __ATTR_RO(version);
+
+static struct miscdevice fuse_miscdevice = {
+ .minor = FUSE_MINOR,
+ .name = "fuse",
+ .fops = &fuse_dev_operations,
+};
+
+static int __init fuse_sysfs_init(void)
+{
+ int err;
+#ifdef FUSE_MAINLINE
+ err = fs_subsys_register(&fuse_subsys);
+#else
+ subsystem_register(&fs_subsys);
+ kset_set_kset_s(&fuse_subsys, fs_subsys);
+ err = subsystem_register(&fuse_subsys);
+#endif
+ if (err)
+ return err;
+ err = subsys_create_file(&fuse_subsys, &fuse_attr_version);
+ if (err) {
+ subsystem_unregister(&fuse_subsys);
+#ifndef FUSE_MAINLINE
+ subsystem_unregister(&fs_subsys);
+#endif
+ return err;
+ }
+ return 0;
+}
+
+static void fuse_sysfs_clean(void)
+{
+ subsys_remove_file(&fuse_subsys, &fuse_attr_version);
+ subsystem_unregister(&fuse_subsys);
+#ifndef FUSE_MAINLINE
+ subsystem_unregister(&fs_subsys);
+#endif
+}
+
+static int __init fuse_device_init(void)
+{
+ int err = fuse_sysfs_init();
+ if (err)
+ return err;
+
+ err = misc_register(&fuse_miscdevice);
+ if (err) {
+ fuse_sysfs_clean();
+ return err;
+ }
+ return 0;
+}
+
+static void fuse_device_clean(void)
+{
+ misc_deregister(&fuse_miscdevice);
+ fuse_sysfs_clean();
+}
+#else
+static struct proc_dir_entry *proc_fs_fuse;
+
static int read_version(char *page, char **start, off_t off, int count,
int *eof, void *data)
{
@@ -630,27 +648,18 @@ static int read_version(char *page, char **start, off_t off, int count,
return s - page;
}
-int fuse_dev_init()
+static int fuse_device_init(void)
{
- proc_fs_fuse = NULL;
- proc_fuse_dev = NULL;
-
- fuse_req_cachep = kmem_cache_create("fuser_request",
- sizeof(struct fuse_req),
- 0, 0, NULL, NULL);
- if (!fuse_req_cachep)
- return -ENOMEM;
-
proc_fs_fuse = proc_mkdir("fuse", proc_root_fs);
if (proc_fs_fuse) {
struct proc_dir_entry *de;
proc_fs_fuse->owner = THIS_MODULE;
- proc_fuse_dev = create_proc_entry("dev", S_IFSOCK | 0666,
+ de = create_proc_entry("dev", S_IFSOCK | 0666,
proc_fs_fuse);
- if (proc_fuse_dev) {
- proc_fuse_dev->owner = THIS_MODULE;
- proc_fuse_dev->proc_fops = &fuse_dev_operations;
+ if (de) {
+ de->owner = THIS_MODULE;
+ de->proc_fops = &fuse_dev_operations;
}
de = create_proc_entry("version", S_IFREG | 0444, proc_fs_fuse);
if (de) {
@@ -661,20 +670,40 @@ int fuse_dev_init()
return 0;
}
-void fuse_dev_cleanup()
+static void fuse_device_clean(void)
{
if (proc_fs_fuse) {
remove_proc_entry("dev", proc_fs_fuse);
remove_proc_entry("version", proc_fs_fuse);
remove_proc_entry("fuse", proc_root_fs);
}
+}
+#endif
- kmem_cache_destroy(fuse_req_cachep);
+int __init fuse_dev_init(void)
+{
+ int err;
+ err = fuse_device_init();
+ if (err)
+ goto out;
+
+ err = -ENOMEM;
+ fuse_req_cachep = kmem_cache_create("fuser_request",
+ sizeof(struct fuse_req),
+ 0, 0, NULL, NULL);
+ if (!fuse_req_cachep)
+ goto out_device_clean;
+
+ return 0;
+
+ out_device_clean:
+ fuse_device_clean();
+ out:
+ return err;
}
-/*
- * Local Variables:
- * indent-tabs-mode: t
- * c-basic-offset: 8
- * End:
- */
+void fuse_dev_cleanup(void)
+{
+ fuse_device_clean();
+ kmem_cache_destroy(fuse_req_cachep);
+}
diff --git a/kernel/dir.c b/kernel/dir.c
index e322544..124bf86 100644
--- a/kernel/dir.c
+++ b/kernel/dir.c
@@ -9,22 +9,24 @@
#include "fuse_i.h"
#include <linux/pagemap.h>
-#include <linux/slab.h>
#include <linux/file.h>
+#ifdef KERNEL_2_6
+#include <linux/gfp.h>
+#else
+#include <linux/mm.h>
+#endif
+#include <linux/sched.h>
static struct inode_operations fuse_dir_inode_operations;
static struct inode_operations fuse_file_inode_operations;
static struct inode_operations fuse_symlink_inode_operations;
-
static struct file_operations fuse_dir_operations;
-
static struct dentry_operations fuse_dentry_operations;
#ifndef KERNEL_2_6
#define new_decode_dev(x) (x)
#define new_encode_dev(x) (x)
#endif
-
static void change_attributes(struct inode *inode, struct fuse_attr *attr)
{
if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size) {
@@ -126,9 +128,9 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
return inode;
}
-struct inode *fuse_ilookup(struct fuse_conn *fc, ino_t ino, unsigned long nodeid)
+struct inode *fuse_ilookup(struct super_block *sb, unsigned long nodeid)
{
- return ilookup5(fc->sb, nodeid, fuse_inode_eq, &nodeid);
+ return ilookup5(sb, nodeid, fuse_inode_eq, &nodeid);
}
#else
static int fuse_inode_eq(struct inode *inode, unsigned long ino, void *_nodeidp){
@@ -163,16 +165,15 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
return inode;
}
-struct inode *fuse_ilookup(struct fuse_conn *fc, ino_t ino, unsigned long nodeid)
+struct inode *fuse_ilookup(struct super_block *sb, ino_t ino, unsigned long nodeid)
{
- struct inode *inode = iget4(fc->sb, ino, fuse_inode_eq, &nodeid);
+ struct inode *inode = iget4(sb, ino, fuse_inode_eq, &nodeid);
if (inode && !inode->u.generic_ip) {
iput(inode);
inode = NULL;
}
return inode;
}
-
#endif
static int fuse_send_lookup(struct fuse_conn *fc, struct fuse_req *req,
@@ -303,8 +304,7 @@ static int lookup_new_entry(struct fuse_conn *fc, struct fuse_req *req,
return 0;
}
-
-static int _fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
+static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
dev_t rdev)
{
struct fuse_conn *fc = INO_FC(dir);
@@ -340,12 +340,12 @@ static int _fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
return err;
}
-static int _fuse_create(struct inode *dir, struct dentry *entry, int mode)
+static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
+ struct nameidata *nd)
{
- return _fuse_mknod(dir, entry, mode, 0);
+ return fuse_mknod(dir, entry, mode, 0);
}
-
static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
{
struct fuse_conn *fc = INO_FC(dir);
@@ -592,7 +592,7 @@ static int fuse_revalidate(struct dentry *entry)
return fuse_do_getattr(inode);
}
-static int _fuse_permission(struct inode *inode, int mask)
+static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
{
struct fuse_conn *fc = INO_FC(inode);
@@ -601,10 +601,10 @@ static int _fuse_permission(struct inode *inode, int mask)
return -EACCES;
else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
int err;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
- err = vfs_permission(inode, mask);
-#else
+#ifdef KERNEL_2_6_10_PLUS
err = generic_permission(inode, mask, NULL);
+#else
+ err = vfs_permission(inode, mask);
#endif
/* If permission is denied, try to refresh file
@@ -613,13 +613,12 @@ static int _fuse_permission(struct inode *inode, int mask)
if (err == -EACCES) {
err = fuse_do_getattr(inode);
- if (!err) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
- err = vfs_permission(inode, mask);
-#else
+ if (!err)
+#ifdef KERNEL_2_6_10_PLUS
err = generic_permission(inode, mask, NULL);
+#else
+ err = vfs_permission(inode, mask);
#endif
- }
}
/* FIXME: Need some mechanism to revoke permissions:
@@ -706,7 +705,6 @@ static int fuse_getdir(struct file *file)
return err;
}
-#define DIR_BUFSIZE 2048
static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
{
struct file *cfile = file->private_data;
@@ -721,17 +719,17 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
cfile = file->private_data;
}
- buf = kmalloc(DIR_BUFSIZE, GFP_KERNEL);
+ buf = (char *) __get_free_page(GFP_KERNEL);
if (!buf)
return -ENOMEM;
- ret = kernel_read(cfile, file->f_pos, buf, DIR_BUFSIZE);
+ ret = kernel_read(cfile, file->f_pos, buf, PAGE_SIZE);
if (ret < 0)
printk("fuse_readdir: failed to read container file\n");
else
ret = parse_dirfile(buf, ret, file, dstbuf, filldir);
- kfree(buf);
+ free_page((unsigned long) buf);
return ret;
}
@@ -774,7 +772,8 @@ static void free_link(char *link)
free_page((unsigned long) link);
}
-static int fuse_readlink(struct dentry *dentry, char *buffer, int buflen)
+static int fuse_readlink(struct dentry *dentry, char __user *buffer,
+ int buflen)
{
int ret;
char *link;
@@ -863,10 +862,10 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
if (attr->ia_valid & ATTR_SIZE) {
unsigned long limit;
is_truncate = 1;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
- limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
-#else
+#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);
@@ -912,7 +911,7 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
return err;
}
-static int _fuse_dentry_revalidate(struct dentry *entry)
+static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
{
if (!entry->d_inode)
return 0;
@@ -942,9 +941,6 @@ static int _fuse_dentry_revalidate(struct dentry *entry)
}
#ifdef KERNEL_2_6
-
-#define fuse_mknod _fuse_mknod
-
static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
struct kstat *stat)
{
@@ -965,29 +961,7 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
return ERR_PTR(err);
return d_splice_alias(inode, entry);
}
-
-static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
- struct nameidata *nd)
-{
- return _fuse_create(dir, entry, mode);
-}
-
-static int fuse_permission(struct inode *inode, int mask,
- struct nameidata *nd)
-{
- return _fuse_permission(inode, mask);
-}
-
-static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
-{
- return _fuse_dentry_revalidate(entry);
-}
-
#else /* KERNEL_2_6 */
-
-#define fuse_create _fuse_create
-#define fuse_permission _fuse_permission
-
static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
{
struct inode *inode;
@@ -1009,20 +983,29 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
return NULL;
}
-static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
+static int fuse_mknod_2_4(struct inode *dir, struct dentry *entry, int mode,
int rdev)
{
- return _fuse_mknod(dir, entry, mode, rdev);
+ return fuse_mknod(dir, entry, mode, rdev);
+}
+
+static int fuse_dentry_revalidate_2_4(struct dentry *entry, int flags)
+{
+ return fuse_dentry_revalidate(entry, NULL);
+}
+
+static int fuse_create_2_4(struct inode *dir, struct dentry *entry, int mode)
+{
+ return fuse_create(dir, entry, mode, NULL);
}
-static int fuse_dentry_revalidate(struct dentry *entry, int flags)
+static int fuse_permission_2_4(struct inode *inode, int mask)
{
- return _fuse_dentry_revalidate(entry);
+ return fuse_permission(inode, mask, NULL);
}
#endif /* KERNEL_2_6 */
#ifdef HAVE_KERNEL_XATTR
-
#ifdef KERNEL_2_6
static int fuse_setxattr(struct dentry *entry, const char *name,
const void *value, size_t size, int flags)
@@ -1198,14 +1181,10 @@ static int fuse_removexattr(struct dentry *entry, const char *name)
fuse_put_request(fc, req);
return err;
}
-
#endif
-static struct inode_operations fuse_dir_inode_operations =
-{
+static struct inode_operations fuse_dir_inode_operations = {
.lookup = fuse_lookup,
- .create = fuse_create,
- .mknod = fuse_mknod,
.mkdir = fuse_mkdir,
.symlink = fuse_symlink,
.unlink = fuse_unlink,
@@ -1213,10 +1192,15 @@ static struct inode_operations fuse_dir_inode_operations =
.rename = fuse_rename,
.link = fuse_link,
.setattr = fuse_setattr,
- .permission = fuse_permission,
#ifdef KERNEL_2_6
+ .create = fuse_create,
+ .mknod = fuse_mknod,
+ .permission = fuse_permission,
.getattr = fuse_getattr,
#else
+ .create = fuse_create_2_4,
+ .mknod = fuse_mknod_2_4,
+ .permission = fuse_permission_2_4,
.revalidate = fuse_revalidate,
#endif
#ifdef HAVE_KERNEL_XATTR
@@ -1236,10 +1220,11 @@ static struct file_operations fuse_dir_operations = {
static struct inode_operations fuse_file_inode_operations = {
.setattr = fuse_setattr,
- .permission = fuse_permission,
#ifdef KERNEL_2_6
+ .permission = fuse_permission,
.getattr = fuse_getattr,
#else
+ .permission = fuse_permission_2_4,
.revalidate = fuse_revalidate,
#endif
#ifdef HAVE_KERNEL_XATTR
@@ -1250,8 +1235,7 @@ static struct inode_operations fuse_file_inode_operations = {
#endif
};
-static struct inode_operations fuse_symlink_inode_operations =
-{
+static struct inode_operations fuse_symlink_inode_operations = {
.setattr = fuse_setattr,
.readlink = fuse_readlink,
.follow_link = fuse_follow_link,
@@ -1269,12 +1253,9 @@ static struct inode_operations fuse_symlink_inode_operations =
};
static struct dentry_operations fuse_dentry_operations = {
+#ifdef KERNEL_2_6
.d_revalidate = fuse_dentry_revalidate,
+#else
+ .d_revalidate = fuse_dentry_revalidate_2_4,
+#endif
};
-
-/*
- * Local Variables:
- * indent-tabs-mode: t
- * c-basic-offset: 8
- * End:
- */
diff --git a/kernel/file.c b/kernel/file.c
index f89bfb7..03e870b 100644
--- a/kernel/file.c
+++ b/kernel/file.c
@@ -9,27 +9,23 @@
#include <linux/pagemap.h>
#include <linux/slab.h>
-#include <asm/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
#ifdef KERNEL_2_6
-#include <linux/backing-dev.h>
#include <linux/writeback.h>
+#include <linux/moduleparam.h>
#endif
-
-#ifndef KERNEL_2_6
-#define PageUptodate(page) Page_Uptodate(page)
-#endif
+#include <asm/uaccess.h>
static int user_mmap;
#ifdef KERNEL_2_6
-#include <linux/moduleparam.h>
-module_param(user_mmap, int, 0);
+module_param(user_mmap, int, 0644);
#else
MODULE_PARM(user_mmap, "i");
+#define PageUptodate(page) Page_Uptodate(page)
#endif
-
MODULE_PARM_DESC(user_mmap, "Allow non root user to create a shared writable mapping");
-
static int fuse_open(struct inode *inode, struct file *file)
{
struct fuse_conn *fc = INO_FC(inode);
@@ -144,7 +140,7 @@ static int fuse_release(struct inode *inode, struct file *file)
req->in.numargs = 1;
req->in.args[0].size = sizeof(struct fuse_release_in);
req->in.args[0].value = inarg;
- request_send_nonint(fc, req);
+ request_send(fc, req);
fuse_put_request(fc, req);
kfree(ff);
up(&inode->i_sem);
@@ -174,7 +170,7 @@ static int fuse_flush(struct file *file)
req->in.numargs = 1;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
- request_send_nonint(fc, req);
+ request_send(fc, req);
err = req->out.h.error;
fuse_reset_request(req);
up(&inode->i_sem);
@@ -260,7 +256,6 @@ static ssize_t fuse_send_read(struct file *file, struct inode *inode,
return res;
}
-
static int fuse_readpage(struct file *file, struct page *page)
{
struct inode *inode = page->mapping->host;
@@ -284,8 +279,7 @@ static int fuse_readpage(struct file *file, struct page *page)
}
#ifdef KERNEL_2_6
-
-static int read_pages_copyout(struct fuse_req *req, const char *buf,
+static int read_pages_copyout(struct fuse_req *req, const char __user *buf,
size_t nbytes)
{
unsigned i;
@@ -356,7 +350,7 @@ static void fuse_send_readpages(struct fuse_req *req, struct file *file,
req->in.args[0].size = sizeof(struct fuse_read_in);
req->in.args[0].value = inarg;
req->copy_out = read_pages_copyout;
- request_send_nonblock(fc, req, read_pages_end, NULL);
+ request_send_async(fc, req, read_pages_end, NULL);
}
struct fuse_readpages_data {
@@ -404,9 +398,7 @@ static int fuse_readpages(struct file *file, struct address_space *mapping,
return 0;
}
-#endif
-
-#ifndef KERNEL_2_6
+#else /* KERNEL_2_6 */
static int fuse_is_block_uptodate(struct inode *inode, size_t bl_index)
{
size_t index = bl_index << FUSE_BLOCK_PAGE_SHIFT;
@@ -512,58 +504,119 @@ static void fuse_file_bigread(struct file *file, struct inode *inode,
bl_index++;
}
}
-#endif
+#endif /* KERNEL_2_6 */
-static ssize_t fuse_read(struct file *file, char *buf, size_t count,
+static int fuse_read_copyout(struct fuse_req *req, const char __user *buf,
+ size_t nbytes)
+{
+ struct fuse_read_in *inarg = &req->misc.read_in;
+ unsigned i;
+ if (nbytes > inarg->size) {
+ printk("fuse: long read\n");
+ return -EPROTO;
+ }
+ req->out.args[0].size = nbytes;
+ for (i = 0; i < req->num_pages && nbytes; i++) {
+ struct page *page = req->pages[i];
+ unsigned long offset = i * PAGE_CACHE_SIZE;
+ unsigned count = min((unsigned) PAGE_CACHE_SIZE, nbytes);
+ if (copy_from_user(page_address(page), buf + offset, count))
+ return -EFAULT;
+ nbytes -= count;
+ }
+ return 0;
+}
+
+static int fuse_send_read_multi(struct file *file, struct fuse_req *req,
+ size_t size, off_t pos)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ struct fuse_conn *fc = INO_FC(inode);
+ struct fuse_inode *fi = INO_FI(inode);
+ struct fuse_file *ff = file->private_data;
+ struct fuse_read_in *inarg;
+
+ inarg = &req->misc.read_in;
+ inarg->fh = ff->fh;
+ inarg->offset = pos;
+ inarg->size = size;
+ req->in.h.opcode = FUSE_READ;
+ req->in.h.nodeid = fi->nodeid;
+ req->in.numargs = 1;
+ req->in.args[0].size = sizeof(struct fuse_read_in);
+ req->in.args[0].value = inarg;
+ req->copy_out = fuse_read_copyout;
+ request_send(fc, req);
+ return req->out.h.error;
+}
+
+static ssize_t fuse_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
struct inode *inode = file->f_dentry->d_inode;
struct fuse_conn *fc = INO_FC(inode);
- char *tmpbuf;
- ssize_t res = 0;
+ ssize_t res;
loff_t pos = *ppos;
- unsigned int max_read = count < fc->max_read ? count : fc->max_read;
+ struct fuse_req *req;
+ unsigned npages;
+ int i;
- do {
- tmpbuf = kmalloc(max_read, GFP_KERNEL);
- if (tmpbuf)
- break;
-
- max_read /= 2;
- } while (max_read > PAGE_CACHE_SIZE / 4);
- if (!tmpbuf)
- return -ENOMEM;
+ npages = (min(fc->max_read, count) + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ npages = min(npages, (unsigned) FUSE_MAX_PAGES_PER_REQ);
+
+ req = fuse_get_request(fc);
+ if (!req)
+ return -ERESTARTSYS;
+
+ res = -ENOMEM;
+ for (req->num_pages = 0; req->num_pages < npages; req->num_pages++) {
+ req->pages[req->num_pages] = alloc_page(GFP_KERNEL);
+ if (!req->pages[req->num_pages])
+ goto out;
+ }
+ res = 0;
while (count) {
- size_t nbytes = count < max_read ? count : max_read;
- ssize_t res1;
- res1 = fuse_send_read(file, inode, tmpbuf, pos, nbytes);
- if (res1 < 0) {
+ size_t nbytes;
+ size_t nbytes_req = min(req->num_pages * (unsigned) PAGE_SIZE,
+ count);
+ int err = fuse_send_read_multi(file, req, nbytes_req, pos);
+ if (err) {
if (!res)
- res = res1;
+ res = err;
break;
}
- res += res1;
- if (copy_to_user(buf, tmpbuf, res1)) {
- res = -EFAULT;
- break;
+ nbytes = req->out.args[0].size;
+ for (i = 0; i < req->num_pages && nbytes; i++) {
+ struct page *page = req->pages[i];
+ unsigned n = min((unsigned) PAGE_SIZE, nbytes);
+ if (copy_to_user(buf, page_address(page), n)) {
+ res = -EFAULT;
+ break;
+ }
+ nbytes -= n;
+ buf += n;
}
- count -= res1;
- buf += res1;
- pos += res1;
- if (res1 < nbytes)
+ nbytes = req->out.args[0].size;
+ count -= nbytes;
+ res += nbytes;
+ pos += nbytes;
+
+ if (res < 0 || nbytes != nbytes_req)
break;
}
- kfree(tmpbuf);
-
+ out:
+ for (i = 0; i < req->num_pages; i++)
+ __free_page(req->pages[i]);
+ fuse_put_request(fc, req);
if (res > 0)
*ppos += res;
return res;
}
-static ssize_t fuse_file_read(struct file *file, char *buf,
- size_t count, loff_t * ppos)
+static ssize_t fuse_file_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
{
struct inode *inode = file->f_dentry->d_inode;
struct fuse_conn *fc = INO_FC(inode);
@@ -586,9 +639,9 @@ static ssize_t fuse_file_read(struct file *file, char *buf,
return res;
}
-static ssize_t fuse_send_write(struct fuse_req *req, int writepage,
- struct fuse_file *ff, struct inode *inode,
- const char *buf, loff_t pos, size_t count)
+static ssize_t fuse_send_write(struct fuse_req *req, struct fuse_file *ff,
+ struct inode *inode, const char *buf,
+ loff_t pos, size_t count)
{
struct fuse_conn *fc = INO_FC(inode);
struct fuse_inode *fi = INO_FI(inode);
@@ -597,17 +650,12 @@ static ssize_t fuse_send_write(struct fuse_req *req, int writepage,
ssize_t res;
memset(&inarg, 0, sizeof(inarg));
- inarg.writepage = writepage;
+ inarg.writepage = 0;
inarg.fh = ff->fh;
inarg.offset = pos;
inarg.size = count;
req->in.h.opcode = FUSE_WRITE;
req->in.h.nodeid = fi->nodeid;
- if (writepage) {
- req->in.h.uid = 0;
- req->in.h.gid = 0;
- req->in.h.pid = 0;
- }
req->in.numargs = 2;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
@@ -644,7 +692,7 @@ static int write_buffer(struct inode *inode, struct file *file,
pos = ((loff_t) page->index << PAGE_CACHE_SHIFT) + offset;
buffer = kmap(page);
- res = fuse_send_write(req, 0, ff, inode, buffer + offset, pos, count);
+ res = fuse_send_write(req, ff, inode, buffer + offset, pos, count);
fuse_put_request(fc, req);
if (res >= 0) {
if (res < count) {
@@ -676,54 +724,10 @@ static int get_write_count(struct inode *inode, struct page *page)
return count;
}
-
-static int write_page_block(struct inode *inode, struct page *page)
-{
- struct fuse_conn *fc = INO_FC(inode);
- struct fuse_inode *fi = INO_FI(inode);
- char *buffer;
- ssize_t res;
- loff_t pos;
- unsigned count;
- struct fuse_req *req;
-
- req = fuse_get_request(fc);
- if (!req)
- return -ERESTARTSYS;
-
- down_read(&fi->write_sem);
- count = get_write_count(inode, page);
- res = 0;
- if (count) {
- struct fuse_file *ff;
- BUG_ON(list_empty(&fi->write_files));
- ff = list_entry(fi->write_files.next, struct fuse_file, ff_list);
- pos = ((loff_t) page->index << PAGE_CACHE_SHIFT);
- buffer = kmap(page);
- res = fuse_send_write(req, 1, ff, inode, buffer, pos, count);
- if (res >= 0) {
- if (res < count) {
- printk("fuse: short write\n");
- res = -EPROTO;
- } else
- res = 0;
- }
- }
- up_read(&fi->write_sem);
- fuse_put_request(fc, req);
- kunmap(page);
- if (res)
- SetPageError(page);
- return res;
-}
-
-
#ifdef KERNEL_2_6
-
-
-static void write_page_nonblock_end(struct fuse_conn *fc, struct fuse_req *req)
+static void write_page_end(struct fuse_conn *fc, struct fuse_req *req)
{
- struct page *page = (struct page *) req->data;
+ struct page *page = req->data;
struct inode *inode = page->mapping->host;
struct fuse_inode *fi = INO_FI(inode);
struct fuse_write_out *outarg = req->out.args[0].value;
@@ -746,8 +750,8 @@ static void write_page_nonblock_end(struct fuse_conn *fc, struct fuse_req *req)
fuse_put_request(fc, req);
}
-static void send_write_nonblock(struct fuse_req *req, struct inode *inode,
- struct page *page, unsigned count)
+static void fuse_send_writepage(struct fuse_req *req, struct inode *inode,
+ struct page *page, unsigned count)
{
struct fuse_conn *fc = INO_FC(inode);
struct fuse_inode *fi = INO_FI(inode);
@@ -777,57 +781,134 @@ static void send_write_nonblock(struct fuse_req *req, struct inode *inode,
req->out.numargs = 1;
req->out.args[0].size = sizeof(struct fuse_write_out);
req->out.args[0].value = &req->misc.write.out;
- request_send_nonblock(fc, req, write_page_nonblock_end, page);
+ request_send_async(fc, req, write_page_end, page);
}
-static int write_page_nonblock(struct inode *inode, struct page *page)
+static int fuse_writepage(struct page *page, struct writeback_control *wbc)
{
+ struct inode *inode = page->mapping->host;
struct fuse_conn *fc = INO_FC(inode);
struct fuse_inode *fi = INO_FI(inode);
struct fuse_req *req;
int err;
err = -EWOULDBLOCK;
- req = fuse_get_request_nonblock(fc);
+ if (wbc->nonblocking)
+ req = fuse_get_request_nonblock(fc);
+ else
+ req = fuse_get_request_nonint(fc);
if (req) {
- if (down_read_trylock(&fi->write_sem)) {
+ int locked = 1;
+ if (wbc->nonblocking)
+ locked = down_read_trylock(&fi->write_sem);
+ else
+ down_read(&fi->write_sem);
+ if (locked) {
unsigned count;
err = 0;
count = get_write_count(inode, page);
if (count) {
SetPageWriteback(page);
- send_write_nonblock(req, inode, page, count);
- return 0;
+ fuse_send_writepage(req, inode, page, count);
+ goto out;
}
up_read(&fi->write_sem);
}
fuse_put_request(fc, req);
}
+ if (err == -EWOULDBLOCK) {
+#ifdef KERNEL_2_6_6_PLUS
+ redirty_page_for_writepage(wbc, page);
+#else
+ __set_page_dirty_nobuffers(page);
+#endif
+ err = 0;
+ }
+ out:
+ unlock_page(page);
return err;
}
+#else
+static ssize_t fuse_send_writepage(struct fuse_req *req, struct fuse_file *ff,
+ struct inode *inode, const char *buf,
+ loff_t pos, size_t count)
+{
+ struct fuse_conn *fc = INO_FC(inode);
+ struct fuse_inode *fi = INO_FI(inode);
+ struct fuse_write_in inarg;
+ struct fuse_write_out outarg;
+ ssize_t res;
+
+ memset(&inarg, 0, sizeof(inarg));
+ inarg.writepage = 1;
+ inarg.fh = ff->fh;
+ inarg.offset = pos;
+ inarg.size = count;
+ req->in.h.opcode = FUSE_WRITE;
+ req->in.h.nodeid = fi->nodeid;
+ req->in.h.uid = 0;
+ req->in.h.gid = 0;
+ req->in.h.pid = 0;
+ req->in.numargs = 2;
+ req->in.args[0].size = sizeof(inarg);
+ req->in.args[0].value = &inarg;
+ req->in.args[1].size = count;
+ req->in.args[1].value = buf;
+ req->out.numargs = 1;
+ req->out.args[0].size = sizeof(outarg);
+ req->out.args[0].value = &outarg;
+ request_send(fc, req);
+ res = req->out.h.error;
+ if (!res) {
+ if (outarg.size > count)
+ return -EPROTO;
+ else
+ return outarg.size;
+ }
+ else
+ return res;
+}
-static int fuse_writepage(struct page *page, struct writeback_control *wbc)
+static int write_page_block(struct inode *inode, struct page *page)
{
- int err;
- struct inode *inode = page->mapping->host;
+ struct fuse_conn *fc = INO_FC(inode);
+ struct fuse_inode *fi = INO_FI(inode);
+ char *buffer;
+ ssize_t res;
+ loff_t pos;
+ unsigned count;
+ struct fuse_req *req;
- if (wbc->nonblocking) {
- err = write_page_nonblock(inode, page);
- if (err == -EWOULDBLOCK) {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,6)
- redirty_page_for_writepage(wbc, page);
-#else
- __set_page_dirty_nobuffers(page);
-#endif
- err = 0;
+ req = fuse_get_request(fc);
+ if (!req)
+ return -ERESTARTSYS;
+
+ down_read(&fi->write_sem);
+ count = get_write_count(inode, page);
+ res = 0;
+ if (count) {
+ struct fuse_file *ff;
+ BUG_ON(list_empty(&fi->write_files));
+ ff = list_entry(fi->write_files.next, struct fuse_file, ff_list);
+ pos = ((loff_t) page->index << PAGE_CACHE_SHIFT);
+ buffer = kmap(page);
+ res = fuse_send_writepage(req, ff, inode, buffer, pos, count);
+ if (res >= 0) {
+ if (res < count) {
+ printk("fuse: short write\n");
+ res = -EPROTO;
+ } else
+ res = 0;
}
- } else
- err = write_page_block(inode, page);
-
- unlock_page(page);
- return err;
+ }
+ up_read(&fi->write_sem);
+ fuse_put_request(fc, req);
+ kunmap(page);
+ if (res)
+ SetPageError(page);
+ return res;
}
-#else
+
static int fuse_writepage(struct page *page)
{
int err = write_page_block(page->mapping->host, page);
@@ -868,8 +949,8 @@ static int fuse_commit_write(struct file *file, struct page *page,
return err;
}
-static ssize_t fuse_write(struct file *file, const char *buf, size_t count,
- loff_t *ppos)
+static ssize_t fuse_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
{
struct inode *inode = file->f_dentry->d_inode;
struct fuse_conn *fc = INO_FC(inode);
@@ -878,26 +959,26 @@ static ssize_t fuse_write(struct file *file, const char *buf, size_t count,
ssize_t res = 0;
loff_t pos = *ppos;
struct fuse_req *req;
+ size_t max_write = min(fc->max_write, (unsigned) PAGE_SIZE);
req = fuse_get_request(fc);
if (!req)
return -ERESTARTSYS;
- tmpbuf = kmalloc(count < fc->max_write ? count : fc->max_write,
- GFP_KERNEL);
+ tmpbuf = (char *) __get_free_page(GFP_KERNEL);
if (!tmpbuf) {
fuse_put_request(fc, req);
return -ENOMEM;
}
while (count) {
- size_t nbytes = count < fc->max_write ? count : fc->max_write;
+ size_t nbytes = min(max_write, count);
ssize_t res1;
if (copy_from_user(tmpbuf, buf, nbytes)) {
res = -EFAULT;
break;
}
- res1 = fuse_send_write(req, 0, ff, inode, tmpbuf, pos, nbytes);
+ res1 = fuse_send_write(req, ff, inode, tmpbuf, pos, nbytes);
if (res1 < 0) {
res = res1;
break;
@@ -912,7 +993,7 @@ static ssize_t fuse_write(struct file *file, const char *buf, size_t count,
if (count)
fuse_reset_request(req);
}
- kfree(tmpbuf);
+ free_page((unsigned long) tmpbuf);
fuse_put_request(fc, req);
if (res > 0) {
@@ -924,7 +1005,7 @@ static ssize_t fuse_write(struct file *file, const char *buf, size_t count,
return res;
}
-static ssize_t fuse_file_write(struct file *file, const char *buf,
+static ssize_t fuse_file_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
struct inode *inode = file->f_dentry->d_inode;
@@ -995,10 +1076,3 @@ void fuse_init_file_inode(struct inode *inode)
inode->i_fop = &fuse_file_operations;
inode->i_data.a_ops = &fuse_file_aops;
}
-
-/*
- * Local Variables:
- * indent-tabs-mode: t
- * c-basic-offset: 8
- * End:
- */
diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h
index 58d6466..ce35ee4 100644
--- a/kernel/fuse_i.h
+++ b/kernel/fuse_i.h
@@ -8,6 +8,7 @@
#include <linux/fuse.h>
+#ifndef FUSE_MAINLINE
#include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
@@ -15,7 +16,13 @@
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-#define KERNEL_2_6
+# define KERNEL_2_6
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,6)
+# define KERNEL_2_6_6_PLUS
+# endif
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
+# define KERNEL_2_6_10_PLUS
+# endif
#endif
#include <config.h>
@@ -30,23 +37,27 @@
# define i_size_write(inode, size) do { (inode)->i_size = size; } while(0)
# endif
#endif
-#include <linux/kernel.h>
-#include <linux/module.h>
+#endif /* FUSE_MAINLINE */
#include <linux/fs.h>
+#include <linux/wait.h>
#include <linux/list.h>
#include <linux/spinlock.h>
+#include <asm/semaphore.h>
#ifndef BUG_ON
#define BUG_ON(x)
#endif
-
+#ifndef __user
+#define __user
+#endif
+#ifndef KERNEL_2_6
/** Read combining parameters */
#define FUSE_BLOCK_SHIFT 16
#define FUSE_BLOCK_SIZE 65536
#define FUSE_BLOCK_MASK 0xffff0000
-
#define FUSE_BLOCK_PAGE_SHIFT (FUSE_BLOCK_SHIFT - PAGE_CACHE_SHIFT)
-
+#endif
+/* Max number of pages that can be used in a single read request */
#define FUSE_MAX_PAGES_PER_REQ 32
/* If more requests are outstanding, then the operation will block */
@@ -73,7 +84,6 @@ permission checking is done in the kernel */
than for small. */
#define FUSE_LARGE_READ (1 << 31)
#endif
-
/** Bypass the page cache for read and write operations */
#define FUSE_DIRECT_IO (1 << 3)
@@ -130,7 +140,7 @@ struct fuse_req;
struct fuse_conn;
typedef void (*fuse_reqend_t)(struct fuse_conn *, struct fuse_req *);
-typedef int (*fuse_copyout_t)(struct fuse_req *, const char *, size_t);
+typedef int (*fuse_copyout_t)(struct fuse_req *, const char __user *, size_t);
/**
* A request to the client
@@ -139,8 +149,8 @@ struct fuse_req {
/** The request list */
struct list_head list;
- /** True if the request is synchronous */
- unsigned int issync:1;
+ /** True if the request has reply */
+ unsigned int isreply:1;
/** The request is locked */
unsigned int locked:1;
@@ -270,26 +280,25 @@ struct fuse_getdir_out_i {
#define INO_FC(inode) SB_FC((inode)->i_sb)
#define INO_FI(i) ((struct fuse_inode *) (((struct inode *)(i))+1))
-
-/**
- * The proc entry for the client device ("/proc/fs/fuse/dev")
- */
-extern struct proc_dir_entry *proc_fuse_dev;
+/** Device operations */
+extern struct file_operations fuse_dev_operations;
/**
* The lock to protect fuses structures
*/
extern spinlock_t fuse_lock;
-
/**
* Get a filled in inode
*/
struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
int generation, struct fuse_attr *attr, int version);
-
-struct inode *fuse_ilookup(struct fuse_conn *fc, ino_t ino, unsigned long nodeid);
+#ifdef KERNEL_2_6
+struct inode *fuse_ilookup(struct super_block *sb, unsigned long nodeid);
+#else
+struct inode *fuse_ilookup(struct super_block *sb, ino_t ino, unsigned long nodeid);
+#endif
/**
* Send FORGET command
@@ -370,20 +379,15 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req);
void request_send(struct fuse_conn *fc, struct fuse_req *req);
/**
- * Send a non-interruptible request
- */
-void request_send_nonint(struct fuse_conn *fc, struct fuse_req *req);
-
-/**
* Send a request for which a reply is not expected
*/
void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req);
/**
- * Send a synchronous request without blocking
+ * Send asynchronous request
*/
-void request_send_nonblock(struct fuse_conn *fc, struct fuse_req *req,
- fuse_reqend_t end, void *data);
+void request_send_async(struct fuse_conn *fc, struct fuse_req *req,
+ fuse_reqend_t end, void *data);
/**
* Get the attributes of a file
@@ -394,10 +398,3 @@ int fuse_do_getattr(struct inode *inode);
* Write dirty pages
*/
void fuse_sync_inode(struct inode *inode);
-
-/*
- * Local Variables:
- * indent-tabs-mode: t
- * c-basic-offset: 8
- * End:
- */
diff --git a/kernel/inode.c b/kernel/inode.c
index 641d03a..3775733 100644
--- a/kernel/inode.c
+++ b/kernel/inode.c
@@ -9,47 +9,41 @@
#include "fuse_i.h"
#include <linux/pagemap.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/file.h>
#include <linux/mount.h>
-#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/module.h>
#ifdef KERNEL_2_6
+#include <linux/moduleparam.h>
#include <linux/parser.h>
#include <linux/statfs.h>
#else
+#include <linux/proc_fs.h>
#include "compat/parser.h"
#endif
-
-static int user_allow_other;
static kmem_cache_t *fuse_inode_cachep;
+static int user_allow_other;
#ifdef KERNEL_2_6
-#include <linux/moduleparam.h>
-module_param(user_allow_other, int, 0);
+module_param(user_allow_other, int, 0644);
#else
MODULE_PARM(user_allow_other, "i");
#endif
-
MODULE_PARM_DESC(user_allow_other, "Allow non root user to specify the \"allow_other\" or \"allow_root\" mount options");
-
#define FUSE_SUPER_MAGIC 0x65735546
#ifndef KERNEL_2_6
#define kstatfs statfs
#endif
-
#ifndef FS_SAFE
#define FS_SAFE 0
#endif
-
#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 int rootmode;
@@ -176,30 +170,32 @@ static int fuse_statfs(struct super_block *sb, struct kstatfs *buf)
return err;
}
-enum { opt_fd,
- opt_rootmode,
- opt_uid,
- opt_default_permissions,
- opt_allow_other,
- opt_allow_root,
- opt_kernel_cache,
- opt_large_read,
- opt_direct_io,
- opt_max_read,
- opt_err };
+enum {
+ OPT_FD,
+ OPT_ROOTMODE,
+ OPT_UID,
+ OPT_DEFAULT_PERMISSIONS,
+ OPT_ALLOW_OTHER,
+ OPT_ALLOW_ROOT,
+ OPT_KERNEL_CACHE,
+ OPT_LARGE_READ,
+ OPT_DIRECT_IO,
+ OPT_MAX_READ,
+ OPT_ERR
+};
static match_table_t tokens = {
- {opt_fd, "fd=%u"},
- {opt_rootmode, "rootmode=%o"},
- {opt_uid, "uid=%u"},
- {opt_default_permissions, "default_permissions"},
- {opt_allow_other, "allow_other"},
- {opt_allow_root, "allow_root"},
- {opt_kernel_cache, "kernel_cache"},
- {opt_large_read, "large_read"},
- {opt_direct_io, "direct_io"},
- {opt_max_read, "max_read=%u" },
- {opt_err, NULL}
+ {OPT_FD, "fd=%u"},
+ {OPT_ROOTMODE, "rootmode=%o"},
+ {OPT_UID, "uid=%u"},
+ {OPT_DEFAULT_PERMISSIONS, "default_permissions"},
+ {OPT_ALLOW_OTHER, "allow_other"},
+ {OPT_ALLOW_ROOT, "allow_root"},
+ {OPT_KERNEL_CACHE, "kernel_cache"},
+ {OPT_LARGE_READ, "large_read"},
+ {OPT_DIRECT_IO, "direct_io"},
+ {OPT_MAX_READ, "max_read=%u"},
+ {OPT_ERR, NULL}
};
static int parse_fuse_opt(char *opt, struct fuse_mount_data *d)
@@ -218,41 +214,41 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d)
token = match_token(p, tokens, args);
switch (token) {
- case opt_fd:
+ case OPT_FD:
if (match_int(&args[0], &value))
return 0;
d->fd = value;
break;
- case opt_rootmode:
+ case OPT_ROOTMODE:
if (match_octal(&args[0], &value))
return 0;
d->rootmode = value;
break;
- case opt_uid:
+ case OPT_UID:
if (match_int(&args[0], &value))
return 0;
d->uid = value;
break;
- case opt_default_permissions:
+ case OPT_DEFAULT_PERMISSIONS:
d->flags |= FUSE_DEFAULT_PERMISSIONS;
break;
- case opt_allow_other:
+ case OPT_ALLOW_OTHER:
d->flags |= FUSE_ALLOW_OTHER;
break;
- case opt_allow_root:
+ case OPT_ALLOW_ROOT:
d->flags |= FUSE_ALLOW_ROOT;
break;
- case opt_kernel_cache:
+ case OPT_KERNEL_CACHE:
d->flags |= FUSE_KERNEL_CACHE;
break;
- case opt_large_read:
+ case OPT_LARGE_READ:
#ifndef KERNEL_2_6
d->flags |= FUSE_LARGE_READ;
#else
@@ -266,11 +262,11 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d)
#endif
break;
- case opt_direct_io:
+ case OPT_DIRECT_IO:
d->flags |= FUSE_DIRECT_IO;
break;
- case opt_max_read:
+ case OPT_MAX_READ:
if (match_int(&args[0], &value))
return 0;
d->max_read = value;
@@ -328,7 +324,6 @@ void fuse_release_conn(struct fuse_conn *fc)
free_conn(fc);
}
-
static struct fuse_conn *new_conn(void)
{
struct fuse_conn *fc;
@@ -367,12 +362,12 @@ static struct fuse_conn *get_conn(struct file *file, struct super_block *sb)
struct inode *ino;
ino = file->f_dentry->d_inode;
- if (!ino || !proc_fuse_dev ||
- strcmp(ino->i_sb->s_type->name, "proc") != 0 ||
- proc_fuse_dev->low_ino != ino->i_ino) {
+ if (file->f_op != &fuse_dev_operations) {
printk("FUSE: bad communication file descriptor\n");
+ printk("fuse_dev_operations: %p file->f_op: %p\n",
+ &fuse_dev_operations, file->f_op);
return NULL;
- }
+ }
fc = new_conn();
if (fc == NULL) {
printk("FUSE: failed to allocate connection data\n");
@@ -402,21 +397,19 @@ static struct inode *get_root_inode(struct super_block *sb, unsigned int mode)
return fuse_iget(sb, 1, 0, &attr, 0);
}
-
#ifdef KERNEL_2_6
-
static struct dentry *fuse_get_dentry(struct super_block *sb, void *vobjp)
{
__u32 *objp = vobjp;
- unsigned long ino = objp[0];
+ unsigned long nodeid = objp[0];
__u32 generation = objp[1];
struct inode *inode;
struct dentry *entry;
- if (ino == 0)
+ if (nodeid == 0)
return ERR_PTR(-ESTALE);
- inode = ilookup(sb, ino);
+ inode = fuse_ilookup(sb, nodeid);
if (!inode || inode->i_generation != generation)
return ERR_PTR(-ESTALE);
@@ -429,8 +422,41 @@ static struct dentry *fuse_get_dentry(struct super_block *sb, void *vobjp)
return entry;
}
+static int fuse_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len,
+ int connectable)
+{
+ struct inode *inode = dentry->d_inode;
+ struct fuse_inode *fi = INO_FI(inode);
+ int len = *max_len;
+ int type = 1;
+
+ if (len < 2 || (connectable && len < 4))
+ return 255;
+
+ len = 2;
+ fh[0] = fi->nodeid;
+ fh[1] = inode->i_generation;
+ if (connectable && !S_ISDIR(inode->i_mode)) {
+ struct inode *parent;
+ struct fuse_inode *parent_fi;
+
+ spin_lock(&dentry->d_lock);
+ parent = dentry->d_parent->d_inode;
+ parent_fi = INO_FI(parent);
+ fh[2] = parent_fi->nodeid;
+ fh[3] = parent->i_generation;
+ spin_unlock(&dentry->d_lock);
+ len = 4;
+ type = 2;
+ }
+ *max_len = len;
+ return type;
+}
+
+
static struct export_operations fuse_export_operations = {
.get_dentry = fuse_get_dentry,
+ .encode_fh = fuse_encode_fh,
};
#endif
@@ -482,8 +508,6 @@ static int fuse_read_super(struct super_block *sb, void *data, int silent)
fc->max_read = d.max_read;
fc->max_write = FUSE_MAX_IN / 2;
- /* fc is needed in fuse_init_file_inode which could be called
- from get_root_inode */
SB_FC(sb) = fc;
root = get_root_inode(sb, d.rootmode);
@@ -524,7 +548,9 @@ static struct file_system_type fuse_fs_type = {
.name = "fuse",
.get_sb = fuse_get_sb,
.kill_sb = kill_anon_super,
+#ifndef FUSE_MAINLINE
.fs_flags = FS_SAFE,
+#endif
};
#else
static struct super_block *fuse_read_super_compat(struct super_block *sb,
@@ -543,15 +569,14 @@ static DECLARE_FSTYPE(fuse_fs_type, "fuse", fuse_read_super_compat, 0);
static void fuse_inode_init_once(void * foo, kmem_cache_t * cachep,
unsigned long flags)
{
- struct inode * inode = (struct inode *) foo;
+ struct inode * inode = foo;
if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
SLAB_CTOR_CONSTRUCTOR)
inode_init_once(inode);
}
-
-int fuse_fs_init()
+int fuse_fs_init(void)
{
int err;
@@ -572,15 +597,8 @@ int fuse_fs_init()
return err;
}
-void fuse_fs_cleanup()
+void fuse_fs_cleanup(void)
{
unregister_filesystem(&fuse_fs_type);
kmem_cache_destroy(fuse_inode_cachep);
}
-
-/*
- * Local Variables:
- * indent-tabs-mode: t
- * c-basic-offset: 8
- * End:
- */
diff --git a/kernel/linux/fuse.h b/kernel/linux/fuse.h
index 55af4d9..8e62f9f 100644
--- a/kernel/linux/fuse.h
+++ b/kernel/linux/fuse.h
@@ -12,16 +12,16 @@
#define FUSE_KERNEL_VERSION 4
/** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 1
+#define FUSE_KERNEL_MINOR_VERSION 2
/** The node ID of the root inode */
#define FUSE_ROOT_ID 1
/** Opening this will yield a new control file */
-#define FUSE_DEV "/proc/fs/fuse/dev"
+#define FUSE_DEV "/dev/fuse"
/** The file containing the version in the form MAJOR.MINOR */
-#define FUSE_VERSION_FILE "/proc/fs/fuse/version"
+#define FUSE_VERSION_FILE "/sys/fs/fuse/version"
struct fuse_attr {
unsigned long ino;
diff --git a/kernel/util.c b/kernel/util.c
index ac6455d..fa5b082 100644
--- a/kernel/util.c
+++ b/kernel/util.c
@@ -9,7 +9,7 @@
#include "fuse_i.h"
#include <linux/init.h>
-#include <linux/slab.h>
+#include <linux/module.h>
MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
MODULE_DESCRIPTION("Filesystem in Userspace");
@@ -23,9 +23,11 @@ int __init fuse_init(void)
{
int res;
- printk(KERN_DEBUG "fuse init %s (API version %i.%i)\n",
- FUSE_VERSION,
+ 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
spin_lock_init(&fuse_lock);
res = fuse_fs_init();
@@ -54,10 +56,3 @@ void __exit fuse_exit(void)
module_init(fuse_init);
module_exit(fuse_exit);
-
-/*
- * Local Variables:
- * indent-tabs-mode: t
- * c-basic-offset: 8
- * End:
- */