fix
diff --git a/ChangeLog b/ChangeLog
index 846268a..f823e11 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2004-01-26  Miklos Szeredi <mszeredi@inf.bme.hu>
+
+	* Fix typo (thanks Marcos Dione)
+	
+2004-01-23  Miklos Szeredi <mszeredi@inf.bme.hu>
+
+	* Fix CONFIG_MODVERSIONS compile on 2.6
+	
+2004-01-22  Miklos Szeredi <mszeredi@inf.bme.hu>
+
+	* Write all pending data before a RELEASE operation
+
+	* Suppress 'Bad file descriptor' warning on exit
+
+	* Replaced fusermount option '-d xxx' with '-n xxx' so it doesn't
+	get confused with '-d' of fuse_main() (sorry for the change)
+
+	* New fusermount option '-l' which enables big reads
+
+	* fuse_main() can accept fusermount arguments after a '--'
+
 2004-01-19  Miklos Szeredi <mszeredi@inf.bme.hu>
 
 	* Support for exporting filesystem over NFS (see README.NFS)
diff --git a/README.NFS b/README.NFS
index f3d0146..fecc436 100644
--- a/README.NFS
+++ b/README.NFS
@@ -1,11 +1,12 @@
-For the moment NFS exporting is supported on kernels versions >=
-2.6.0.
+NFS exporting is supported on kernels versions >= 2.6.0.  For 2.4.X
+kernels the exporting infrastructure is not refined enough, so don't
+expect this to work.
 
 You need to add an fsid=NNN option to /etc/exports to make exporting a
 FUSE directory work.
 
 You may get ESTALE (Stale NFS file handle) errors with this.  This is
 because the current FUSE kernel API and the userspace library cannot
-handle a situation where the kernel forgets about a dentry which is
+handle a situation where the kernel forgets about an inode which is
 still referenced by the remote NFS client.  This problem will be
 addressed in a later version.
diff --git a/example/null.c b/example/null.c
index 91f2cda..f9ead78 100644
--- a/example/null.c
+++ b/example/null.c
@@ -23,7 +23,7 @@
     stbuf->st_nlink = 1;
     stbuf->st_uid = getuid();
     stbuf->st_gid = getgid();
-    stbuf->st_size = (1 << 30); /* 1G */
+    stbuf->st_size = (1ULL << 32); /* 4G */
     stbuf->st_blocks = 0;
     stbuf->st_atime = stbuf->st_mtime = stbuf->st_ctime = time(NULL);
 
diff --git a/include/fuse.h b/include/fuse.h
index b85f0d8..c2f0be4 100644
--- a/include/fuse.h
+++ b/include/fuse.h
@@ -86,7 +86,9 @@
  * 
  *  - read(), write() are not passed a filehandle, but rather a
  *  pathname.  The offset of the read and write is passed as the last
- *  argument, like the pread() and pwrite() system calls.
+ *  argument, like the pread() and pwrite() system calls.  (NOTE:
+ *  read() should always return the number of bytes requested, except
+ *  at end of file)
  * 
  *  - release() is called when an open file has:
  *       1) all file descriptors closed
@@ -142,10 +144,11 @@
  * main() function.
  * 
  * This function does the following:
- *   - mounts the filesystem
+ *   - parses command line options (-d -s and -h)
+ *   - passes all options after '--' to the fusermount program
+ *   - mounts the filesystem by calling fusermount
  *   - installs signal handlers for INT, HUP, TERM and PIPE
  *   - registers an exit handler to unmount the filesystem on program exit
- *   - parses command line options (-d -s and -h)
  *   - creates a fuse handle
  *   - registers the operations
  *   - calls either the single-threaded or the multi-threaded event loop
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index bcd85b0..909c8b0 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -12,7 +12,7 @@
 #define FUSE_KERNEL_VERSION 2
 
 /** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 1
+#define FUSE_KERNEL_MINOR_VERSION 2
 
 /** The inode number of the root indode */
 #define FUSE_ROOT_INO 1
@@ -53,6 +53,12 @@
     until the INVALIDATE operation is invoked */
 #define FUSE_KERNEL_CACHE        (1 << 2)
 
