performance improvements
diff --git a/kernel/dir.c b/kernel/dir.c
index 537b71c..a3f1485 100644
--- a/kernel/dir.c
+++ b/kernel/dir.c
@@ -79,29 +79,52 @@
 	return inode;
 }
 
+/* If the inode belongs to an existing directory, then it cannot be
+ assigned to new dentry */
+static int inode_ok(struct inode *inode)
+{
+	struct dentry *alias;
+	if(S_ISDIR(inode->i_mode) && (alias = d_find_alias(inode)) != NULL) {
+		dput(alias);
+		printk("fuse: cannot assign an existing directory\n");
+		return 0;
+
+	}
+	return 1;
+}
+
 static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
 {
 	int ret;
 	struct fuse_conn *fc = INO_FC(dir);
 	struct fuse_in in = FUSE_IN_INIT;
 	struct fuse_out out = FUSE_OUT_INIT;
-	struct fuse_lookup_out arg;
+	struct fuse_lookup_out outarg;
 	struct inode *inode;
 
 	in.h.opcode = FUSE_LOOKUP;
 	in.h.ino = dir->i_ino;
-	in.argsize = entry->d_name.len + 1;
-	in.arg = entry->d_name.name;
-	out.argsize = sizeof(arg);
-	out.arg = &arg;
+	in.numargs = 1;
+	in.args[0].size = entry->d_name.len + 1;
+	in.args[0].value = entry->d_name.name;
+	out.numargs = 1;
+	out.args[0].size = sizeof(outarg);
+	out.args[0].value = &outarg;
 	request_send(fc, &in, &out);
 	
 	inode = NULL;
 	if(!out.h.error) {
 		ret = -ENOMEM;
-		inode = fuse_iget(dir->i_sb, arg.ino, &arg.attr, out.h.unique);
+		inode = fuse_iget(dir->i_sb, outarg.ino, &outarg.attr,
+				  out.h.unique);
 		if(!inode) 
 			goto err;
+
+		ret = -EPROTO;
+		if(!inode_ok(inode)) {
+			iput(inode);
+			goto err;
+		}
 	}
 	else if(out.h.error != -ENOENT) {
 		ret = out.h.error;
@@ -126,28 +149,25 @@
 	struct fuse_conn *fc = INO_FC(dir);
 	struct fuse_in in = FUSE_IN_INIT;
 	struct fuse_out out = FUSE_OUT_INIT;
-	struct fuse_mknod_in *inarg;
-	unsigned int insize;
+	struct fuse_mknod_in inarg;
 	struct fuse_mknod_out outarg;
 	struct inode *inode;
-	
-	insize = offsetof(struct fuse_mknod_in, name) + entry->d_name.len + 1;
-	inarg = kmalloc(insize, GFP_KERNEL);
-	if(!inarg)
-		return -ENOMEM;
-	
-	inarg->mode = mode;
-	inarg->rdev = rdev;
-	strcpy(inarg->name, entry->d_name.name);
+
+	memset(&inarg, 0, sizeof(inarg));
+	inarg.mode = mode;
+	inarg.rdev = rdev;
 
 	in.h.opcode = FUSE_MKNOD;
 	in.h.ino = dir->i_ino;
-	in.argsize = insize;
-	in.arg = inarg;
-	out.argsize = sizeof(outarg);
-	out.arg = &outarg;
+	in.numargs = 2;
+	in.args[0].size = sizeof(inarg);
+	in.args[0].value = &inarg;
+	in.args[1].size = entry->d_name.len + 1;
+	in.args[1].value = entry->d_name.name;
+	out.numargs = 1;
+	out.args[0].size = sizeof(outarg);
+	out.args[0].value = &outarg;
 	request_send(fc, &in, &out);
-	kfree(inarg);
 
 	if(out.h.error) 
 		return out.h.error;
@@ -156,6 +176,18 @@
 	if(!inode) 
 		return -ENOMEM;
 
+	/* Don't allow userspace to do really stupid things... */
+	if((inode->i_mode ^ mode) & S_IFMT) {
+		iput(inode);
+		printk("fuse_mknod: inode has wrong type\n");
+		return -EPROTO;
+	}
+
+	if(!inode_ok(inode)) {
+		iput(inode);
+		return -EPROTO;
+	}
+
 	d_instantiate(entry, inode);
 	return 0;
 }
@@ -171,23 +203,19 @@
 	struct fuse_conn *fc = INO_FC(dir);
 	struct fuse_in in = FUSE_IN_INIT;
 	struct fuse_out out = FUSE_OUT_INIT;
-	struct fuse_mkdir_in *inarg;
-	unsigned int insize;
-	
-	insize = offsetof(struct fuse_mkdir_in, name) + entry->d_name.len + 1;
-	inarg = kmalloc(insize, GFP_KERNEL);
-	if(!inarg)
-		return -ENOMEM;
-	
-	inarg->mode = mode;
-	strcpy(inarg->name, entry->d_name.name);
+	struct fuse_mkdir_in inarg;
+
+	memset(&inarg, 0, sizeof(inarg));
+	inarg.mode = mode;
 
 	in.h.opcode = FUSE_MKDIR;
 	in.h.ino = dir->i_ino;
-	in.argsize = insize;
-	in.arg = inarg;
+	in.numargs = 2;
+	in.args[0].size = sizeof(inarg);
+	in.args[0].value = &inarg;
+	in.args[1].size = entry->d_name.len + 1;
+	in.args[1].value = entry->d_name.name;
 	request_send(fc, &in, &out);
-	kfree(inarg);
 
 	return out.h.error;
 }
