fix
authorMiklos Szeredi <miklos@szeredi.hu>
Sat, 20 Nov 2004 11:12:21 +0000 (11:12 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Sat, 20 Nov 2004 11:12:21 +0000 (11:12 +0000)
ChangeLog
kernel/cleanup.sh [new file with mode: 0755]
kernel/dev.c
kernel/dir.c
kernel/file.c
kernel/fuse_i.h
kernel/inode.c
kernel/linux/fuse.h
kernel/util.c

index 1f905b1e13d62ab8b5024af6bbd7a3faba9b604b..f50741c16f6edc71928a17fe76273ee26c29782a 100644 (file)
--- 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 (executable)
index 0000000..6255cb2
--- /dev/null
@@ -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
index d353c7f59f4a04c1856aa9ff358b12659e7a1cdd..726177097c75ab4e966ed0fe77069cc0fa5417b0 100644 (file)
@@ -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);
+}
index e3225446c103312bd4cff1e8e72af7ea3648b3c3..124bf867e46087bb8c2c93338c8e0c470b409ee0 100644 (file)
@@ -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:
- */
index f89bfb7824c12146dde247fe790fe20ce7e5b6b7..03e870be976148daed51a35af7db28b367bb7658 100644 (file)
@@ -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:
- */
index 58d64667475684d3377eb7af75378abef63b6b5c..ce35ee40c276d589cb234c9f8a0a868ee9e55ff2 100644 (file)
@@ -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)
 #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>
 #     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
@@ -369,21 +378,16 @@ 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:
- */
index 641d03a59089bd89d33e4e7b7afbb4bab21e8ac6..37757338f70ce6c47d0ede7aef35a21142d405c2 100644 (file)
@@ -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:
- */
index 55af4d9da646a315818d8bec289153fd95adfd12..8e62f9f5de88e7de07c667c3fdacbef78e3a8fe9 100644 (file)
 #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;
index ac6455d775c78668d12f239833e11147d69ad8e4..fa5b0828fb26d8f45a3ddc40bdd9467aecb37791 100644 (file)
@@ -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:
- */