fix
diff --git a/kernel/dev.c b/kernel/dev.c
index d5fb2b6..4f1e8c0 100644
--- a/kernel/dev.c
+++ b/kernel/dev.c
@@ -188,6 +188,37 @@
 	spin_unlock(&fuse_lock);
 }
 
+static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
+{
+	int i;
+	struct fuse_init_out *arg = &req->misc.init_out;
+
+	if (arg->major != FUSE_KERNEL_VERSION)
+		fc->conn_error = 1;
+	else {
+		fc->minor = arg->minor;
+		if (fc->minor >= 5) {
+			fc->name_max = arg->name_max;
+			fc->symlink_max = arg->symlink_max;
+			fc->xattr_size_max = arg->xattr_size_max;
+			fc->max_write = arg->max_write;
+		} else {
+			/* Old fix values */
+			fc->name_max = 1024;
+			fc->symlink_max = 4096;
+			fc->xattr_size_max = 4096;
+			fc->max_write = 4096;
+		}
+	}
+
+	/* After INIT reply is received other requests can go
+	   out.  So do (FUSE_MAX_OUTSTANDING - 1) number of
+	   up()s on outstanding_sem.  The last up() is done in
+	   fuse_putback_request() */
+	for (i = 1; i < FUSE_MAX_OUTSTANDING; i++)
+		up(&fc->outstanding_sem);
+}
+
 /*
  * This function is called when a request is finished.  Either a reply
  * has arrived or it was interrupted (and not yet sent) or some error
@@ -212,21 +243,9 @@
 		up_read(&fc->sbput_sem);
 	}
 	wake_up(&req->waitq);
-	if (req->in.h.opcode == FUSE_INIT) {
-		int i;
-
-		if (req->misc.init_in_out.major != FUSE_KERNEL_VERSION)
-			fc->conn_error = 1;
-
-		fc->minor = req->misc.init_in_out.minor;
-
-		/* After INIT reply is received other requests can go
-		   out.  So do (FUSE_MAX_OUTSTANDING - 1) number of
-		   up()s on outstanding_sem.  The last up() is done in
-		   fuse_putback_request() */
-		for (i = 1; i < FUSE_MAX_OUTSTANDING; i++)
-			up(&fc->outstanding_sem);
-	} else if (req->in.h.opcode == FUSE_RELEASE && req->inode == NULL) {
+	if (req->in.h.opcode == FUSE_INIT)
+		process_init_reply(fc, req);
+	else if (req->in.h.opcode == FUSE_RELEASE && req->inode == NULL) {
 		/* Special case for failed iget in CREATE */
 		u64 nodeid = req->in.h.nodeid;
 		__fuse_get_request(req);
@@ -399,7 +418,7 @@
 	/* This is called from fuse_read_super() so there's guaranteed
 	   to be a request available */
 	struct fuse_req *req = do_get_request(fc);
-	struct fuse_init_in_out *arg = &req->misc.init_in_out;
+	struct fuse_init_in *arg = &req->misc.init_in;
 	arg->major = FUSE_KERNEL_VERSION;
 	arg->minor = FUSE_KERNEL_MINOR_VERSION;
 	req->in.h.opcode = FUSE_INIT;
@@ -407,8 +426,12 @@
 	req->in.args[0].size = sizeof(*arg);
 	req->in.args[0].value = arg;
 	req->out.numargs = 1;
-	req->out.args[0].size = sizeof(*arg);
-	req->out.args[0].value = arg;
+	/* Variable length arguement used for backward compatibility
+	   with interface version < 7.5.  Rest of init_out is zeroed
+	   by do_get_request(), so a short reply is not a problem */
+	req->out.argvar = 1;
+	req->out.args[0].size = sizeof(struct fuse_init_out);
+	req->out.args[0].value = &req->misc.init_out;
 	request_send_background(fc, req);
 }
 
diff --git a/kernel/dir.c b/kernel/dir.c
index 991edcf..3258d42 100644
--- a/kernel/dir.c
+++ b/kernel/dir.c
@@ -202,7 +202,7 @@
 	struct dentry *newent;
 #endif
 
-	if (entry->d_name.len > FUSE_NAME_MAX)
+	if (entry->d_name.len > fc->name_max)
 		return ERR_PTR(-ENAMETOOLONG);
 
 	req = fuse_get_request(fc);
@@ -274,7 +274,7 @@
 		goto out;
 
 	err = -ENAMETOOLONG;
-	if (entry->d_name.len > FUSE_NAME_MAX)
+	if (entry->d_name.len > fc->name_max)
 		goto out;
 
 	err = -EINTR;
@@ -455,7 +455,7 @@
 	unsigned len = strlen(link) + 1;
 	struct fuse_req *req;
 
-	if (len > FUSE_SYMLINK_MAX)
+	if (len > fc->symlink_max)
 		return -ENAMETOOLONG;
 
 	req = fuse_get_request(fc);
@@ -561,7 +561,8 @@
 			fuse_invalidate_attr(newdir);
 
 		/* newent will end up negative */
-		fuse_invalidate_entry_cache(newent);
+		if (newent->d_inode)
+			fuse_invalidate_entry_cache(newent);
 	} else if (err == -EINTR) {
 		/* If request was interrupted, DEITY only knows if the
 		   rename actually took place.  If the invalidation
@@ -798,11 +799,13 @@
 static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
 			 void *dstbuf, filldir_t filldir)
 {
+	struct fuse_conn *fc = get_fuse_conn(file->f_dentry->d_inode);
+
 	while (nbytes >= FUSE_NAME_OFFSET) {
 		struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
 		size_t reclen = FUSE_DIRENT_SIZE(dirent);
 		int over;
-		if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
+		if (!dirent->namelen || dirent->namelen > fc->name_max)
 			return -EIO;
 		if (reclen > nbytes)
 			break;
@@ -1125,7 +1128,7 @@
 	struct fuse_setxattr_in inarg;
 	int err;
 
-	if (size > FUSE_XATTR_SIZE_MAX)
+	if (size > fc->xattr_size_max)
 		return -E2BIG;
 
 	if (fc->no_setxattr)
diff --git a/kernel/file.c b/kernel/file.c
index a4cc04d..2365d2e 100644
--- a/kernel/file.c
+++ b/kernel/file.c
@@ -516,7 +516,12 @@
 	struct inode *inode = page->mapping->host;
 	struct fuse_conn *fc = get_fuse_conn(inode);
 	loff_t pos = page_offset(page) + offset;
-	struct fuse_req *req = fuse_get_request(fc);
+	struct fuse_req *req;
+
+	if (count > fc->max_write)
+		return -EIO;
+
+	req = fuse_get_request(fc);
 	if (!req)
 		return -EINTR;
 
diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h
index 9ae1eec..7f26b65 100644
--- a/kernel/fuse_i.h
+++ b/kernel/fuse_i.h
@@ -236,7 +236,8 @@
 	union {
 		struct fuse_forget_in forget_in;
 		struct fuse_release_in release_in;
-		struct fuse_init_in_out init_in_out;
+		struct fuse_init_in init_in;
+		struct fuse_init_out init_out;
 	} misc;
 
 	/** page vector */
@@ -284,6 +285,15 @@
 	/** Maximum write size */
 	unsigned max_write;
 
+	/** Maximum path segment length */
+	unsigned name_max;
+
+	/** Maximum symbolic link size */
+	unsigned symlink_max;
+
+	/** Maximum size of xattr data */
+	unsigned xattr_size_max;
+
 	/** Readers of the connection are waiting on this */
 	wait_queue_head_t waitq;
 
diff --git a/kernel/fuse_kernel.h b/kernel/fuse_kernel.h
index e43153e..26fff13 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 4
+#define FUSE_KERNEL_MINOR_VERSION 5
 
 /** The node ID of the root inode */
 #define FUSE_ROOT_ID 1
@@ -143,13 +143,6 @@
 	FUSE_CREATE        = 35
 };
 