+/** Allow FUSE to combine reads into 64k chunks.  This is useful if
+    the filesystem is better at handling large chunks.  NOTE: in
+    current implementation the raw throughput is worse for large reads
+    than for small. */
+#define FUSE_LARGE_READ          (1 << 3)
+
 struct fuse_attr {
 	unsigned int        mode;
 	unsigned int        nlink;
diff --git a/kernel/dev.c b/kernel/dev.c
index d3c56a6..9851327 100644
--- a/kernel/dev.c
+++ b/kernel/dev.c
@@ -298,8 +298,7 @@
 		if(ret < 0) {
 			req->out->h.error = -EPROTO;
 			req->finished = 1;
-		}
-		else {
+		} else {
 			list_add_tail(&req->list, &fc->processing);
 			req->sent = 1;
 		}
diff --git a/kernel/dir.c b/kernel/dir.c
index 7e91639..608de2d 100644
--- a/kernel/dir.c
+++ b/kernel/dir.c
@@ -18,7 +18,7 @@
 
 static struct file_operations fuse_dir_operations;
 
-static struct dentry_operations fuse_dentry_opertations;
+static struct dentry_operations fuse_dentry_operations;
 
 /* FIXME: This should be user configurable */
 #define FUSE_REVALIDATE_TIME (1 * HZ)
@@ -137,7 +137,7 @@
 		return err;
 
 	entry->d_time = jiffies;
-	entry->d_op = &fuse_dentry_opertations;
+	entry->d_op = &fuse_dentry_operations;
 	*inodep = inode;
 	return 0;
 }
@@ -769,7 +769,7 @@
 #endif
 };
 
-static struct dentry_operations fuse_dentry_opertations = {
+static struct dentry_operations fuse_dentry_operations = {
 	.d_revalidate	= fuse_dentry_revalidate,
 };
 
diff --git a/kernel/file.c b/kernel/file.c
index 0752943..04eb729 100644
--- a/kernel/file.c
+++ b/kernel/file.c
@@ -60,6 +60,9 @@
 	struct fuse_open_in *inarg = NULL;
 	unsigned int s = sizeof(struct fuse_in) + sizeof(struct fuse_open_in);
 
+	if(file->f_mode & FMODE_WRITE)
+		filemap_fdatawrite(inode->i_mapping);
+
 	in = kmalloc(s, GFP_NOFS);
 	if(!in)
 		return -ENOMEM;
@@ -189,7 +192,6 @@
 		char *buffer;
 
 		page = grab_cache_page(mapping, index);
-
 		if (!page)
 			return -1;
 
@@ -241,38 +243,40 @@
 	return out.h.error;
 }   
 
+static void fuse_file_bigread(struct address_space *mapping,
+			      struct inode *inode, loff_t pos, size_t count)
+{
+	size_t bl_index = pos >> FUSE_BLOCK_SHIFT;
+	size_t bl_end_index = (pos + count) >> FUSE_BLOCK_SHIFT;
+	size_t bl_file_end_index = inode->i_size >> FUSE_BLOCK_SHIFT;
+	
+	if (bl_end_index > bl_file_end_index)
+		bl_end_index = bl_file_end_index;
+	
+	while (bl_index <= bl_end_index) {
+		int res;
+		char *bl_buf = kmalloc(FUSE_BLOCK_SIZE, GFP_NOFS);
+		if (!bl_buf)
+			break;
+		res = fuse_is_block_uptodate(mapping, inode, bl_index);
+		if (!res)
+			res = fuse_file_read_block(inode, bl_buf, bl_index);
+		if (!res)
+			fuse_cache_block(mapping, inode, bl_buf, bl_index);
+		kfree(bl_buf);
+		bl_index++;
+	}
+}
+
 static ssize_t fuse_file_read(struct file *filp, char *buf,
 		size_t count, loff_t * ppos)
 {
 	struct address_space *mapping = filp->f_dentry->d_inode->i_mapping;
 	struct inode *inode = mapping->host;
+	struct fuse_conn *fc = INO_FC(inode);
 
-	size_t bl_index = *ppos >> FUSE_BLOCK_SHIFT;
-	size_t bl_end_index = (*ppos + count) >> FUSE_BLOCK_SHIFT;
-	size_t bl_file_end_index = inode->i_size >> FUSE_BLOCK_SHIFT;
-
-	if (bl_end_index > bl_file_end_index)
-		bl_end_index = bl_file_end_index;
-
-	while (bl_index <= bl_end_index) {
-		int res;
-		char *bl_buf = kmalloc(FUSE_BLOCK_SIZE, GFP_NOFS);
-
-		if (!bl_buf)
-			break;
-
-		res = fuse_is_block_uptodate(mapping, inode, bl_index);
-
-		if (!res)
-			res = fuse_file_read_block(inode, bl_buf, bl_index);
-
-		if (!res)
-			fuse_cache_block(mapping, inode, bl_buf, bl_index);
-
-		kfree(bl_buf);
-
-		bl_index++;
-	}
+	if(fc->flags & FUSE_LARGE_READ)
+		fuse_file_bigread(mapping, inode, *ppos, count);
 
 	return generic_file_read(filp, buf, count, ppos);
 }  
