fix
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 @@
 
 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 @@
 	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_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 @@
 		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_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 @@
 	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 @@
 	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 @@
 	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 @@
 
 	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 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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 		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 @@
 		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 @@
 	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 @@
 	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 @@
 	.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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 		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 @@
 
 		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 @@
 	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 @@
 		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 @@
 		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 @@
 	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 @@
 	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 @@
 }
 
 #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 @@
 		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 @@
 	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(struct dentry *entry, int flags)
+static int fuse_dentry_revalidate_2_4(struct dentry *entry, int flags)
 {
-	return _fuse_dentry_revalidate(entry);
+	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_permission_2_4(struct inode *inode, int mask)
+{
+	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 @@
 	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 @@
 	.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 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 @@
 #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 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 @@
 	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 @@
 	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 @@
 	return res;
 }
 
-
 static int fuse_readpage(struct file *file, struct page *page)
 {
 	struct inode *inode = page->mapping->host;
@@ -284,8 +279,7 @@
 }
 
 #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 @@
 	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 @@
 
 	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 @@
 		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 @@
 	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 @@
 	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 @@
 	
 	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 @@
 	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 @@
 	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 @@
 	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);
 	}
-	return err;
-}
-
-static int fuse_writepage(struct page *page, struct writeback_control *wbc)
-{
-	int err;
-	struct inode *inode = page->mapping->host;
-
-	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);
+	if (err == -EWOULDBLOCK) {
+#ifdef KERNEL_2_6_6_PLUS
+		redirty_page_for_writepage(wbc, page);
 #else
-			__set_page_dirty_nobuffers(page);
+		__set_page_dirty_nobuffers(page);
 #endif
-			err = 0;
-		}
-	} else
-		err = write_page_block(inode, page);
-
+		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 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_writepage(req, 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;
+}
+
 static int fuse_writepage(struct page *page)
 {
 	int err = write_page_block(page->mapping->host, page);
@@ -868,8 +949,8 @@
 	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 @@
 	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 @@
 		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 @@
 	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 @@
 	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 @@
     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_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 @@
 	/** 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 @@
 #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 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 @@
  * 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 @@
 	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 @@
 		
 		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 @@
 #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 @@
 		free_conn(fc);
 }
 
-
 static struct fuse_conn *new_conn(void)
 {
 	struct fuse_conn *fc;
@@ -367,12 +362,12 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	.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 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 @@
 	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 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 @@
 
 module_init(fuse_init);
 module_exit(fuse_exit);
-
-/*
- * Local Variables:
- * indent-tabs-mode: t
- * c-basic-offset: 8
- * End:
- */