interrupted request improvements
diff --git a/kernel/inode.c b/kernel/inode.c
index ac80b63..eb40b7b 100644
--- a/kernel/inode.c
+++ b/kernel/inode.c
@@ -24,14 +24,19 @@
 #endif
 
 static kmem_cache_t *fuse_inode_cachep;
+static int mount_count;
 
 static int user_allow_other;
+static int mount_max = 1000;
 #ifdef KERNEL_2_6
 module_param(user_allow_other, int, 0644);
+module_param(mount_max, int, 0644);
 #else
 MODULE_PARM(user_allow_other, "i");
+MODULE_PARM(mount_max, "i");
 #endif
 MODULE_PARM_DESC(user_allow_other, "Allow non root user to specify the \"allow_other\" or \"allow_root\" mount options");
+MODULE_PARM_DESC(mount_max, "Maximum number of FUSE mounts allowed, if -1 then unlimited (default: 1000)");
 
 #define FUSE_SUPER_MAGIC 0x65735546
 
@@ -112,11 +117,155 @@
 	}
 }
 
+void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
+{
+	if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size)
+#ifdef KERNEL_2_6
+		invalidate_inode_pages(inode->i_mapping);
+#else
+		invalidate_inode_pages(inode);
+#endif
+
+	inode->i_ino     = attr->ino;
+	inode->i_mode    = (inode->i_mode & S_IFMT) + (attr->mode & 07777);
+	inode->i_nlink   = attr->nlink;
+	inode->i_uid     = attr->uid;
+	inode->i_gid     = attr->gid;
+	i_size_write(inode, attr->size);
+	inode->i_blksize = PAGE_CACHE_SIZE;
+	inode->i_blocks  = attr->blocks;
+#ifdef KERNEL_2_6
+	inode->i_atime.tv_sec   = attr->atime;
+	inode->i_atime.tv_nsec  = attr->atimensec;
+	inode->i_mtime.tv_sec   = attr->mtime;
+	inode->i_mtime.tv_nsec  = attr->mtimensec;
+	inode->i_ctime.tv_sec   = attr->ctime;
+	inode->i_ctime.tv_nsec  = attr->ctimensec;
+#else
+	inode->i_atime   = attr->atime;
+	inode->i_mtime   = attr->mtime;
+	inode->i_ctime   = attr->ctime;
+#endif
+}
+
+static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
+{
+	inode->i_mode = attr->mode & S_IFMT;
+	i_size_write(inode, attr->size);
+	if (S_ISREG(inode->i_mode)) {
+		fuse_init_common(inode);
+		fuse_init_file_inode(inode);
+	} else if (S_ISDIR(inode->i_mode))
+		fuse_init_dir(inode);
+	else if (S_ISLNK(inode->i_mode))
+		fuse_init_symlink(inode);
+	else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
+		 S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
+		fuse_init_common(inode);
+		init_special_inode(inode, inode->i_mode,
+				   new_decode_dev(attr->rdev));
+	} else {
+		/* Don't let user create weird files */
+		inode->i_mode = S_IFREG;
+		fuse_init_common(inode);
+		fuse_init_file_inode(inode);
+	}
+}
+
+#ifdef KERNEL_2_6
+static int fuse_inode_eq(struct inode *inode, void *_nodeidp)
+{
+	unsigned long nodeid = *(unsigned long *) _nodeidp;
+	if (get_node_id(inode) == nodeid)
+		return 1;
+	else
+		return 0;
+}
+
+static int fuse_inode_set(struct inode *inode, void *_nodeidp)
+{
+	unsigned long nodeid = *(unsigned long *) _nodeidp;
+	get_fuse_inode(inode)->nodeid = nodeid;
+	return 0;
+}
+
+struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
+			int generation, struct fuse_attr *attr, int version)
+{
+	struct inode *inode;
+	struct fuse_conn *fc = get_fuse_conn_super(sb);
+	int retried = 0;
+
+ retry:
+	inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid);
+	if (!inode)
+		return NULL;
+
+	if ((inode->i_state & I_NEW)) {
+		inode->i_generation = generation;
+		inode->i_data.backing_dev_info = &fc->bdi;
+		fuse_init_inode(inode, attr);
+		unlock_new_inode(inode);
+	} else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
+		BUG_ON(retried);
+		/* Inode has changed type, any I/O on the old should fail */
+		make_bad_inode(inode);
+		iput(inode);
+		retried = 1;
+		goto retry;
+	}
+
+	fuse_change_attributes(inode, attr);
+	inode->i_version = version;
+	return inode;
+}
+#else
+static int fuse_inode_eq(struct inode *inode, unsigned long ino, void *_nodeidp){
+	unsigned long nodeid = *(unsigned long *) _nodeidp;
+	if (inode->u.generic_ip && get_node_id(inode) == nodeid)
+		return 1;
+	else
+		return 0;
+}
+
+struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
+			int generation, struct fuse_attr *attr, int version)
+{
+	struct inode *inode;
+	int retried = 0;
+
+ retry:
+	inode = iget4(sb, attr->ino, fuse_inode_eq, &nodeid);
+	if (!inode)
+		return NULL;
+
+	if (!inode->u.generic_ip) {
+		get_fuse_inode(inode)->nodeid = nodeid;
+		inode->u.generic_ip = inode;
+		inode->i_generation = generation;
+		fuse_init_inode(inode, attr);
+	} else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
+		BUG_ON(retried);
+		/* Inode has changed type, any I/O on the old should fail */
+		remove_inode_hash(inode);
+		make_bad_inode(inode);
+		iput(inode);
+		retried = 1;
+		goto retry;
+	}
+
+	fuse_change_attributes(inode, attr);
+	inode->i_version = version;
+	return inode;
+}
+#endif
+
 static void fuse_put_super(struct super_block *sb)
 {
 	struct fuse_conn *fc = get_fuse_conn_super(sb);
 
 	spin_lock(&fuse_lock);
+	mount_count --;
 	fc->sb = NULL;
 	fc->uid = 0;
 	fc->flags = 0;
@@ -329,7 +478,7 @@
 		INIT_LIST_HEAD(&fc->pending);
 		INIT_LIST_HEAD(&fc->processing);
 		INIT_LIST_HEAD(&fc->unused_list);
-		sema_init(&fc->unused_sem, FUSE_MAX_OUTSTANDING);
+		sema_init(&fc->outstanding_sem, FUSE_MAX_OUTSTANDING);
 		for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) {
 			struct fuse_req *req = fuse_request_alloc();
 			if (!req) {
@@ -392,7 +541,7 @@
 	if (nodeid == 0)
 		return ERR_PTR(-ESTALE);
 
-	inode = fuse_ilookup(sb, nodeid);
+	inode = ilookup5(sb, nodeid, fuse_inode_eq, &nodeid);
 	if (!inode || inode->i_generation != generation)
 		return ERR_PTR(-ESTALE);
 
@@ -449,12 +598,24 @@
 	.show_options	= fuse_show_options,
 };
 
+static int inc_mount_count(void)
+{
+	int success = 0;
+	spin_lock(&fuse_lock);
+	mount_count ++;
+	if (mount_max == -1 || mount_count <= mount_max)
+		success = 1;
+	spin_unlock(&fuse_lock);
+	return success;
+}
+
 static int fuse_read_super(struct super_block *sb, void *data, int silent)
 {
 	struct fuse_conn *fc;
 	struct inode *root;
 	struct fuse_mount_data d;
 	struct file *file;
+	int err;
 
 	if (!parse_fuse_opt((char *) data, &d))
 		return -EINVAL;
@@ -493,6 +654,11 @@
 
 	*get_fuse_conn_super_p(sb) = fc;
 
+	err = -ENFILE;
+	if (!inc_mount_count() && current->uid != 0)
+		goto err;
+
+	err = -ENOMEM;
 	root = get_root_inode(sb, d.rootmode);
 	if (root == NULL)
 		goto err;
@@ -507,11 +673,12 @@
 
  err:
 	spin_lock(&fuse_lock);
+	mount_count --;
 	fc->sb = NULL;
 	fuse_release_conn(fc);
 	spin_unlock(&fuse_lock);
 	*get_fuse_conn_super_p(sb) = NULL;
-	return -EINVAL;
+	return err;
 }
 
 #ifdef KERNEL_2_6