@@ -466,11 +470,15 @@
 
 void fuse_init_file_inode(struct inode *inode)
 {
+#ifdef KERNEL_2_6
+	struct fuse_conn *fc = INO_FC(inode);
+	/* Readahead somehow defeats big reads on 2.6 (says Michael
+           Grigoriev) */
+	if(fc->flags & FUSE_LARGE_READ)
+		inode->i_mapping->backing_dev_info->ra_pages = 0;
+#endif
 	inode->i_fop = &fuse_file_operations;
 	inode->i_data.a_ops = &fuse_file_aops;
-#ifdef KERNEL_2_6
-	inode->i_mapping->backing_dev_info->ra_pages = 0;
-#endif
 }
 
 /* 
diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h
index f2e55d4..cc386ac 100644
--- a/kernel/fuse_i.h
+++ b/kernel/fuse_i.h
@@ -8,15 +8,25 @@
 
 
 #include <linux/fuse.h>
+#include <linux/version.h>
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+#error Kernel version 2.5.* not supported
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#define KERNEL_2_6
+#endif
+
+#ifndef KERNEL_2_6
 #include <linux/config.h>
 #ifdef CONFIG_MODVERSIONS
 #define MODVERSIONS
 #include <linux/modversions.h>
 #endif
+#endif 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/fs.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
@@ -28,15 +38,6 @@
 
 #define FUSE_BLOCK_PAGE_SHIFT (FUSE_BLOCK_SHIFT - PAGE_CACHE_SHIFT)
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-#error Kernel version 2.5.* not supported
-#endif
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-#define KERNEL_2_6
-#endif
-
-
 /**
  * A Fuse connection.
  *
diff --git a/kernel/inode.c b/kernel/inode.c
index 4a16051..f5c3a97 100644
--- a/kernel/inode.c
+++ b/kernel/inode.c
@@ -201,38 +201,35 @@
 	sb->s_export_op = &fuse_export_operations;
 #endif
 
+	fc = get_conn(d);
+	if(fc == NULL)
+		return -EINVAL;
+	spin_lock(&fuse_lock);
+	if(fc->sb != NULL) {
+		printk("fuse_read_super: connection already mounted\n");
+		spin_unlock(&fuse_lock);
+		return -EINVAL;
+	}
+	fc->sb = sb;
+	fc->flags = d->flags;
+	fc->uid = d->uid;
+	spin_unlock(&fuse_lock);
+	
+	/* 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);
 	if(root == NULL) {
 		printk("fuse_read_super: failed to get root inode\n");
 		return -EINVAL;
 	}
 
-	spin_lock(&fuse_lock);
-	fc = get_conn(d);
-	if(fc == NULL)
-		goto err;
-
-	if(fc->sb != NULL) {
-		printk("fuse_read_super: connection already mounted\n");
-		goto err;
-	}
-
-	SB_FC(sb) = fc;
 	sb->s_root = d_alloc_root(root);
 	if(!sb->s_root)
-		goto err;
+		return -EINVAL;
 
-	fc->sb = sb;
-	fc->flags = d->flags;
-	fc->uid = d->uid;
-	spin_unlock(&fuse_lock);
-	
 	return 0;
-
-  err:
-	spin_unlock(&fuse_lock);
-	iput(root);
-	return -EINVAL;
 }
 
 #ifdef KERNEL_2_6
diff --git a/lib/fuse.c b/lib/fuse.c
index d382707..50ae3a8 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -1006,7 +1006,7 @@
         res = read(f->fd, cmd->buf, FUSE_MAX_IN);
         if(res == -1) {
             free_cmd(cmd);
-            if(errno == EINTR)
+            if(f->exited || errno == EINTR)
                 return NULL;
 
             /* ENODEV means we got unmounted, so we silenty return failure */
