fix
diff --git a/ChangeLog b/ChangeLog
index 1298d09..0ea0d2e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,45 @@
+2006-01-20  Miklos Szeredi <miklos@szeredi.hu>
+
+	* fuse_opt: add new helper constants FUSE_OPT_KEY_KEEP and
+	FUSE_OPT_KEY_DISCARD
+
+	* Add options 'max_readahead', 'sync_read' and 'async_read'
+
+	* Kernel ABI version 7.6:
+
+	* Negotiate the 'max_readahead' value and 'async_read' flags with
+	userspace in the INIT method
+
+	* Add connection info to ->init() methods to both lowlevel and
+	highlevel API
+
+	* Fall back to synchronous read() behavior if either library or
+	userspace filesystem is using the old interface version.  This is
+	needed so non-updated filesystems won't be confused by the
+	different read() behavior
+
+2006-01-19  Miklos Szeredi <miklos@szeredi.hu>
+
+	* lib: if "fsname=" option was given, pass it to fusermount
+
+	* fuse_opt: add new fuse_opt_insert_arg() function, which is
+	needed by filesystems to implement some argument manipulations
+	correctly
+
+	* fuse_opt: fix memory leak in handling "--" option
+
+2006-01-18  Miklos Szeredi <miklos@szeredi.hu>
+
+	* kernel: fix detection of case when fuse is not configured into
+	the kernel either as module or built-in
+
+	* fuse_opt.h: fix incompatibility with C++ compilers by renaming
+	'template' structure member to 'templ'.  Reported by Takashi Iwai
+
+	* fuse.h: fix compatibility bugs.  Patch by Yura Pakhuchiy
+
+	* kernel: support version 2.6.16 (i_sem -> i_mutex)
+
 2006-01-16  Miklos Szeredi <miklos@szeredi.hu>
 
 	* Added (again) asynchronous readpages support
diff --git a/configure.in b/configure.in
index d14db87..4e29570 100644
--- a/configure.in
+++ b/configure.in
@@ -1,4 +1,4 @@
-AC_INIT(fuse, 2.5.0)
+AC_INIT(fuse, 2.7.0-pre0)
 AC_CANONICAL_TARGET
 AM_INIT_AUTOMAKE
 AM_CONFIG_HEADER(include/config.h)
@@ -23,7 +23,7 @@
 if test "$ac_env_CFLAGS_set" != set; then
 	CFLAGS="-Wall -W -g -O2"
 fi
-CPPFLAGS="$CPPFLAGS -D_FILE_OFFSET_BITS=64 -D_REENTRANT -DFUSE_USE_VERSION=25"
+CPPFLAGS="$CPPFLAGS -D_FILE_OFFSET_BITS=64 -D_REENTRANT -DFUSE_USE_VERSION=27"
 
 AC_ARG_ENABLE(kernel-module,
 	[  --enable-kernel-module  Compile kernel module ])
diff --git a/include/fuse.h b/include/fuse.h
index a94c61a..3c3a98f 100644
--- a/include/fuse.h
+++ b/include/fuse.h
@@ -295,7 +295,7 @@
      *
      * Introduced in version 2.3
      */
-    void *(*init) (void);
+    void *(*init) (struct fuse_conn_info *conn);
 
     /**
      * Clean up filesystem
@@ -535,13 +535,25 @@
  * Compatibility stuff                                         *
  * ----------------------------------------------------------- */
 
-#ifndef __FreeBSD__
+#ifdef __FreeBSD__
+#  if FUSE_USE_VERSION < 25
+#    error On FreeBSD API version 25 or greater must be used
+#  endif
+#endif
 
-#if FUSE_USE_VERSION == 22 || FUSE_USE_VERSION == 21 || FUSE_USE_VERSION == 11
+#if FUSE_USE_VERSION == 25 || FUSE_USE_VERSION == 22 || \
+    FUSE_USE_VERSION == 21 || FUSE_USE_VERSION == 11
 #  include "fuse_compat.h"
 #  undef FUSE_MINOR_VERSION
 #  undef fuse_main
-#  if FUSE_USE_VERSION == 22
+#  if FUSE_USE_VERSION == 25
+#    define FUSE_MINOR_VERSION 6
+#    define fuse_main(argc, argv, op) \
+            fuse_main_real_compat25(argc, argv, op, sizeof(*(op)))
+#    define fuse_new fuse_new_compat25
+#    define fuse_setup fuse_setup_compat25
+#    define fuse_operations fuse_operations_compat25
+#  elif FUSE_USE_VERSION == 22
 #    define FUSE_MINOR_VERSION 4
 #    define fuse_main(argc, argv, op) \
             fuse_main_real_compat22(argc, argv, op, sizeof(*(op)))
@@ -549,13 +561,14 @@
 #    define fuse_setup fuse_setup_compat22
 #    define fuse_operations fuse_operations_compat22
 #    define fuse_file_info fuse_file_info_compat22
+#    define fuse_mount fuse_mount_compat22
 #  else
 #    define fuse_dirfil_t fuse_dirfil_t_compat
 #    define __fuse_read_cmd fuse_read_cmd
 #    define __fuse_process_cmd fuse_process_cmd
 #    define __fuse_loop_mt fuse_loop_mt_proc
 #    if FUSE_USE_VERSION == 21
-#      define FUSE_MAJOR_VERSION 2
+#      define FUSE_MINOR_VERSION 1
 #      define fuse_operations fuse_operations_compat2
 #      define fuse_main fuse_main_compat2
 #      define fuse_new fuse_new_compat2