@@ -198,24 +226,16 @@
 	struct fuse_conn *fc = INO_FC(dir);
 	struct fuse_in in = FUSE_IN_INIT;
 	struct fuse_out out = FUSE_OUT_INIT;
-	char *inarg;
-	unsigned int insize;
-	
-	insize = entry->d_name.len + 1 + strlen(link) + 1;
-	inarg = kmalloc(insize, GFP_KERNEL);
-	if(!inarg)
-		return -ENOMEM;
-	
-	strcpy(inarg, entry->d_name.name);
-	strcpy(inarg + entry->d_name.len + 1, link);
 
 	in.h.opcode = FUSE_SYMLINK;
 	in.h.ino = dir->i_ino;
-	in.argsize = insize;
-	in.arg = inarg;
+	in.numargs = 2;
+	in.args[0].size = entry->d_name.len + 1;
+	in.args[0].value = entry->d_name.name;
+	in.args[1].size = strlen(link) + 1;
+	in.args[1].value = link;
 	request_send(fc, &in, &out);
-	kfree(inarg);
-	
+
 	return out.h.error;
 }
 
@@ -228,9 +248,11 @@
 
 	in.h.opcode = op;
 	in.h.ino = dir->i_ino;
-	in.argsize = entry->d_name.len + 1;
-	in.arg = entry->d_name.name;
+	in.numargs = 1;
+	in.args[0].size = entry->d_name.len + 1;
+	in.args[0].value = entry->d_name.name;
 	request_send(fc, &in, &out);
+
 	return out.h.error;
 }
 
@@ -250,27 +272,21 @@
 	struct fuse_conn *fc = INO_FC(olddir);
 	struct fuse_in in = FUSE_IN_INIT;
 	struct fuse_out out = FUSE_OUT_INIT;
-	struct fuse_rename_in *inarg;
-	unsigned int oldnamsize = oldent->d_name.len + 1;
-	unsigned int newnamsize = newent->d_name.len + 1;
-	unsigned int insize;
+	struct fuse_rename_in inarg;
 	
-	insize = offsetof(struct fuse_rename_in, names) + oldnamsize +
-		newnamsize;
-	inarg = kmalloc(insize, GFP_KERNEL);
-	if(!inarg)
-		return -ENOMEM;
-	
-	inarg->newdir = newdir->i_ino;
-	strcpy(inarg->names, oldent->d_name.name);
-	strcpy(inarg->names + oldnamsize, newent->d_name.name);
+	memset(&inarg, 0, sizeof(inarg));
+	inarg.newdir = newdir->i_ino;
 
 	in.h.opcode = FUSE_RENAME;
 	in.h.ino = olddir->i_ino;