diff --git a/lib/helper.c b/lib/helper.c
index d3b8b1c..d417d90 100644
--- a/lib/helper.c
+++ b/lib/helper.c
@@ -23,15 +23,24 @@
 static void usage(char *progname)
 {
     fprintf(stderr,
-            "usage: %s mountpoint [options] \n"
+            "usage: %s mountpoint [options] [-- [fusermount options]]\n"
             "Options:\n"
             "    -d      enable debug output\n"
             "    -s      disable multithreaded operation\n"
-            "    -h      print help\n",
+            "    -h      print help\n"
+            "\n"
+            "Fusermount options:\n"
+            "            see 'fusermount -h'\n",
             progname);
     exit(1);
 }
 
+static void invalid_option(char *argv[], int argctr)
+{
+    fprintf(stderr, "invalid option: %s\n", argv[argctr]);
+    usage(argv[0]);
+}
+
 static void exit_handler()
 {
     if(fuse != NULL)
@@ -71,19 +80,51 @@
     int fuse_fd;
     char *fuse_mountpoint = NULL;
     char umount_cmd[1024] = "";
-
-    if(isreexec == NULL) {
+    char **fusermount_args = NULL;
+    
+    if(!isreexec) {
         if(argc < 2 || argv[1][0] == '-')
             usage(argv[0]);
+        argctr ++;
+    }
 
+    flags = 0;
+    multithreaded = 1;
+    for(; argctr < argc && !fusermount_args; argctr ++) {
+        if(argv[argctr][0] == '-' && strlen(argv[argctr]) == 2)
+            switch(argv[argctr][1]) {
+            case 'd':
+                flags |= FUSE_DEBUG;
+                break;
+                
+            case 's':
+                multithreaded = 0;
+                break;
+                
+            case 'h':
+                usage(argv[0]);
+                break;
+                
+            case '-':
+                if(!isreexec)
+                    fusermount_args = &argv[argctr+1];
+                else
+                    invalid_option(argv, argctr);
+                break;
+                
+            default:
+                invalid_option(argv, argctr);
+            }
+        else 
+            invalid_option(argv, argctr);
+    }
+
+    if(!isreexec) {
         fuse_mountpoint = strdup(argv[1]);
-        fuse_fd = fuse_mount(fuse_mountpoint, NULL);
+        fuse_fd = fuse_mount(fuse_mountpoint, (const char **) fusermount_args);
         if(fuse_fd == -1)
             exit(1);
-
-        argctr++;
-    }
-    else {
+    } else {
         char *tmpstr;
 
         /* Old (obsolescent) way of doing the mount: 
@@ -101,32 +142,6 @@
 
     set_signal_handlers();
 
-    flags = 0;
-    multithreaded = 1;
-    for(; argctr < argc && argv[argctr][0] == '-'; argctr ++) {
-        switch(argv[argctr][1]) {
-        case 'd':
-            flags |= FUSE_DEBUG;
-            break;
-
-        case 's':
-            multithreaded = 0;
-            break;
-
-        case 'h':
-            usage(argv[0]);
-            break;
-
-        default:
-            fprintf(stderr, "invalid option: %s\n", argv[argctr]);
-            exit(1);
-        }
-    }
-    if(argctr != argc) {
-        fprintf(stderr, "missing or surplus argument\n");
-        exit(1);
-    }
-
     fuse = fuse_new(fuse_fd, flags, op);
 
     if(multithreaded)
diff --git a/util/fusermount.c b/util/fusermount.c
index 1a6db91..1d8afd2 100644
--- a/util/fusermount.c
+++ b/util/fusermount.c
@@ -487,7 +487,8 @@
             " -p       check default permissions on files\n"
             " -c       cache in kernel space if possible\n"
             " -x       allow other users to access the files (only for root)\n"
-            " -d name  add 'name' as the filesystem name to mtab\n",
+            " -n name  add 'name' as the filesystem name to mtab\n"
+            " -l       issue large reads\n",
             progname);
     exit(1);
 }
@@ -541,15 +542,19 @@
             flags |= FUSE_ALLOW_OTHER;
             break;
             
-        case 'd':
+        case 'n':
             a++;
             if(a == argc) {
-                fprintf(stderr, "%s: Missing argument to -d\n", progname);
+                fprintf(stderr, "%s: Missing argument to -n\n", progname);
                 exit(1);
             }
             fsname = argv[a];
             break;
 
+        case 'l':
+            flags |= FUSE_LARGE_READ;
+            break;
+
         default:
             fprintf(stderr, "%s: Unknown option %s\n", progname, argv[a]);
             exit(1);