@@ -563,6 +576,7 @@
 #      define __fuse_teardown fuse_teardown
 #      define __fuse_exited fuse_exited
 #      define __fuse_set_getcontext_func fuse_set_getcontext_func
+#      define fuse_mount fuse_mount_compat22
 #    else
 #      warning Compatibility with API version 11 is deprecated
 #      undef FUSE_MAJOR_VERSION
@@ -576,18 +590,10 @@
 #      define FUSE_DEBUG FUSE_DEBUG_COMPAT1
 #    endif
 #  endif
-#elif FUSE_USE_VERSION < 25
-#  error Compatibility with API version other than 21, 22 and 11 not supported
+#elif FUSE_USE_VERSION < 27
+#  error Compatibility with API version other than 21, 22, 25 and 11 not supported
 #endif
 
-#else /* __FreeBSD__ */
-
-#if FUSE_USE_VERSION < 25
-#  error On FreeBSD API version 25 or greater must be used
-#endif
-
-#endif /* __FreeBSD__ */
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/fuse_common.h b/include/fuse_common.h
index 0f35ea6..4304462 100644
--- a/include/fuse_common.h
+++ b/include/fuse_common.h
@@ -20,7 +20,7 @@
 #define FUSE_MAJOR_VERSION 2
 
 /** Minor version of FUSE library interface */
-#define FUSE_MINOR_VERSION 5
+#define FUSE_MINOR_VERSION 7
 
 #define FUSE_MAKE_VERSION(maj, min)  ((maj) * 10 + (min))
 #define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION)
@@ -66,6 +66,15 @@
     uint64_t fh;
 };
 
+struct fuse_conn_info {
+    unsigned proto_major;
+    unsigned proto_minor;
+    unsigned async_read;
+    unsigned max_write;
+    unsigned max_readahead;
+    unsigned reserved[27];
+};
+
 /**
  * Create a FUSE mountpoint
  *
diff --git a/include/fuse_compat.h b/include/fuse_compat.h
index 220ef07..97f7b12 100644
--- a/include/fuse_compat.h
+++ b/include/fuse_compat.h
@@ -9,6 +9,60 @@
 /* these definitions provide source compatibility to prior versions.
    Do not include this file directly! */
 