-	in.argsize = insize;
-	in.arg = inarg;
+	in.numargs = 3;
+	in.args[0].size = sizeof(inarg);
+	in.args[0].value = &inarg;
+	in.args[1].size = oldent->d_name.len + 1;
+	in.args[1].value = oldent->d_name.name;
+	in.args[2].size = newent->d_name.len + 1;
+	in.args[2].value = newent->d_name.name;
 	request_send(fc, &in, &out);
-	kfree(inarg);
 
 	return out.h.error;
 }
@@ -282,23 +298,19 @@
 	struct fuse_conn *fc = INO_FC(inode);
 	struct fuse_in in = FUSE_IN_INIT;
 	struct fuse_out out = FUSE_OUT_INIT;
-	struct fuse_link_in *inarg;
-	unsigned int insize;
+	struct fuse_link_in inarg;
 	
-	insize = offsetof(struct fuse_link_in, name) + newent->d_name.len + 1;
-	inarg = kmalloc(insize, GFP_KERNEL);
-	if(!inarg)
-		return -ENOMEM;
-	
-	inarg->newdir = newdir->i_ino;
-	strcpy(inarg->name, newent->d_name.name);
+	memset(&inarg, 0, sizeof(inarg));
+	inarg.newdir = newdir->i_ino;
 
 	in.h.opcode = FUSE_LINK;
 	in.h.ino = inode->i_ino;
-	in.argsize = insize;
-	in.arg = inarg;
+	in.numargs = 2;
+	in.args[0].size = sizeof(inarg);
+	in.args[0].value = &inarg;
+	in.args[1].size = newent->d_name.len + 1;
+	in.args[1].value = newent->d_name.name;
 	request_send(fc, &in, &out);
-	kfree(inarg);
 
 	return out.h.error;
 }
@@ -328,8 +340,9 @@
 
 	in.h.opcode = FUSE_GETATTR;
 	in.h.ino = inode->i_ino;
-	out.argsize = sizeof(arg);
-	out.arg = &arg;
+	out.numargs = 1;
+	out.args[0].size = sizeof(arg);
+	out.args[0].value = &arg;
 	request_send(fc, &in, &out);
 	
 	if(!out.h.error)
@@ -400,16 +413,17 @@
 
 	in.h.opcode = FUSE_READLINK;
 	in.h.ino = inode->i_ino;
-	out.arg = link;
-	out.argsize = PAGE_SIZE - 1;
 	out.argvar = 1;
+	out.numargs = 1;
+	out.args[0].size = PAGE_SIZE - 1;
+	out.args[0].value = link;
 	request_send(fc, &in, &out);
 	if(out.h.error) {
 		free_page((unsigned long) link);
 		return ERR_PTR(out.h.error);
 	}
 
-	link[out.argsize] = '\0';
+	link[out.args[0].size] = '\0';
 	return link;
 }
 
@@ -453,8 +467,9 @@
 	
 	in.h.opcode = FUSE_GETDIR;
 	in.h.ino = inode->i_ino;
-	out.argsize = sizeof(outarg);
-	out.arg = &outarg;
+	out.numargs = 1;
+	out.args[0].size = sizeof(outarg);
+	out.args[0].value = &outarg;
 	request_send(fc, &in, &out);
 	if(!out.h.error) {
 		struct file *cfile = outarg.file;
@@ -521,14 +536,17 @@
 	struct fuse_setattr_in inarg;
 	struct fuse_setattr_out outarg;
 
+	memset(&inarg, 0, sizeof(inarg));
 	inarg.valid = iattr_to_fattr(attr, &inarg.attr);
 	
 	in.h.opcode = FUSE_SETATTR;
 	in.h.ino = inode->i_ino;
-	in.argsize = sizeof(inarg);
-	in.arg = &inarg;
-	out.argsize = sizeof(outarg);
-	out.arg = &outarg;
+	in.numargs = 1;
+	in.args[0].size = sizeof(inarg);
+	in.args[0].value = &inarg;
+	out.numargs = 1;
+	out.args[0].size = sizeof(outarg);
+	out.args[0].value = &outarg;
 	request_send(fc, &in, &out);
 
 	if(!out.h.error) {