-/* Conservative buffer size for the client */
-#define FUSE_MAX_IN 8192
-
-#define FUSE_NAME_MAX 1024
-#define FUSE_SYMLINK_MAX 4096
-#define FUSE_XATTR_SIZE_MAX 4096
-
 struct fuse_entry_out {
 	__u64	nodeid;		/* Inode ID */
 	__u64	generation;	/* Inode generation: nodeid:gen must
@@ -283,11 +276,20 @@
 	__u32	padding;
 };
 
-struct fuse_init_in_out {
+struct fuse_init_in {
 	__u32	major;
 	__u32	minor;
 };
 
+struct fuse_init_out {
+	__u32	major;
+	__u32	minor;
+	__u32	name_max;
+	__u32	symlink_max;
+	__u32	xattr_size_max;
+	__u32	max_write;
+};
+
 struct fuse_in_header {
 	__u32	len;
 	__u32	opcode;
diff --git a/kernel/inode.c b/kernel/inode.c
index 1d56566..8c7c7d6 100644
--- a/kernel/inode.c
+++ b/kernel/inode.c
@@ -647,7 +647,6 @@
 	if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages)
 		fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE;
 #endif
-	fc->max_write = FUSE_MAX_IN / 2;
 
 	err = -ENOMEM;
 	root = get_root_inode(sb, d.rootmode);