+struct fuse_operations_compat25 {
+    int (*getattr) (const char *, struct stat *);
+    int (*readlink) (const char *, char *, size_t);
+    int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t);
+    int (*mknod) (const char *, mode_t, dev_t);
+    int (*mkdir) (const char *, mode_t);
+    int (*unlink) (const char *);
+    int (*rmdir) (const char *);
+    int (*symlink) (const char *, const char *);
+    int (*rename) (const char *, const char *);
+    int (*link) (const char *, const char *);
+    int (*chmod) (const char *, mode_t);
+    int (*chown) (const char *, uid_t, gid_t);
+    int (*truncate) (const char *, off_t);
+    int (*utime) (const char *, struct utimbuf *);
+    int (*open) (const char *, struct fuse_file_info *);
+    int (*read) (const char *, char *, size_t, off_t, struct fuse_file_info *);
+    int (*write) (const char *, const char *, size_t, off_t,
+                  struct fuse_file_info *);
+    int (*statfs) (const char *, struct statvfs *);
+    int (*flush) (const char *, struct fuse_file_info *);
+    int (*release) (const char *, struct fuse_file_info *);
+    int (*fsync) (const char *, int, struct fuse_file_info *);
+    int (*setxattr) (const char *, const char *, const char *, size_t, int);
+    int (*getxattr) (const char *, const char *, char *, size_t);
+    int (*listxattr) (const char *, char *, size_t);
+    int (*removexattr) (const char *, const char *);
+    int (*opendir) (const char *, struct fuse_file_info *);
+    int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t,
+                    struct fuse_file_info *);
+    int (*releasedir) (const char *, struct fuse_file_info *);
+    int (*fsyncdir) (const char *, int, struct fuse_file_info *);
+    void *(*init) (void);
+    void (*destroy) (void *);
+    int (*access) (const char *, int);
+    int (*create) (const char *, mode_t, struct fuse_file_info *);
+    int (*ftruncate) (const char *, off_t, struct fuse_file_info *);
+    int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *);
+};
+
+struct fuse *fuse_new_compat25(int fd, struct fuse_args *args,
+                               const struct fuse_operations_compat25 *op,
+                               size_t op_size);
+
+int fuse_main_real_compat25(int argc, char *argv[],
+                            const struct fuse_operations_compat25 *op,
+                            size_t op_size);
+
+struct fuse *fuse_setup_compat25(int argc, char *argv[],
+                                 const struct fuse_operations_compat25 *op,
+                                 size_t op_size, char **mountpoint,
+                                 int *multithreaded, int *fd);
+
+#ifndef __FreeBSD__
 #include <sys/statfs.h>
 
 struct fuse_file_info_compat22 {
@@ -145,3 +199,5 @@
 struct fuse *fuse_new_compat1(int fd, int flags, const struct fuse_operations_compat1 *op);
 
 void fuse_main_compat1(int argc, char *argv[], const struct fuse_operations_compat1 *op);
+
+#endif /* __FreeBSD__ */
diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h
index e45968c..0c4672f 100644
--- a/include/fuse_lowlevel.h
+++ b/include/fuse_lowlevel.h
@@ -141,7 +141,7 @@
      *
      * @param userdata the user data passed to fuse_lowlevel_new()
      */
-    void (*init) (void *userdata);
+    void (*init) (void *userdata, struct fuse_conn_info *conn);
 
     /**
      * Clean up filesystem
@@ -1235,27 +1235,29 @@
  * Compatibility stuff                                         *
  * ----------------------------------------------------------- */
 
-#ifndef __FreeBSD__
+#ifdef __FreeBSD__
+#  if FUSE_USE_VERSION < 25
+#    error On FreeBSD API version 25 or greater must be used
+#  endif
+#endif
 
-#if FUSE_USE_VERSION == 24
+#if FUSE_USE_VERSION == 25 || FUSE_USE_VERSION == 24
 #  include "fuse_lowlevel_compat.h"
 #  undef FUSE_MINOR_VERSION
-#  define FUSE_MINOR_VERSION 4
-#  define fuse_file_info fuse_file_info_compat
-#  define fuse_reply_statfs fuse_reply_statfs_compat
-#  define fuse_reply_open fuse_reply_open_compat
-#elif FUSE_USE_VERSION < 25
-#  error Compatibility with low level API version other than 24 not supported
+#  if FUSE_USE_VERSION == 25
+#    define FUSE_MINOR_VERSION 6
+#    define fuse_lowlevel_ops fuse_lowlevel_ops_compat25
+#    define fuse_lowlevel_new fuse_lowlevel_new_compat25
+#  else
+#    define FUSE_MINOR_VERSION 4
+#    define fuse_file_info fuse_file_info_compat
+#    define fuse_reply_statfs fuse_reply_statfs_compat
+#    define fuse_reply_open fuse_reply_open_compat
+#  endif
+#elif FUSE_USE_VERSION < 27
+#  error Compatibility with low level API version other than 24 and 25 not supported
 #endif
 
-#else /* __FreeBSD__ */
-
-#if FUSE_USE_VERSION < 25
-#  error On FreeBSD API version 25 or greater must be used
-#endif
-
-#endif /* __FreeBSD__ */
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/fuse_lowlevel_compat.h b/include/fuse_lowlevel_compat.h
index ccb7d01..0ba0c96 100644
--- a/include/fuse_lowlevel_compat.h
+++ b/include/fuse_lowlevel_compat.h
@@ -9,6 +9,61 @@
 /* these definitions provide source compatibility to prior versions.
    Do not include this file directly! */
 
+struct fuse_lowlevel_ops_compat25 {
+    void (*init) (void *userdata);
+    void (*destroy) (void *userdata);
+    void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name);
+    void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup);
+    void (*getattr) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
+    void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr,
+                     int to_set, struct fuse_file_info *fi);
+    void (*readlink) (fuse_req_t req, fuse_ino_t ino);
+    void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name,
+                   mode_t mode, dev_t rdev);
+    void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name,
+                   mode_t mode);
+    void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name);
+    void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name);
+    void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent,
+                     const char *name);
+    void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name,
+                    fuse_ino_t newparent, const char *newname);
+    void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
+                  const char *newname);
+    void (*open) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
+    void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
+                  struct fuse_file_info *fi);
+    void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf,
+                   size_t size, off_t off, struct fuse_file_info *fi);
+    void (*flush) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
+    void (*release) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
+    void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync,
+                   struct fuse_file_info *fi);
+    void (*opendir) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
+    void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
+                     struct fuse_file_info *fi);
+    void (*releasedir) (fuse_req_t req, fuse_ino_t ino,
+                        struct fuse_file_info *fi);
+    void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync,
+                      struct fuse_file_info *fi);
+    void (*statfs) (fuse_req_t req);
+    void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
+                      const char *value, size_t size, int flags);
+    void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
+                      size_t size);
+    void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size);
+    void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name);
+    void (*access) (fuse_req_t req, fuse_ino_t ino, int mask);
+    void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name,
+                    mode_t mode, struct fuse_file_info *fi);
+};
+
+struct fuse_session *fuse_lowlevel_new_compat25(struct fuse_args *args,
+                        const struct fuse_lowlevel_ops_compat25 *op,
+                        size_t op_size, void *userdata);
+
+#ifndef __FreeBSD__
+
 #include <sys/statfs.h>
 
 struct fuse_file_info_compat {
@@ -27,3 +82,5 @@
 struct fuse_session *fuse_lowlevel_new_compat(const char *opts,
                                               const struct fuse_lowlevel_ops *op,
                                               size_t op_size, void *userdata);
+
+#endif /* __FreeBSD__ */
diff --git a/include/fuse_opt.h b/include/fuse_opt.h
index 2ef5d56..9e159d5 100644
--- a/include/fuse_opt.h
+++ b/include/fuse_opt.h
@@ -72,7 +72,7 @@
  */
 struct fuse_opt {
     /** Matching template and optional parameter formatting */
-    const char *template;
+    const char *templ;
 
     /**
      * Offset of variable within 'data' parameter of fuse_opt_parse()
@@ -82,7 +82,7 @@
 
     /**
      * Value to set the variable to, or to be passed as 'key' to the
-     * processing function.  Ignored if template a format
+     * processing function.  Ignored if template has a format
      */
     int value;
 };
@@ -91,13 +91,13 @@
  * Key option.  In case of a match, the processing function will be
  * called with the specified key.
  */
-#define FUSE_OPT_KEY(template, key) { template, -1U, key }
+#define FUSE_OPT_KEY(templ, key) { templ, -1U, key }
 
 /**
  * Last option.  An array of 'struct fuse_opt' must end with a NULL
  * template value
  */
-#define FUSE_OPT_END { .template = NULL }
+#define FUSE_OPT_END { .templ = NULL }
 
 /**
  * Argument list
@@ -120,7 +120,7 @@
 
 /**
  * Key value passed to the processing function if an option did not
- * match any templated
+ * match any template
  */
 #define FUSE_OPT_KEY_OPT     -1
 
@@ -133,6 +133,22 @@
 #define FUSE_OPT_KEY_NONOPT  -2
 
 /**
+ * Special key value for options to keep
+ *
+ * Argument is not passed to processing function, but behave as if the
+ * processing function returned 1
+ */
+#define FUSE_OPT_KEY_KEEP -3
+
+/**
+ * Special key value for options to discard
+ *
+ * Argument is not passed to processing function, but behave as if the
+ * processing function returned zero
+ */
+#define FUSE_OPT_KEY_DISCARD -4
+
+/**
  * Processing function
  *
  * This function is called if
@@ -202,6 +218,21 @@
 int fuse_opt_add_arg(struct fuse_args *args, const char *arg);
 
 /**
+ * Add an argument at the specified position in a NULL terminated
+ * argument vector
+ *
+ * Adds the argument to the N-th position.  This is useful for adding
+ * options at the beggining of the array which must not come after the
+ * special '--' option.
+ *
+ * @param args is the structure containing the current argument list
+ * @param pos is the position at which to add the argument
+ * @param arg is the new argument to add
+ * @return -1 on allocation error, 0 on success
+ */
+int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg);
+
+/**
  * Free the contents of argument list
  *
  * The structure itself is not freed
diff --git a/kernel/configure.ac b/kernel/configure.ac
index 0ef06f8..cdb2669 100644
--- a/kernel/configure.ac
+++ b/kernel/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT(fuse-kernel, 2.5.0)
+AC_INIT(fuse-kernel, 2.7.0-pre0)
 AC_CONFIG_HEADERS([config.h])
 
 AC_PROG_INSTALL
diff --git a/kernel/file.c b/kernel/file.c
index e8dae79..be9cc39 100644
--- a/kernel/file.c
+++ b/kernel/file.c
@@ -350,9 +350,14 @@
 	loff_t pos = page_offset(req->pages[0]);
 	size_t count = req->num_pages << PAGE_CACHE_SHIFT;
 	req->out.page_zeroing = 1;
-	req->end = fuse_readpages_end;
 	fuse_read_fill(req, file, inode, pos, count, FUSE_READ);
-	request_send_background(fc, req);
+	if (fc->async_read) {
+		req->end = fuse_readpages_end;
+		request_send_background(fc, req);
+	} else {
+		request_send(fc, req);
+		fuse_readpages_end(fc, req);
+	}
 }
 
 struct fuse_readpages_data {
diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h
index 4979fac..b37b6aa 100644
--- a/kernel/fuse_i.h
+++ b/kernel/fuse_i.h
@@ -369,6 +369,9 @@
 	    reply, before any other request, and never cleared */
 	unsigned conn_error : 1;
 
+	/** Do readpages asynchronously?  Only set in INIT */
+	unsigned async_read : 1;
+
 	/*
 	 * The following bitfields are only for optimization purposes
 	 * and hence races in setting them will not cause malfunction
diff --git a/kernel/fuse_kernel.h b/kernel/fuse_kernel.h
index 191b97d..54b1933 100644
--- a/kernel/fuse_kernel.h
+++ b/kernel/fuse_kernel.h
@@ -49,7 +49,7 @@
 #define FUSE_KERNEL_VERSION 7
 
 /** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 5
+#define FUSE_KERNEL_MINOR_VERSION 6
 
 /** The node ID of the root inode */
 #define FUSE_ROOT_ID 1
@@ -93,6 +93,9 @@
 	__u32	spare[6];
 };
 
+/**
+ * Bitmasks for fuse_setattr_in.valid
+ */
 #define FATTR_MODE	(1 << 0)
 #define FATTR_UID	(1 << 1)
 #define FATTR_GID	(1 << 2)
@@ -110,6 +113,11 @@
 #define FOPEN_DIRECT_IO		(1 << 0)
 #define FOPEN_KEEP_CACHE	(1 << 1)
 
+/**
+ * INIT request/reply flags
+ */
+#define FUSE_ASYNC_READ		(1 << 0)
+
 enum fuse_opcode {
 	FUSE_LOOKUP	   = 1,
 	FUSE_FORGET	   = 2,  /* no reply */
@@ -282,12 +290,16 @@
 struct fuse_init_in {
 	__u32	major;
 	__u32	minor;
+	__u32	max_readahead;
+	__u32	flags;
 };
 
 struct fuse_init_out {
 	__u32	major;
 	__u32	minor;
-	__u32	unused[3];
+	__u32	max_readahead;
+	__u32	flags;
+	__u32	unused;
 	__u32	max_write;
 };
 
diff --git a/kernel/inode.c b/kernel/inode.c
index f10990f..00a13cc 100644
--- a/kernel/inode.c
+++ b/kernel/inode.c
@@ -646,6 +646,19 @@
 	if (req->out.h.error || arg->major != FUSE_KERNEL_VERSION)
 		fc->conn_error = 1;
 	else {
+#ifdef KERNEL_2_6
+		unsigned long ra_pages;
+
+		if (arg->minor >= 6) {
+			ra_pages = arg->max_readahead / PAGE_CACHE_SIZE;
+			fc->async_read = arg->flags & FUSE_ASYNC_READ;
+		} else {
+			ra_pages = fc->max_read / PAGE_CACHE_SIZE;
+			fc->async_read = 0;
+		}
+
+		fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages);
+#endif
 		fc->minor = arg->minor;
 		fc->max_write = arg->minor < 5 ? 4096 : arg->max_write;
 	}
@@ -669,6 +682,10 @@
 
 	arg->major = FUSE_KERNEL_VERSION;
 	arg->minor = FUSE_KERNEL_MINOR_VERSION;
+#ifdef KERNEL_2_6
+	arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE;
+	arg->flags |= FUSE_ASYNC_READ;
+#endif
 	req->in.h.opcode = FUSE_INIT;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(*arg);
@@ -732,10 +749,6 @@
 	fc->user_id = d.user_id;
 	fc->group_id = d.group_id;
 	fc->max_read = d.max_read;
-#ifdef KERNEL_2_6
-	if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages)
-		fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE;
-#endif
 
 	/* Used by get_root_inode() */
 	sb->s_fs_info = fc;
diff --git a/lib/Makefile.am b/lib/Makefile.am
index d58cfed..366fcb0 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -22,7 +22,7 @@
 	helper.c		\
 	$(mount_source)
 
-libfuse_la_LDFLAGS = -lpthread -version-number 2:5:0 \
+libfuse_la_LDFLAGS = -lpthread -version-number 2:7:0 \
 	-Wl,--version-script,fuse_versionscript
 
 EXTRA_DIST = fuse_versionscript
diff --git a/lib/fuse.c b/lib/fuse.c
index 7d66a7d..2cfb436 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -553,7 +553,7 @@
         reply_err(req, err);
 }
 
-static void fuse_data_init(void *data)
+static void fuse_data_init(void *data, struct fuse_conn_info *conn)
 {
     struct fuse *f = (struct fuse *) data;
     struct fuse_context *c = fuse_get_context();
@@ -562,7 +562,7 @@
     c->fuse = f;
 
     if (f->op.init)
-        f->user_data = f->op.init();
+        f->user_data = f->op.init(conn);
 }
 
 static void fuse_data_destroy(void *data)
@@ -1808,7 +1808,6 @@
 
 enum {
     KEY_HELP,
-    KEY_KEEP
 };
 
 #define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v }
@@ -1816,8 +1815,8 @@
 static const struct fuse_opt fuse_lib_opts[] = {
     FUSE_OPT_KEY("-h",                    KEY_HELP),
     FUSE_OPT_KEY("--help",                KEY_HELP),
-    FUSE_OPT_KEY("debug",                 KEY_KEEP),
-    FUSE_OPT_KEY("-d",                    KEY_KEEP),
+    FUSE_OPT_KEY("debug",                 FUSE_OPT_KEY_KEEP),
+    FUSE_OPT_KEY("-d",                    FUSE_OPT_KEY_KEEP),
     FUSE_LIB_OPT("debug",                 debug, 1),
     FUSE_LIB_OPT("-d",                    debug, 1),
     FUSE_LIB_OPT("hard_remove",           hard_remove, 1),
@@ -1906,6 +1905,11 @@
     f->conf.readdir_ino = 1;
 #endif
 
+    if (compat && compat <= 25) {
+        if (fuse_sync_compat_args(args) == -1)
+            goto out_free;
+    }
+
     f->se = fuse_lowlevel_new(args, &fuse_path_ops, sizeof(fuse_path_ops), f);
     if (f->se == NULL)
         goto out_free;
@@ -2012,13 +2016,13 @@
     free(f);
 }
 
-#ifndef __FreeBSD__
-
 #include "fuse_compat.h"
 
+#ifndef __FreeBSD__
+
 static int fuse_do_open(struct fuse *f, char *path, struct fuse_file_info *fi)
 {
-    if (!f->compat)
+    if (!f->compat || f->compat >= 25)
         return f->op.open(path, fi);
     else if (f->compat == 22) {
         int err;
@@ -2045,7 +2049,7 @@
 static int fuse_do_opendir(struct fuse *f, char *path,
                            struct fuse_file_info *fi)
 {
-    if (!f->compat) {
+    if (!f->compat || f->compat >= 25) {
         return f->op.opendir(path, fi);
     } else {
         int err;
@@ -2085,7 +2089,7 @@
 {
     int err;
 
-    if (!f->compat) {
+    if (!f->compat || f->compat >= 25) {
         err = f->op.statfs(path, buf);
     } else if (f->compat > 11) {
         struct statfs oldbuf;
@@ -2179,3 +2183,13 @@
 }
 
 #endif /* __FreeBSD__ */
+
+struct fuse *fuse_new_compat25(int fd, struct fuse_args *args,
+                               const struct fuse_operations_compat25 *op,
+                               size_t op_size)
+{
+    return fuse_new_common(fd, args, (struct fuse_operations *) op,
+                           op_size, 25);
+}
+
+__asm__(".symver fuse_new_compat25,fuse_new@FUSE_2.5");
diff --git a/lib/fuse_i.h b/lib/fuse_i.h
index efbabf7..79c3cbf 100644
--- a/lib/fuse_i.h
+++ b/lib/fuse_i.h
@@ -22,3 +22,5 @@
 struct fuse *fuse_new_common(int fd, struct fuse_args *args,
                              const struct fuse_operations *op,
                              size_t op_size, int compat);
+
+int fuse_sync_compat_args(struct fuse_args *args);
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index 0bd6c99..13ddab9 100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -10,6 +10,7 @@
 #include "fuse_lowlevel.h"
 #include "fuse_kernel.h"
 #include "fuse_opt.h"
+#include "fuse_i.h"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -27,9 +28,8 @@
     struct fuse_lowlevel_ops op;
     int got_init;
     void *userdata;
-    int major;
-    int minor;
     uid_t owner;
+    struct fuse_conn_info conn;
 };
 
 struct fuse_req {
@@ -263,7 +263,7 @@
 
     /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant
        negative entry */
-    if (!e->ino && req->f->minor < 4)
+    if (!e->ino && req->f->conn.proto_minor < 4)
         return fuse_reply_err(req, ENOENT);
 
     memset(&arg, 0, sizeof(arg));
@@ -330,7 +330,7 @@
 int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
 {
     struct fuse_statfs_out arg;
-    size_t size = req->f->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(arg);
+    size_t size = req->f->conn.proto_minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(arg);
 
     memset(&arg, 0, sizeof(arg));
     convert_statfs(stbuf, &arg.st);
@@ -693,27 +693,51 @@
 
     if (f->debug) {
         printf("INIT: %u.%u\n", arg->major, arg->minor);
+        if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) {
+            printf("flags=0x%08x\n", arg->flags);
+            printf("max_readahead=0x%08x\n", arg->max_readahead);
+        }
         fflush(stdout);
     }
-    f->got_init = 1;
-    if (f->op.init)
-        f->op.init(f->userdata);
+    f->conn.proto_major = arg->major;
+    f->conn.proto_minor = arg->minor;
 
-    f->major = FUSE_KERNEL_VERSION;
-    f->minor = arg->minor;
+    if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) {
+        if (f->conn.async_read)
+            f->conn.async_read = arg->flags & FUSE_ASYNC_READ;
+        if (arg->max_readahead < f->conn.max_readahead)
+            f->conn.max_readahead = arg->max_readahead;
+    } else {
+        f->conn.async_read = 0;
+        f->conn.max_readahead = 0;
+    }
 
     if (bufsize < FUSE_MIN_READ_BUFFER) {
         fprintf(stderr, "fuse: warning: buffer size too small: %i\n", bufsize);
         bufsize = FUSE_MIN_READ_BUFFER;
     }
 
+    bufsize -= 4096;
+    if (bufsize < f->conn.max_write)
+        f->conn.max_write = bufsize;
+
+    f->got_init = 1;
+    if (f->op.init)
+        f->op.init(f->userdata, &f->conn);
+
     memset(&outarg, 0, sizeof(outarg));
-    outarg.major = f->major;
+    outarg.major = FUSE_KERNEL_VERSION;
     outarg.minor = FUSE_KERNEL_MINOR_VERSION;
-    outarg.max_write = bufsize - 4096;
+    if (f->conn.async_read)
+        outarg.flags |= FUSE_ASYNC_READ;
+    outarg.max_readahead = f->conn.max_readahead;
+    outarg.max_write = f->conn.max_write;
 
     if (f->debug) {
         printf("   INIT: %u.%u\n", outarg.major, outarg.minor);
+        printf("   flags=0x%08x\n", outarg.flags);
+        printf("   max_readahead=0x%08x\n", outarg.max_readahead);
+        printf("   max_write=0x%08x\n", outarg.max_write);
         fflush(stdout);
     }
 
@@ -902,6 +926,11 @@
     { "debug", offsetof(struct fuse_ll, debug), 1 },
     { "-d", offsetof(struct fuse_ll, debug), 1 },
     { "allow_root", offsetof(struct fuse_ll, allow_root), 1 },
+    { "max_write=%u", offsetof(struct fuse_ll, conn.max_write), 0 },
+    { "max_readahead=%u", offsetof(struct fuse_ll, conn.max_readahead), 0 },
+    { "async_read", offsetof(struct fuse_ll, conn.async_read), 1 },
+    { "sync_read", offsetof(struct fuse_ll, conn.async_read), 0 },
+    FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_DISCARD),
     FUSE_OPT_KEY("-h", KEY_HELP),
     FUSE_OPT_KEY("--help", KEY_HELP),
     FUSE_OPT_KEY("-V", KEY_VERSION),
@@ -915,6 +944,15 @@
             FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
 }
 
+static void fuse_ll_help(void)
+{
+    fprintf(stderr,
+"    -o max_write=N         set maximum size of write requests\n"
+"    -o max_readahead=N     set maximum readahead\n"
+"    -o async_read          perform reads asynchronously (default)\n"
+"    -o sync_read           perform reads synchronously\n");
+}
+
 static int fuse_ll_opt_proc(void *data, const char *arg, int key,
                             struct fuse_args *outargs)
 {
@@ -922,6 +960,7 @@
 
     switch (key) {
     case KEY_HELP:
+        fuse_ll_help();
         break;
 
     case KEY_VERSION:
@@ -972,6 +1011,10 @@
         goto out;
     }
 
+    f->conn.async_read = 1;
+    f->conn.max_write = UINT_MAX;
+    f->conn.max_readahead = UINT_MAX;
+
     if (fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1)
         goto out_free;
 
@@ -991,10 +1034,10 @@
     return NULL;
 }
 
-#ifndef __FreeBSD__
-
 #include "fuse_lowlevel_compat.h"
 
+#ifndef __FreeBSD__
+
 static void fill_open_compat(struct fuse_open_out *arg,
                       const struct fuse_file_info_compat *f)
 {
@@ -1062,3 +1105,49 @@
 __asm__(".symver fuse_lowlevel_new_compat,fuse_lowlevel_new@FUSE_2.4");
 
 #endif /* __FreeBSD__ */
+
+struct fuse_ll_compat_conf {
+    unsigned max_read;
+    int set_max_read;
+};
+
+static const struct fuse_opt fuse_ll_opts_compat[] = {
+    { "max_read=", offsetof(struct fuse_ll_compat_conf, set_max_read), 1 },
+    { "max_read=%u", offsetof(struct fuse_ll_compat_conf, max_read), 0 },
+    FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP),
+    FUSE_OPT_END
+};
+
+int fuse_sync_compat_args(struct fuse_args *args)
+{
+    struct fuse_ll_compat_conf conf;
+
+    if (fuse_opt_parse(args, &conf, fuse_ll_opts_compat, NULL) == -1)
+        return -1;
+
+    if (fuse_opt_insert_arg(args, 1, "-osync_read"))
+        return -1;
+
+    if (conf.set_max_read) {
+        char tmpbuf[64];
+
+        sprintf(tmpbuf, "-omax_readahead=%u", conf.max_read);
+        if (fuse_opt_insert_arg(args, 1, tmpbuf) == -1)
+            return -1;
+    }
+    return 0;
+}
+
+struct fuse_session *fuse_lowlevel_new_compat25(struct fuse_args *args,
+                        const struct fuse_lowlevel_ops_compat25 *op,
+                        size_t op_size, void *userdata)
+{
+    if (fuse_sync_compat_args(args) == -1)
+        return NULL;
+
+    return fuse_lowlevel_new(args, (const struct fuse_lowlevel_ops *) op,
+                             op_size, userdata);
+}
+
+
+__asm__(".symver fuse_lowlevel_new_compat25,fuse_lowlevel_new@FUSE_2.5");
diff --git a/lib/fuse_opt.c b/lib/fuse_opt.c
index 2ac499c..582c6ad 100644
--- a/lib/fuse_opt.c
+++ b/lib/fuse_opt.c
@@ -62,6 +62,21 @@
     return 0;
 }
 
+int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg)
+{
+    assert(pos <= args->argc);
+    if (fuse_opt_add_arg(args, arg) == -1)
+        return -1;
+
+    if (pos != args->argc - 1) {
+        char *newarg = args->argv[args->argc - 1];
+        memmove(&args->argv[pos + 1], &args->argv[pos],
+                sizeof(char *) * (args->argc - pos - 1));
+        args->argv[pos] = newarg;
+    }
+    return 0;
+}
+
 static int next_arg(struct fuse_opt_context *ctx, const char *opt)
 {
     if (ctx->argctr + 1 >= ctx->argc) {
@@ -102,25 +117,13 @@
     return fuse_opt_add_opt(&ctx->opts, opt);
 }
 
-static int insert_arg(struct fuse_opt_context *ctx, int pos, const char *arg)
-{
-    assert(pos <= ctx->outargs.argc);
-    if (add_arg(ctx, arg) == -1)
-        return -1;
-
-    if (pos != ctx->outargs.argc - 1) {
-        char *newarg = ctx->outargs.argv[ctx->outargs.argc - 1];
-        memmove(&ctx->outargs.argv[pos + 1], &ctx->outargs.argv[pos],
-                sizeof(char *) * (ctx->outargs.argc - pos - 1));
-        ctx->outargs.argv[pos] = newarg;
-    }
-    return 0;
-}
-
 static int call_proc(struct fuse_opt_context *ctx, const char *arg, int key,
                      int iso)
 {
-    if (ctx->proc) {
+    if (key == FUSE_OPT_KEY_DISCARD)
+        return 0;
+
+    if (key != FUSE_OPT_KEY_KEEP && ctx->proc) {
         int res = ctx->proc(ctx->data, arg, key, &ctx->outargs);
         if (res == -1 || !res)
             return res;
@@ -155,8 +158,8 @@
 static const struct fuse_opt *find_opt(const struct fuse_opt *opt,
                                        const char *arg, unsigned *sepp)
 {
-    for (; opt && opt->template; opt++)
-        if (match_template(opt->template, arg, sepp))
+    for (; opt && opt->templ; opt++)
+        if (match_template(opt->templ, arg, sepp))
             return opt;
     return NULL;
 }
@@ -195,11 +198,11 @@
             return -1;
     } else {
         void *var = ctx->data + opt->offset;
-        if (sep && opt->template[sep + 1]) {
+        if (sep && opt->templ[sep + 1]) {
             const char *param = arg + sep;
-            if (opt->template[sep] == '=')
+            if (opt->templ[sep] == '=')
                 param ++;
-            if (process_opt_param(var, opt->template + sep + 1,
+            if (process_opt_param(var, opt->templ + sep + 1,
                                   param, arg) == -1)
                 return -1;
         } else
@@ -239,7 +242,7 @@
     if (opt) {
         for (; opt; opt = find_opt(opt + 1, arg, &sep)) {
             int res;
-            if (sep && opt->template[sep] == ' ' && !arg[sep])
+            if (sep && opt->templ[sep] == ' ' && !arg[sep])
                 res = process_opt_sep_arg(ctx, opt, sep, arg, iso);
             else
                 res = process_opt(ctx, opt, sep, arg, iso);
@@ -321,12 +324,14 @@
             return -1;
 
     if (ctx->opts) {
-        if (insert_arg(ctx, 1, "-o") == -1 ||
-            insert_arg(ctx, 2, ctx->opts) == -1)
+        if (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 ||
+            fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1)
             return -1;
     }
-    if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc)
+    if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc) {
+        free(ctx->outargs.argv[ctx->outargs.argc - 1]);
         ctx->outargs.argv[--ctx->outargs.argc] = NULL;
+    }
 
     return 0;
 }
diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript
index 9927158..421228e 100644
--- a/lib/fuse_versionscript
+++ b/lib/fuse_versionscript
@@ -61,18 +61,16 @@
 
 FUSE_2.5 {
 	global:
-		fuse_lowlevel_new;
 		fuse_lowlevel_new_compat;
-		fuse_main_real;
 		fuse_main_real_compat22;
 		fuse_mount;
 		fuse_mount_compat22;
-		fuse_new;
 		fuse_new_compat22;
 		fuse_opt_parse;
 		fuse_opt_add_opt;
 		fuse_opt_add_arg;
 		fuse_opt_free_args;
+		fuse_opt_insert_arg;
 		fuse_opt_match;
 		fuse_parse_cmdline;
 		fuse_remove_signal_handlers;
@@ -81,10 +79,26 @@
 		fuse_reply_open_compat;
 		fuse_reply_statfs;
 		fuse_reply_statfs_compat;
-		fuse_setup;
 		fuse_setup_compat22;
 		fuse_set_signal_handlers;
+} FUSE_2.4;
+
+FUSE_2.6 {
+	global:
+		fuse_opt_insert_arg;
+} FUSE_2.5;
+
+FUSE_2.7 {
+	global:
+		fuse_lowlevel_new;
+		fuse_lowlevel_new_compat25;
+		fuse_main_real;
+		fuse_main_real_compat25;
+		fuse_new;
+		fuse_new_compat25;
+		fuse_setup;
+		fuse_setup_compat25;
 
 	local:
 		 *;
-} FUSE_2.4;
+} FUSE_2.6;
diff --git a/lib/helper.c b/lib/helper.c
index b7f77be..f937366 100644
--- a/lib/helper.c
+++ b/lib/helper.c
@@ -22,7 +22,6 @@
     KEY_HELP,
     KEY_HELP_NOHEADER,
     KEY_VERSION,
-    KEY_KEEP,
 };
 
 struct helper_opts {
@@ -46,8 +45,9 @@
     FUSE_OPT_KEY("-ho",         KEY_HELP_NOHEADER),
     FUSE_OPT_KEY("-V",          KEY_VERSION),
     FUSE_OPT_KEY("--version",   KEY_VERSION),
-    FUSE_OPT_KEY("-d",          KEY_KEEP),
-    FUSE_OPT_KEY("debug",       KEY_KEEP),
+    FUSE_OPT_KEY("-d",          FUSE_OPT_KEY_KEEP),
+    FUSE_OPT_KEY("debug",       FUSE_OPT_KEY_KEEP),
+    FUSE_OPT_KEY("fsname=",     FUSE_OPT_KEY_KEEP),
     FUSE_OPT_END
 };
 
@@ -100,11 +100,12 @@
     case FUSE_OPT_KEY_NONOPT:
         if (!hopts->mountpoint)
             return fuse_opt_add_opt(&hopts->mountpoint, arg);
-
-        /* fall through */
+        else {
+            fprintf(stderr, "fuse: invalid argument `%s'\n", arg);
+            return -1;
+        }
 
     default:
-    case KEY_KEEP:
         return 1;
     }
 }
@@ -289,10 +290,10 @@
     return -1;
 }
 
-#ifndef __FreeBSD__
-
 #include "fuse_compat.h"
 
+#ifndef __FreeBSD__
+
 struct fuse *fuse_setup_compat22(int argc, char *argv[],
                                  const struct fuse_operations_compat22 *op,
                                  size_t op_size, char **mountpoint,
@@ -341,3 +342,24 @@
 __asm__(".symver fuse_main_real_compat22,fuse_main_real@FUSE_2.2");
 
 #endif /* __FreeBSD__ */
+
+
+struct fuse *fuse_setup_compat25(int argc, char *argv[],
+                                 const struct fuse_operations_compat25 *op,
+                                 size_t op_size, char **mountpoint,
+                                 int *multithreaded, int *fd)
+{
+    return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
+                             op_size, mountpoint, multithreaded, fd, 25);
+}
+
+int fuse_main_real_compat25(int argc, char *argv[],
+                            const struct fuse_operations_compat25 *op,
+                            size_t op_size)
+{
+    return fuse_main_common(argc, argv, (struct fuse_operations *) op, op_size,
+                            25);
+}
+
+__asm__(".symver fuse_setup_compat25,fuse_setup@FUSE_2.5");
+__asm__(".symver fuse_main_real_compat25,fuse_main_real@FUSE_2.5");
diff --git a/lib/mount.c b/lib/mount.c
index 219ee14..2840a54 100644
--- a/lib/mount.c
+++ b/lib/mount.c
@@ -48,6 +48,7 @@
     FUSE_OPT_KEY("fsname=",             KEY_KERN),
     FUSE_OPT_KEY("large_read",          KEY_KERN),
     FUSE_OPT_KEY("max_read=",           KEY_KERN),
+    FUSE_OPT_KEY("max_read=",           FUSE_OPT_KEY_KEEP),
     FUSE_OPT_KEY("-r",                  KEY_RO),
     FUSE_OPT_KEY("ro",                  KEY_KERN),
     FUSE_OPT_KEY("rw",                  KEY_KERN),