added support for setting the st_ino field
diff --git a/ChangeLog b/ChangeLog
index 0781488..450d956 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2004-11-02  Miklos Szeredi <miklos@szeredi.hu>
+
+	* Added "use_ino" mount option.  This enables the filesystems to
+	set the st_ino field on files
+
 2004-11-01  Miklos Szeredi <miklos@szeredi.hu>
 
 	* Fix compile problems with ancient (<=2.4.18) kernels (reported
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index 21ecc47..e5f9a6c 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -9,13 +9,13 @@
 /* This file defines the kernel interface of FUSE */
 
 /** Version number of this interface */
-#define FUSE_KERNEL_VERSION 3
+#define FUSE_KERNEL_VERSION 4
 
 /** Minor version number of this interface */
 #define FUSE_KERNEL_MINOR_VERSION 1
 
-/** The inode number of the root indode */
-#define FUSE_ROOT_INO 1
+/** The node ID of the root inode */
+#define FUSE_ROOT_ID 1
 
 /** Opening this will yield a new control file */
 #define FUSE_DEV "/proc/fs/fuse/dev"
@@ -24,6 +24,7 @@
 #define FUSE_VERSION_FILE "/proc/fs/fuse/version"
 
 struct fuse_attr {
+	unsigned long       ino;
 	unsigned int        mode;
 	unsigned int        nlink;
 	unsigned int        uid;
@@ -93,8 +94,8 @@
 #define FUSE_XATTR_SIZE_MAX 4096
 
 struct fuse_entry_out {
-	unsigned long ino;         /* Inode number */
-	unsigned long generation;  /* Inode generation: ino:gen must
+	unsigned long nodeid;      /* Inode ID */
+	unsigned long generation;  /* Inode generation: nodeid:gen must
                                       be unique for the fs's lifetime */
 	unsigned long entry_valid; /* Cache timeout for the name */
 	unsigned long entry_valid_nsec;
@@ -198,7 +199,7 @@
 struct fuse_in_header {
 	int unique;
 	enum fuse_opcode opcode;
-	unsigned long ino;
+	unsigned long nodeid;
 	unsigned int uid;
 	unsigned int gid;
 	unsigned int pid;
@@ -212,7 +213,9 @@
 struct fuse_user_header {
 	int unique; /* zero */
 	enum fuse_opcode opcode;
-	unsigned long ino;
+	unsigned long nodeid;
+	unsigned long ino;  /* Needed only on 2.4.x where ino is also
+			       used for inode lookup */
 };
 
 struct fuse_dirent {
diff --git a/kernel/dev.c b/kernel/dev.c
index c783ead..2e081d0 100644
--- a/kernel/dev.c
+++ b/kernel/dev.c
@@ -433,33 +433,21 @@
 	return 0;
 }
 
-#ifdef KERNEL_2_6
 static int fuse_invalidate(struct fuse_conn *fc, struct fuse_user_header *uh)
 {
-	struct inode *inode = ilookup(fc->sb, uh->ino);
+	struct inode *inode = fuse_ilookup(fc, uh->ino, uh->nodeid);
 	if (!inode)
 		return -ENOENT;
 	fuse_sync_inode(inode);
+#ifdef KERNEL_2_6
 	invalidate_inode_pages(inode->i_mapping);
+#else
+	invalidate_inode_pages(inode);
+#endif
+
 	iput(inode);
 	return 0;
 }
-#else 
-static int fuse_invalidate(struct fuse_conn *fc, struct fuse_user_header *uh)
-{
-	struct inode *inode = iget(fc->sb, uh->ino);
-	int err = -ENOENT;
-	if (inode) {
-		if (INO_FI(inode)) {
-			fuse_sync_inode(inode);
-			invalidate_inode_pages(inode);
-			err = 0;
-		}
-		iput(inode);
-	}
-	return err;
-}
-#endif
 
 static int fuse_user_request(struct fuse_conn *fc, const char *buf,
 			     size_t nbytes)
diff --git a/kernel/dir.c b/kernel/dir.c
index 36eb3bf..ce6df5d 100644
--- a/kernel/dir.c
+++ b/kernel/dir.c
@@ -35,6 +35,7 @@
 #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;
@@ -80,40 +81,102 @@
 		printk("fuse_init_inode: bad file type: %o\n", inode->i_mode);
 }
 
-struct inode *fuse_iget(struct super_block *sb, ino_t ino, int generation,
-			struct fuse_attr *attr, int version)
+#ifdef KERNEL_2_6
+static int fuse_inode_eq(struct inode *inode, void *_nodeidp)
+{
+	unsigned long nodeid = *(unsigned long *) _nodeidp;
+	struct fuse_inode *fi = INO_FI(inode);
+	if (fi->nodeid == nodeid)
+		return 1;
+	else
+		return 0;
+}
+
+static int fuse_inode_set(struct inode *inode, void *_nodeidp)
+{
+	unsigned long nodeid = *(unsigned long *) _nodeidp;
+	struct fuse_inode *fi = INO_FI(inode);
+	fi->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;
 
-	inode = iget(sb, ino);
-	if (inode) {
-		if (!INO_FI(inode)) {
-			struct fuse_inode *fi = fuse_inode_alloc();
-			if (!fi) {
-				iput(inode);
-				inode = NULL;
-				goto out;
-			}
-			INO_FI(inode) = fi;
-			inode->i_generation = generation;
-			fuse_init_inode(inode, attr);
-		} else if (inode->i_generation != generation)
-			printk("fuse_iget: bad generation for ino %lu\n", ino);
+	inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid);
+	if (!inode)
+		return NULL;
 
-		change_attributes(inode, attr);
-		inode->i_version = version;
-	}
- out:
+	if ((inode->i_state & I_NEW)) {
+		inode->i_generation = generation;
+		fuse_init_inode(inode, attr);
+		unlock_new_inode(inode);
+	} else if (inode->i_generation != generation)
+		printk("fuse_iget: bad generation for node %lu\n", nodeid);
 
+	change_attributes(inode, attr);
+	inode->i_version = version;
 	return inode;
 }
 
+struct inode *fuse_ilookup(struct fuse_conn *fc, ino_t ino, unsigned long nodeid)
+{
+	return ilookup5(fc->sb, nodeid, fuse_inode_eq, &nodeid);
+}
+#else
+static int fuse_inode_eq(struct inode *inode, unsigned long ino, void *_nodeidp){
+	unsigned long nodeid = *(unsigned long *) _nodeidp;
+	struct fuse_inode *fi = INO_FI(inode);
+	if (inode->u.generic_ip && fi->nodeid == 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;
+
+	inode = iget4(sb, attr->ino, fuse_inode_eq, &nodeid);
+	if (!inode)
+		return NULL;
+
+	if (!inode->u.generic_ip) {
+		struct fuse_inode *fi = INO_FI(inode);
+		fi->nodeid = nodeid;
+		inode->u.generic_ip = inode;
+		inode->i_generation = generation;
+		fuse_init_inode(inode, attr);
+	} else if (inode->i_generation != generation)
+		printk("fuse_iget: bad generation for node %lu\n", nodeid);
+
+	change_attributes(inode, attr);
+	inode->i_version = version;
+	return inode;
+}
+
+struct inode *fuse_ilookup(struct fuse_conn *fc, ino_t ino, unsigned long nodeid)
+{
+	struct inode *inode = iget4(fc->sb, ino, fuse_inode_eq, &nodeid);
+	if (inode && !inode->u.generic_ip) {
+		iput(inode);
+		inode = NULL;
+	}
+	return inode;
+}
+
+#endif
+
 static int fuse_send_lookup(struct fuse_conn *fc, struct fuse_req *req,
 			    struct inode *dir, struct dentry *entry, 
 			    struct fuse_entry_out *outarg, int *version)
 {
+	struct fuse_inode *fi = INO_FI(dir);
 	req->in.h.opcode = FUSE_LOOKUP;
-	req->in.h.ino = dir->i_ino;
+	req->in.h.nodeid = fi->nodeid;
 	req->in.numargs = 1;
 	req->in.args[0].size = entry->d_name.len + 1;
 	req->in.args[0].value = entry->d_name.name;
@@ -171,10 +234,10 @@
 
 	err = fuse_send_lookup(fc, req, dir, entry, &outarg, &version);
 	if (!err) {
-		inode = fuse_iget(dir->i_sb, outarg.ino, outarg.generation,
+		inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
 				  &outarg.attr, version);
 		if (!inode) {
-			fuse_send_forget(fc, req, outarg.ino, version);
+			fuse_send_forget(fc, req, outarg.nodeid, version);
 			return -ENOMEM;
 		}
 	} 
@@ -208,10 +271,10 @@
 {
 	struct inode *inode;
 	struct fuse_inode *fi;
-	inode = fuse_iget(dir->i_sb, outarg->ino, outarg->generation, 
+	inode = fuse_iget(dir->i_sb, outarg->nodeid, outarg->generation, 
 			  &outarg->attr, version);
 	if (!inode) {
-		fuse_send_forget(fc, req, outarg->ino, version);
+		fuse_send_forget(fc, req, outarg->nodeid, version);
 		return -ENOMEM;
 	}
 	fuse_put_request(fc, req);
@@ -240,6 +303,7 @@
 		      dev_t rdev)
 {
 	struct fuse_conn *fc = INO_FC(dir);
+	struct fuse_inode *fi = INO_FI(dir);
 	struct fuse_req *req = fuse_get_request(fc);
 	struct fuse_mknod_in inarg;
 	struct fuse_entry_out outarg;
@@ -252,7 +316,7 @@
 	inarg.mode = mode;
 	inarg.rdev = new_encode_dev(rdev);
 	req->in.h.opcode = FUSE_MKNOD;
-	req->in.h.ino = dir->i_ino;
+	req->in.h.nodeid = fi->nodeid;
 	req->in.numargs = 2;
 	req->in.args[0].size = sizeof(inarg);
 	req->in.args[0].value = &inarg;
@@ -280,6 +344,7 @@
 static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
 {
 	struct fuse_conn *fc = INO_FC(dir);
+	struct fuse_inode *fi = INO_FI(dir);
 	struct fuse_req *req = fuse_get_request(fc);
 	struct fuse_mkdir_in inarg;
 	struct fuse_entry_out outarg;
@@ -291,7 +356,7 @@
 	memset(&inarg, 0, sizeof(inarg));
 	inarg.mode = mode;
 	req->in.h.opcode = FUSE_MKDIR;
-	req->in.h.ino = dir->i_ino;
+	req->in.h.nodeid = fi->nodeid;
 	req->in.numargs = 2;
 	req->in.args[0].size = sizeof(inarg);
 	req->in.args[0].value = &inarg;
@@ -314,6 +379,7 @@
 			const char *link)
 {
 	struct fuse_conn *fc = INO_FC(dir);
+	struct fuse_inode *fi = INO_FI(dir);
 	struct fuse_req *req;
 	struct fuse_entry_out outarg;
 	unsigned int len = strlen(link) + 1;
@@ -327,7 +393,7 @@
 		return -ERESTARTSYS;
 
 	req->in.h.opcode = FUSE_SYMLINK;
-	req->in.h.ino = dir->i_ino;
+	req->in.h.nodeid = fi->nodeid;
 	req->in.numargs = 2;
 	req->in.args[0].size = entry->d_name.len + 1;
 	req->in.args[0].value = entry->d_name.name;
@@ -349,6 +415,7 @@
 static int fuse_unlink(struct inode *dir, struct dentry *entry)
 {
 	struct fuse_conn *fc = INO_FC(dir);
+	struct fuse_inode *fi = INO_FI(dir);
 	struct fuse_req *req = fuse_get_request(fc);
 	int err;
 	
@@ -356,7 +423,7 @@
 		return -ERESTARTSYS;
 
 	req->in.h.opcode = FUSE_UNLINK;
-	req->in.h.ino = dir->i_ino;
+	req->in.h.nodeid = fi->nodeid;
 	req->in.numargs = 1;
 	req->in.args[0].size = entry->d_name.len + 1;
 	req->in.args[0].value = entry->d_name.name;
@@ -379,6 +446,7 @@
 static int fuse_rmdir(struct inode *dir, struct dentry *entry)
 {
 	struct fuse_conn *fc = INO_FC(dir);
+	struct fuse_inode *fi = INO_FI(dir);
 	struct fuse_req *req = fuse_get_request(fc);
 	int err;
 	
@@ -386,7 +454,7 @@
 		return -ERESTARTSYS;
 
 	req->in.h.opcode = FUSE_RMDIR;
-	req->in.h.ino = dir->i_ino;
+	req->in.h.nodeid = fi->nodeid;
 	req->in.numargs = 1;
 	req->in.args[0].size = entry->d_name.len + 1;
 	req->in.args[0].value = entry->d_name.name;
@@ -404,6 +472,8 @@
 		       struct inode *newdir, struct dentry *newent)
 {
 	struct fuse_conn *fc = INO_FC(olddir);
+	struct fuse_inode *oldfi = INO_FI(olddir);
+	struct fuse_inode *newfi = INO_FI(newdir);
 	struct fuse_req *req = fuse_get_request(fc);
 	struct fuse_rename_in inarg;
 	int err;
@@ -412,9 +482,9 @@
 		return -ERESTARTSYS;
 
 	memset(&inarg, 0, sizeof(inarg));
-	inarg.newdir = newdir->i_ino;
+	inarg.newdir = newfi->nodeid;
 	req->in.h.opcode = FUSE_RENAME;
-	req->in.h.ino = olddir->i_ino;
+	req->in.h.nodeid = oldfi->nodeid;
 	req->in.numargs = 3;
 	req->in.args[0].size = sizeof(inarg);
 	req->in.args[0].value = &inarg;
@@ -438,6 +508,8 @@
 {
 	struct inode *inode = entry->d_inode;
 	struct fuse_conn *fc = INO_FC(inode);
+	struct fuse_inode *fi = INO_FI(inode);
+	struct fuse_inode *newfi = INO_FI(newdir);
 	struct fuse_req *req = fuse_get_request(fc);
 	struct fuse_link_in inarg;
 	struct fuse_entry_out outarg;
@@ -447,9 +519,9 @@
 		return -ERESTARTSYS;
 
 	memset(&inarg, 0, sizeof(inarg));
-	inarg.newdir = newdir->i_ino;
+	inarg.newdir = newfi->nodeid;
 	req->in.h.opcode = FUSE_LINK;
-	req->in.h.ino = inode->i_ino;
+	req->in.h.nodeid = fi->nodeid;
 	req->in.numargs = 2;
 	req->in.args[0].size = sizeof(inarg);
 	req->in.args[0].value = &inarg;
@@ -482,7 +554,7 @@
 		return -ERESTARTSYS;
 
 	req->in.h.opcode = FUSE_GETATTR;
-	req->in.h.ino = inode->i_ino;
+	req->in.h.nodeid = fi->nodeid;
 	req->out.numargs = 1;
 	req->out.args[0].size = sizeof(arg);
 	req->out.args[0].value = &arg;
@@ -503,7 +575,7 @@
 	struct fuse_inode *fi = INO_FI(inode);
 	struct fuse_conn *fc = INO_FC(inode);
 
-	if (inode->i_ino == FUSE_ROOT_INO) {
+	if (fi->nodeid == FUSE_ROOT_ID) {
 		if (!(fc->flags & FUSE_ALLOW_OTHER) &&
 		    current->fsuid != fc->uid &&
 		    (!(fc->flags & FUSE_ALLOW_ROOT) ||
@@ -598,6 +670,7 @@
 {
 	struct inode *inode = file->f_dentry->d_inode;
 	struct fuse_conn *fc = INO_FC(inode);
+	struct fuse_inode *fi = INO_FI(inode);
 	struct fuse_req *req = fuse_get_request(fc);
 	struct fuse_getdir_out_i outarg;
 	int err;
@@ -606,7 +679,7 @@
 		return -ERESTARTSYS;
 
 	req->in.h.opcode = FUSE_GETDIR;
-	req->in.h.ino = inode->i_ino;
+	req->in.h.nodeid = fi->nodeid;
 	req->out.numargs = 1;
 	req->out.args[0].size = sizeof(struct fuse_getdir_out);
 	req->out.args[0].value = &outarg;
@@ -651,6 +724,7 @@
 {
 	struct inode *inode = dentry->d_inode;
 	struct fuse_conn *fc = INO_FC(inode);
+	struct fuse_inode *fi = INO_FI(inode);
 	struct fuse_req *req = fuse_get_request(fc);
 	char *link;
 
@@ -663,7 +737,7 @@
 		goto out;
 	}
 	req->in.h.opcode = FUSE_READLINK;
-	req->in.h.ino = inode->i_ino;
+	req->in.h.nodeid = fi->nodeid;
 	req->out.argvar = 1;
 	req->out.numargs = 1;
 	req->out.args[0].size = PAGE_SIZE - 1;
@@ -793,7 +867,7 @@
 	memset(&inarg, 0, sizeof(inarg));
 	inarg.valid = iattr_to_fattr(attr, &inarg.attr);
 	req->in.h.opcode = FUSE_SETATTR;
-	req->in.h.ino = inode->i_ino;
+	req->in.h.nodeid = fi->nodeid;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(inarg);
 	req->in.args[0].value = &inarg;
@@ -837,7 +911,7 @@
 		if (ret)
 			return 0;
 		
-		if (outarg.ino != inode->i_ino)
+		if (outarg.nodeid != fi->nodeid)
 			return 0;
 		
 		change_attributes(inode, &outarg.attr);
@@ -942,6 +1016,7 @@
 {
 	struct inode *inode = entry->d_inode;
 	struct fuse_conn *fc = INO_FC(inode);
+	struct fuse_inode *fi = INO_FI(inode);
 	struct fuse_req *req;
 	struct fuse_setxattr_in inarg;
 	int err;
@@ -960,7 +1035,7 @@
 	inarg.size = size;
 	inarg.flags = flags;
 	req->in.h.opcode = FUSE_SETXATTR;
-	req->in.h.ino = inode->i_ino;
+	req->in.h.nodeid = fi->nodeid;
 	req->in.numargs = 3;
 	req->in.args[0].size = sizeof(inarg);
 	req->in.args[0].value = &inarg;
@@ -983,6 +1058,7 @@
 {
 	struct inode *inode = entry->d_inode;
 	struct fuse_conn *fc = INO_FC(inode);
+	struct fuse_inode *fi = INO_FI(inode);
 	struct fuse_req *req;
 	struct fuse_getxattr_in inarg;
 	struct fuse_getxattr_out outarg;
@@ -998,7 +1074,7 @@
 	memset(&inarg, 0, sizeof(inarg));
 	inarg.size = size;
 	req->in.h.opcode = FUSE_GETXATTR;
-	req->in.h.ino = inode->i_ino;
+	req->in.h.nodeid = fi->nodeid;
 	req->in.numargs = 2;
 	req->in.args[0].size = sizeof(inarg);
 	req->in.args[0].value = &inarg;
@@ -1032,6 +1108,7 @@
 {
 	struct inode *inode = entry->d_inode;
 	struct fuse_conn *fc = INO_FC(inode);
+	struct fuse_inode *fi = INO_FI(inode);
 	struct fuse_req *req;
 	struct fuse_getxattr_in inarg;
 	struct fuse_getxattr_out outarg;
@@ -1047,7 +1124,7 @@
 	memset(&inarg, 0, sizeof(inarg));
 	inarg.size = size;
 	req->in.h.opcode = FUSE_LISTXATTR;
-	req->in.h.ino = inode->i_ino;
+	req->in.h.nodeid = fi->nodeid;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(inarg);
 	req->in.args[0].value = &inarg;
@@ -1079,6 +1156,7 @@
 {
 	struct inode *inode = entry->d_inode;
 	struct fuse_conn *fc = INO_FC(inode);
+	struct fuse_inode *fi = INO_FI(inode);
 	struct fuse_req *req;
 	int err;
 	
@@ -1090,7 +1168,7 @@
 		return -ERESTARTSYS;
 
 	req->in.h.opcode = FUSE_REMOVEXATTR;
-	req->in.h.ino = inode->i_ino;
+	req->in.h.nodeid = fi->nodeid;
 	req->in.numargs = 1;
 	req->in.args[0].size = strlen(name) + 1;
 	req->in.args[0].value = name;
diff --git a/kernel/file.c b/kernel/file.c
index f4e0b56..aa9dba3 100644
--- a/kernel/file.c
+++ b/kernel/file.c
@@ -33,6 +33,7 @@
 static int fuse_open(struct inode *inode, struct file *file)
 {
 	struct fuse_conn *fc = INO_FC(inode);
+	struct fuse_inode *fi = INO_FI(inode);
 	struct fuse_req *req;
 	struct fuse_open_in inarg;
 	struct fuse_open_out outarg;
@@ -45,7 +46,7 @@
 
 	/* If opening the root node, no lookup has been performed on
 	   it, so the attributes must be refreshed */
-	if (inode->i_ino == FUSE_ROOT_INO) {
+	if (fi->nodeid == FUSE_ROOT_ID) {
 		int err = fuse_do_getattr(inode);
 		if (err)
 		 	return err;
@@ -68,11 +69,10 @@
 		goto out_put_request;
 	}
 
-
 	memset(&inarg, 0, sizeof(inarg));
 	inarg.flags = file->f_flags & ~O_EXCL;
 	req->in.h.opcode = FUSE_OPEN;
-	req->in.h.ino = inode->i_ino;
+	req->in.h.nodeid = fi->nodeid;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(inarg);
 	req->in.args[0].value = &inarg;
@@ -140,7 +140,7 @@
 	inarg->fh = ff->fh;
 	inarg->flags = file->f_flags & ~O_EXCL;
 	req->in.h.opcode = FUSE_RELEASE;
-	req->in.h.ino = inode->i_ino;
+	req->in.h.nodeid = fi->nodeid;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(struct fuse_release_in);
 	req->in.args[0].value = inarg;
@@ -157,6 +157,7 @@
 {
 	struct inode *inode = file->f_dentry->d_inode;
 	struct fuse_conn *fc = INO_FC(inode);
+	struct fuse_inode *fi = INO_FI(inode);
 	struct fuse_file *ff = file->private_data;
 	struct fuse_req *req = ff->release_req;
 	struct fuse_flush_in inarg;
@@ -169,7 +170,7 @@
 	memset(&inarg, 0, sizeof(inarg));
 	inarg.fh = ff->fh;
 	req->in.h.opcode = FUSE_FLUSH;
-	req->in.h.ino = inode->i_ino;
+	req->in.h.nodeid = fi->nodeid;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(inarg);
 	req->in.args[0].value = &inarg;
@@ -210,7 +211,7 @@
 	inarg.fh = ff->fh;
 	inarg.datasync = datasync;
 	req->in.h.opcode = FUSE_FSYNC;
-	req->in.h.ino = inode->i_ino;
+	req->in.h.nodeid = fi->nodeid;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(inarg);
 	req->in.args[0].value = &inarg;
@@ -228,6 +229,7 @@
 			      char *buf, loff_t pos, size_t count)
 {
 	struct fuse_conn *fc = INO_FC(inode);
+	struct fuse_inode *fi = INO_FI(inode);
 	struct fuse_file *ff = file->private_data;
 	struct fuse_req *req;
 	struct fuse_read_in inarg;
@@ -242,7 +244,7 @@
 	inarg.offset = pos;
 	inarg.size = count;
 	req->in.h.opcode = FUSE_READ;
-	req->in.h.ino = inode->i_ino;
+	req->in.h.nodeid = fi->nodeid;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(inarg);
 	req->in.args[0].value = &inarg;
@@ -333,6 +335,7 @@
 				struct inode *inode)
 {
 	struct fuse_conn *fc = INO_FC(inode);
+	struct fuse_inode *fi = INO_FI(inode);
 	struct fuse_file *ff = file->private_data;
 	struct fuse_read_in *inarg;
 	loff_t pos;
@@ -348,7 +351,7 @@
 	inarg->offset = pos;
 	inarg->size = numpages * PAGE_CACHE_SIZE;
 	req->in.h.opcode = FUSE_READ;
-	req->in.h.ino = inode->i_ino;
+	req->in.h.nodeid = fi->nodeid;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(struct fuse_read_in);
 	req->in.args[0].value = inarg;
@@ -588,6 +591,7 @@
 			       const char *buf, loff_t pos, size_t count)
 {
 	struct fuse_conn *fc = INO_FC(inode);
+	struct fuse_inode *fi = INO_FI(inode);
 	struct fuse_write_in inarg;
 	struct fuse_write_out outarg;
 	ssize_t res;
@@ -598,7 +602,7 @@
 	inarg.offset = pos;
 	inarg.size = count;
 	req->in.h.opcode = FUSE_WRITE;
-	req->in.h.ino = inode->i_ino;
+	req->in.h.nodeid = fi->nodeid;
 	if (writepage) {
 		req->in.h.uid = 0;
 		req->in.h.gid = 0;
@@ -757,7 +761,7 @@
 	inarg->offset = ((loff_t) page->index << PAGE_CACHE_SHIFT);
 	inarg->size = count;
 	req->in.h.opcode = FUSE_WRITE;
-	req->in.h.ino = inode->i_ino;
+	req->in.h.nodeid = fi->nodeid;
 	req->in.h.uid = 0;
 	req->in.h.gid = 0;
 	req->in.h.pid = 0;
diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h
index 8e3b416..d0cde75 100644
--- a/kernel/fuse_i.h
+++ b/kernel/fuse_i.h
@@ -79,6 +79,7 @@
 
 /** FUSE specific inode data */
 struct fuse_inode {
+	unsigned long nodeid;
 	struct fuse_req *forget_req;
 	struct rw_semaphore write_sem;
 	unsigned long i_time;
@@ -261,7 +262,7 @@
 #endif
 #define INO_FC(inode) SB_FC((inode)->i_sb)
 #define DEV_FC(file) ((file)->private_data)
-#define INO_FI(inode) ((inode)->u.generic_ip)
+#define INO_FI(i) ((struct fuse_inode *) (((struct inode *)(i))+1))
 
 
 /**
@@ -278,15 +279,17 @@
 /**
  * Get a filled in inode
  */
-struct inode *fuse_iget(struct super_block *sb, ino_t ino, int generation,
-			struct fuse_attr *attr, int version);
+struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
+			int generation, struct fuse_attr *attr, int version);
 
 
+struct inode *fuse_ilookup(struct fuse_conn *fc, ino_t ino, unsigned long nodeid);
+
 /**
  * Send FORGET command
  */
-void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, ino_t ino,
-		      int version);
+void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
+		      unsigned long nodeid, int version);
 
 /**
  * Initialise operations on regular file
@@ -381,11 +384,6 @@
  */
 void fuse_sync_inode(struct inode *inode);
 
-/**
- * Allocate fuse specific inode data
- */
-struct fuse_inode *fuse_inode_alloc(void);
-
 /*
  * Local Variables:
  * indent-tabs-mode: t
diff --git a/kernel/inode.c b/kernel/inode.c
index 8de566c..6ad42ee 100644
--- a/kernel/inode.c
+++ b/kernel/inode.c
@@ -58,32 +58,39 @@
 	unsigned int max_read;
 };
 
-struct fuse_inode *fuse_inode_alloc(void)
+static struct inode *fuse_alloc_inode(struct super_block *sb)
 {
+	struct inode *inode;
 	struct fuse_inode *fi;
 
-	fi = kmem_cache_alloc(fuse_inode_cachep, SLAB_KERNEL);
-	if (fi) {
-		memset(fi, 0, sizeof(*fi));
-		fi->forget_req = fuse_request_alloc();
-		if (!fi->forget_req) {
-			kmem_cache_free(fuse_inode_cachep, fi);
-			fi = NULL;
-		} else {
-			init_rwsem(&fi->write_sem);
-			INIT_LIST_HEAD(&fi->write_files);
-		}
-	}
+	inode = kmem_cache_alloc(fuse_inode_cachep, SLAB_KERNEL);
+	if (!inode)
+		return NULL;
 
-	return fi;
+#ifndef KERNEL_2_6
+	inode->u.generic_ip = NULL;
+#endif
+
+	fi = INO_FI(inode);
+	memset(fi, 0, sizeof(*fi));
+	fi->forget_req = fuse_request_alloc();
+	if (!fi->forget_req) {
+		kmem_cache_free(fuse_inode_cachep, inode);
+		return NULL;
+	}
+	init_rwsem(&fi->write_sem);
+	INIT_LIST_HEAD(&fi->write_files);
+
+	return inode;
 }
 
-static void fuse_inode_free(struct fuse_inode *fi)
+static void fuse_destroy_inode(struct inode *inode)
 {
+	struct fuse_inode *fi = INO_FI(inode);
 	BUG_ON(!list_empty(&fi->write_files));
 	if (fi->forget_req)
 		fuse_request_free(fi->forget_req);
-	kmem_cache_free(fuse_inode_cachep, fi);
+	kmem_cache_free(fuse_inode_cachep, inode);
 }
 
 static void fuse_read_inode(struct inode *inode)
@@ -91,13 +98,13 @@
 	/* No op */
 }
 
-void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, ino_t ino,
-		      int version)
+void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
+		      unsigned long nodeid, int version)
 {
 	struct fuse_forget_in *inarg = &req->misc.forget_in;
 	inarg->version = version;
 	req->in.h.opcode = FUSE_FORGET;
-	req->in.h.ino = ino;
+	req->in.h.nodeid = nodeid;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(struct fuse_forget_in);
 	req->in.args[0].value = inarg;
@@ -107,15 +114,11 @@
 static void fuse_clear_inode(struct inode *inode)
 {
 	struct fuse_conn *fc = INO_FC(inode);
-	struct fuse_inode *fi = INO_FI(inode);
 	
-	if (fi) {
-		if (fc) {
-			fuse_send_forget(fc, fi->forget_req, inode->i_ino,
-					 inode->i_version);
-			fi->forget_req = NULL;
-		}
-		fuse_inode_free(fi);
+	if (fc) {
+		struct fuse_inode *fi = INO_FI(inode);
+		fuse_send_forget(fc, fi->forget_req, fi->nodeid, inode->i_version);
+		fi->forget_req = NULL;
 	}
 }
 
@@ -330,6 +333,7 @@
 	memset(&attr, 0, sizeof(attr));
 
 	attr.mode = mode;
+	attr.ino = FUSE_ROOT_ID;
 	return fuse_iget(sb, 1, 0, &attr, 0);
 }
 
@@ -366,6 +370,8 @@
 #endif
 
 static struct super_operations fuse_super_operations = {
+	.alloc_inode    = fuse_alloc_inode,
+	.destroy_inode  = fuse_destroy_inode,
 	.read_inode	= fuse_read_inode,
 	.clear_inode	= fuse_clear_inode,
 	.put_super	= fuse_put_super,
@@ -469,6 +475,17 @@
 static DECLARE_FSTYPE(fuse_fs_type, "fuse", fuse_read_super_compat, 0);
 #endif
 
+static void fuse_inode_init_once(void * foo, kmem_cache_t * cachep,
+				 unsigned long flags)
+{
+	struct inode * inode = (struct inode *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(inode);
+}
+
+
 int fuse_fs_init()
 {
 	int err;
@@ -478,8 +495,9 @@
 		printk("fuse: failed to register filesystem\n");
 	else {
 		fuse_inode_cachep = kmem_cache_create("fuse_inode",
-						      sizeof(struct fuse_inode),
-						      0, 0, NULL, NULL);
+						      sizeof(struct inode) + sizeof(struct fuse_inode) ,
+						      0, SLAB_HWCACHE_ALIGN,
+						      fuse_inode_init_once, NULL);
 		if (!fuse_inode_cachep) {
 			unregister_filesystem(&fuse_fs_type);
 			err = -ENOMEM;
diff --git a/lib/fuse.c b/lib/fuse.c
index 22d6509..6b42252 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -64,48 +64,48 @@
     pthread_mutex_unlock(&f->lock);
 }
 
-static struct node *__get_node(struct fuse *f, fino_t ino)
+static struct node *__get_node(struct fuse *f, nodeid_t nodeid)
 {
-    size_t hash = ino % f->ino_table_size;
+    size_t hash = nodeid % f->id_table_size;
     struct node *node;
 
-    for (node = f->ino_table[hash]; node != NULL; node = node->ino_next)
-        if (node->ino == ino)
+    for (node = f->id_table[hash]; node != NULL; node = node->id_next)
+        if (node->nodeid == nodeid)
             return node;
     
     return NULL;
 }
 
-static struct node *get_node(struct fuse *f, fino_t ino)
+static struct node *get_node(struct fuse *f, nodeid_t nodeid)
 {
-    struct node *node = __get_node(f, ino);
+    struct node *node = __get_node(f, nodeid);
     if (node != NULL)
         return node;
     
-    fprintf(stderr, "fuse internal error: inode %lu not found\n", ino);
+    fprintf(stderr, "fuse internal error: inode %lu not found\n", nodeid);
     abort();
 }
 
-static void hash_ino(struct fuse *f, struct node *node)
+static void hash_id(struct fuse *f, struct node *node)
 {
-    size_t hash = node->ino % f->ino_table_size;
-    node->ino_next = f->ino_table[hash];
-    f->ino_table[hash] = node;    
+    size_t hash = node->nodeid % f->id_table_size;
+    node->id_next = f->id_table[hash];
+    f->id_table[hash] = node;    
 }
 
-static void unhash_ino(struct fuse *f, struct node *node)
+static void unhash_id(struct fuse *f, struct node *node)
 {
-    size_t hash = node->ino % f->ino_table_size;
-    struct node **nodep = &f->ino_table[hash];
+    size_t hash = node->nodeid % f->id_table_size;
+    struct node **nodep = &f->id_table[hash];
 
-    for (; *nodep != NULL; nodep = &(*nodep)->ino_next) 
+    for (; *nodep != NULL; nodep = &(*nodep)->id_next) 
         if (*nodep == node) {
-            *nodep = node->ino_next;
+            *nodep = node->id_next;
             return;
         }
 }
 
-static fino_t next_ino(struct fuse *f)
+static nodeid_t next_id(struct fuse *f)
 {
     do {
         f->ctr++;
@@ -121,7 +121,7 @@
     free(node);
 }
 
-static unsigned int name_hash(struct fuse *f, fino_t parent, const char *name)
+static unsigned int name_hash(struct fuse *f, nodeid_t parent, const char *name)
 {
     unsigned int hash = *name;
 
@@ -132,7 +132,7 @@
     return (hash + parent) % f->name_table_size;
 }
 
-static struct node *__lookup_node(struct fuse *f, fino_t parent,
+static struct node *__lookup_node(struct fuse *f, nodeid_t parent,
                                 const char *name)
 {
     size_t hash = name_hash(f, parent, name);
@@ -145,7 +145,7 @@
     return NULL;
 }
 
-static struct node *lookup_node(struct fuse *f, fino_t parent,
+static struct node *lookup_node(struct fuse *f, nodeid_t parent,
                                 const char *name)
 {
     struct node *node;
@@ -161,7 +161,7 @@
     abort();
 }
 
-static int hash_name(struct fuse *f, struct node *node, fino_t parent,
+static int hash_name(struct fuse *f, struct node *node, nodeid_t parent,
                      const char *name)
 {
     size_t hash = name_hash(f, parent, name);
@@ -191,12 +191,12 @@
                 return;
             }
         fprintf(stderr, "fuse internal error: unable to unhash node: %lu\n",
-                node->ino);
+                node->nodeid);
         abort();
     }
 }
 
-static struct node *find_node(struct fuse *f, fino_t parent, char *name,
+static struct node *find_node(struct fuse *f, nodeid_t parent, char *name,
                               struct fuse_attr *attr, int version)
 {
     struct node *node;
@@ -209,8 +209,13 @@
     pthread_mutex_lock(&f->lock);
     node = __lookup_node(f, parent, name);
     if (node != NULL) {
-        if (node->mode == mode && node->rdev == rdev)
+        if (node->mode == mode && node->rdev == rdev && 
+            (!(f->flags & FUSE_USE_INO) || node->ino == attr->ino)) {
+            if (!(f->flags & FUSE_USE_INO))
+                attr->ino = node->nodeid;
+
             goto out;
+        }
         
         unhash_name(f, node);
     }
@@ -219,18 +224,21 @@
     if (node == NULL)
         goto out_err;
 
+    node->nodeid = next_id(f);
+    if (!(f->flags & FUSE_USE_INO))
+        attr->ino = node->nodeid;
     node->mode = mode;
     node->rdev = rdev;
+    node->ino = attr->ino;
     node->open_count = 0;
     node->is_hidden = 0;
-    node->ino = next_ino(f);
     node->generation = f->generation;
     if (hash_name(f, node, parent, name) == -1) {
         free(node);
         node = NULL;
         goto out_err;
     }
-    hash_ino(f, node);
+    hash_id(f, node);
 
  out:
     node->version = version;
@@ -239,9 +247,11 @@
     return node;
 }
 
-static int path_lookup(struct fuse *f, const char *path, fino_t *inop)
+static int path_lookup(struct fuse *f, const char *path, nodeid_t *nodeidp,
+                       unsigned long *inop)
 {
-    fino_t ino;
+    nodeid_t nodeid;
+    unsigned long ino;
     int err;
     char *s;
     char *name;
@@ -250,22 +260,26 @@
         return -ENOMEM;
 
     pthread_mutex_lock(&f->lock);
-    ino = FUSE_ROOT_INO;
+    nodeid = FUSE_ROOT_ID;
+    ino = nodeid;
     err = 0;
     for  (s = tmp; (name = strsep(&s, "/")) != NULL; ) {
         if (name[0]) {
-            struct node *node = __lookup_node(f, ino, name);
+            struct node *node = __lookup_node(f, nodeid, name);
             if (node == NULL) {
                 err = -ENOENT;
                 break;
             }
+            nodeid = node->nodeid;
             ino = node->ino;
         }
     }
     pthread_mutex_unlock(&f->lock);
     free(tmp);
-    if (!err)
+    if (!err) {
+        *nodeidp = nodeid;
         *inop = ino;
+    }
     
     return err;
 }
@@ -285,7 +299,7 @@
     return s;
 }
 
-static char *get_path_name(struct fuse *f, fino_t ino, const char *name)
+static char *get_path_name(struct fuse *f, nodeid_t nodeid, const char *name)
 {
     char buf[FUSE_MAX_PATH];
     char *s = buf + FUSE_MAX_PATH - 1;
@@ -300,7 +314,7 @@
     }
 
     pthread_mutex_lock(&f->lock);
-    for (node = get_node(f, ino); node->ino != FUSE_ROOT_INO;
+    for (node = get_node(f, nodeid); node->nodeid != FUSE_ROOT_ID;
         node = get_node(f, node->parent)) {
         if (node->name == NULL) {
             s = NULL;
@@ -321,27 +335,27 @@
         return strdup(s);
 }
 
-static char *get_path(struct fuse *f, fino_t ino)
+static char *get_path(struct fuse *f, nodeid_t nodeid)
 {
-    return get_path_name(f, ino, NULL);
+    return get_path_name(f, nodeid, NULL);
 }
 
-static void destroy_node(struct fuse *f, fino_t ino, int version)
+static void destroy_node(struct fuse *f, nodeid_t nodeid, int version)
 {
     struct node *node;
 
     pthread_mutex_lock(&f->lock);
-    node = __get_node(f, ino);
-    if (node && node->version == version && ino != FUSE_ROOT_INO) {
+    node = __get_node(f, nodeid);
+    if (node && node->version == version && nodeid != FUSE_ROOT_ID) {
         unhash_name(f, node);
-        unhash_ino(f, node);
+        unhash_id(f, node);
         free_node(node);
     }
     pthread_mutex_unlock(&f->lock);
 
 }
 
-static void remove_node(struct fuse *f, fino_t dir, const char *name)
+static void remove_node(struct fuse *f, nodeid_t dir, const char *name)
 {
     struct node *node;
 
@@ -356,8 +370,8 @@
     pthread_mutex_unlock(&f->lock);
 }
 
-static int rename_node(struct fuse *f, fino_t olddir, const char *oldname,
-                        fino_t newdir, const char *newname, int hide)
+static int rename_node(struct fuse *f, nodeid_t olddir, const char *oldname,
+                        nodeid_t newdir, const char *newname, int hide)
 {
     struct node *node;
     struct node *newnode;
@@ -397,6 +411,7 @@
 
 static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
 {
+    attr->ino       = stbuf->st_ino;
     attr->mode      = stbuf->st_mode;
     attr->nlink     = stbuf->st_nlink;
     attr->uid       = stbuf->st_uid;
@@ -506,7 +521,7 @@
     return __send_reply(f, in, error, arg, argsize, 0);
 }
 
-static int is_open(struct fuse *f, fino_t dir, const char *name)
+static int is_open(struct fuse *f, nodeid_t dir, const char *name)
 {
     struct node *node;
     int isopen = 0;
@@ -518,7 +533,7 @@
     return isopen;
 }
 
-static char *hidden_name(struct fuse *f, fino_t dir, const char *oldname,
+static char *hidden_name(struct fuse *f, nodeid_t dir, const char *oldname,
                         char *newname, size_t bufsize)
 {
     struct stat buf;
@@ -537,7 +552,7 @@
         do {
             f->hidectr ++;
             snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
-                     (unsigned int) node->ino, f->hidectr);
+                     (unsigned int) node->nodeid, f->hidectr);
             newnode = __lookup_node(f, dir, newname);
         } while(newnode);
         pthread_mutex_unlock(&f->lock);
@@ -556,7 +571,7 @@
     return newpath;
 }
 
-static int hide_node(struct fuse *f, const char *oldpath, fino_t dir,
+static int hide_node(struct fuse *f, const char *oldpath, nodeid_t dir,
                      const char *oldname)
 {
     char newname[64];
@@ -575,7 +590,7 @@
     return err;
 }
 
-static int lookup_path(struct fuse *f, fino_t ino, int version,  char *name,
+static int lookup_path(struct fuse *f, nodeid_t nodeid, int version, char *name,
                        const char *path, struct fuse_entry_out *arg)
 {
     int res;
@@ -587,18 +602,18 @@
 
         memset(arg, 0, sizeof(struct fuse_entry_out));
         convert_stat(&buf, &arg->attr);
-        node = find_node(f, ino, name, &arg->attr, version);
+        node = find_node(f, nodeid, name, &arg->attr, version);
         if (node == NULL)
             res = -ENOMEM;
         else {
-            arg->ino = node->ino;
+            arg->nodeid = node->nodeid;
             arg->generation = node->generation;
             arg->entry_valid = ENTRY_REVALIDATE_TIME;
             arg->entry_valid_nsec = 0;
             arg->attr_valid = ATTR_REVALIDATE_TIME;
             arg->attr_valid_nsec = 0;
             if (f->flags & FUSE_DEBUG) {
-                printf("   INO: %li\n", arg->ino);
+                printf("   NODEID: %li\n", arg->nodeid);
                 fflush(stdout);
             }
         }
@@ -614,7 +629,7 @@
     struct fuse_entry_out arg;
 
     res = -ENOENT;
-    path = get_path_name(f, in->ino, name);
+    path = get_path_name(f, in->nodeid, name);
     if (path != NULL) {
         if (f->flags & FUSE_DEBUG) {
             printf("LOOKUP %s\n", path);
@@ -622,22 +637,22 @@
         }
         res = -ENOSYS;
         if (f->op.getattr)
-            res = lookup_path(f, in->ino, in->unique, name, path, &arg);
+            res = lookup_path(f, in->nodeid, in->unique, name, path, &arg);
         free(path);
     }
     res2 = send_reply(f, in, res, &arg, sizeof(arg));
     if (res == 0 && res2 == -ENOENT)
-        destroy_node(f, arg.ino, in->unique);
+        destroy_node(f, arg.nodeid, in->unique);
 }
 
 static void do_forget(struct fuse *f, struct fuse_in_header *in,
                       struct fuse_forget_in *arg)
 {
     if (f->flags & FUSE_DEBUG) {
-        printf("FORGET %li/%i\n", in->ino, arg->version);
+        printf("FORGET %li/%i\n", in->nodeid, arg->version);
         fflush(stdout);
     }
-    destroy_node(f, in->ino, arg->version);
+    destroy_node(f, in->nodeid, arg->version);
 }
 
 static void do_getattr(struct fuse *f, struct fuse_in_header *in)
@@ -648,7 +663,7 @@
     struct fuse_attr_out arg;
 
     res = -ENOENT;
-    path = get_path(f, in->ino);
+    path = get_path(f, in->nodeid);
     if (path != NULL) {
         res = -ENOSYS;
         if (f->op.getattr)
@@ -661,6 +676,12 @@
         arg.attr_valid = ATTR_REVALIDATE_TIME;
         arg.attr_valid_nsec = 0;
         convert_stat(&buf, &arg.attr);
+        if (!(f->flags & FUSE_USE_INO))
+            arg.attr.ino = in->nodeid;
+        else {
+            struct node *node = get_node(f, in->nodeid);
+            node->ino = arg.attr.ino;
+        }
     }
 
     send_reply(f, in, res, &arg, sizeof(arg));
@@ -726,7 +747,7 @@
     struct fuse_attr_out outarg;
 
     res = -ENOENT;
-    path = get_path(f, in->ino);
+    path = get_path(f, in->nodeid);
     if (path != NULL) {
         res = -ENOSYS;
         if (f->op.getattr) {
@@ -748,6 +769,12 @@
                     outarg.attr_valid = ATTR_REVALIDATE_TIME;
                     outarg.attr_valid_nsec = 0;
                     convert_stat(&buf, &outarg.attr);
+                    if (!(f->flags & FUSE_USE_INO))
+                        outarg.attr.ino = in->nodeid;
+                    else {
+                        struct node *node = get_node(f, in->nodeid);
+                        node->ino = outarg.attr.ino;
+                    }
                 }
             }
         }
@@ -763,7 +790,7 @@
     char *path;
 
     res = -ENOENT;
-    path = get_path(f, in->ino);
+    path = get_path(f, in->nodeid);
     if (path != NULL) {
         res = -ENOSYS;
         if (f->op.readlink)
@@ -783,14 +810,14 @@
 
     dh.fuse = f;
     dh.fp = tmpfile();
-    dh.dir = in->ino;
+    dh.dir = in->nodeid;
 
     res = -EIO;
     if (dh.fp == NULL)
         perror("fuse: failed to create temporary file");
     else {
         res = -ENOENT;
-        path = get_path(f, in->ino);
+        path = get_path(f, in->nodeid);
         if (path != NULL) {
             res = -ENOSYS;
             if (f->op.getdir)
@@ -817,7 +844,7 @@
     struct fuse_entry_out outarg;
 
     res = -ENOENT;
-    path = get_path_name(f, in->ino, name);
+    path = get_path_name(f, in->nodeid, name);
     if (path != NULL) {
         if (f->flags & FUSE_DEBUG) {
             printf("MKNOD %s\n", path);
@@ -827,13 +854,13 @@
         if (f->op.mknod && f->op.getattr) {
             res = f->op.mknod(path, inarg->mode, inarg->rdev);
             if (res == 0)
-                res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
+                res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
         }
         free(path);
     }
     res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
     if (res == 0 && res2 == -ENOENT)
-        destroy_node(f, outarg.ino, in->unique);
+        destroy_node(f, outarg.nodeid, in->unique);
 }
 
 static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
@@ -846,7 +873,7 @@
     struct fuse_entry_out outarg;
 
     res = -ENOENT;
-    path = get_path_name(f, in->ino, name);
+    path = get_path_name(f, in->nodeid, name);
     if (path != NULL) {
         if (f->flags & FUSE_DEBUG) {
             printf("MKDIR %s\n", path);
@@ -856,13 +883,13 @@
         if (f->op.mkdir && f->op.getattr) {
             res = f->op.mkdir(path, inarg->mode);
             if (res == 0)
-                res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
+                res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
         }
         free(path);
     }
     res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
     if (res == 0 && res2 == -ENOENT)
-        destroy_node(f, outarg.ino, in->unique);
+        destroy_node(f, outarg.nodeid, in->unique);
 }
 
 static void do_unlink(struct fuse *f, struct fuse_in_header *in, char *name)
@@ -871,7 +898,7 @@
     char *path;
 
     res = -ENOENT;
-    path = get_path_name(f, in->ino, name);
+    path = get_path_name(f, in->nodeid, name);
     if (path != NULL) {
         if (f->flags & FUSE_DEBUG) {
             printf("UNLINK %s\n", path);
@@ -879,12 +906,12 @@
         }
         res = -ENOSYS;
         if (f->op.unlink) {
-            if (!(f->flags & FUSE_HARD_REMOVE) && is_open(f, in->ino, name))
-                res = hide_node(f, path, in->ino, name);
+            if (!(f->flags & FUSE_HARD_REMOVE) && is_open(f, in->nodeid, name))
+                res = hide_node(f, path, in->nodeid, name);
             else {
                 res = f->op.unlink(path);
                 if (res == 0)
-                    remove_node(f, in->ino, name);
+                    remove_node(f, in->nodeid, name);
             }
         }
         free(path);
@@ -898,7 +925,7 @@
     char *path;
 
     res = -ENOENT;
-    path = get_path_name(f, in->ino, name);
+    path = get_path_name(f, in->nodeid, name);
     if (path != NULL) {
         if (f->flags & FUSE_DEBUG) {
             printf("RMDIR %s\n", path);
@@ -908,7 +935,7 @@
         if (f->op.rmdir) {
             res = f->op.rmdir(path);
             if (res == 0)
-                remove_node(f, in->ino, name);
+                remove_node(f, in->nodeid, name);
         }
         free(path);
     }
@@ -924,7 +951,7 @@
     struct fuse_entry_out outarg;
 
     res = -ENOENT;
-    path = get_path_name(f, in->ino, name);
+    path = get_path_name(f, in->nodeid, name);
     if (path != NULL) {
         if (f->flags & FUSE_DEBUG) {
             printf("SYMLINK %s\n", path);
@@ -934,13 +961,13 @@
         if (f->op.symlink && f->op.getattr) {
             res = f->op.symlink(link, path);
             if (res == 0)
-                res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
+                res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
         }
         free(path);
     }
     res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
     if (res == 0 && res2 == -ENOENT)
-        destroy_node(f, outarg.ino, in->unique);
+        destroy_node(f, outarg.nodeid, in->unique);
 
 }
 
@@ -948,8 +975,8 @@
                       struct fuse_rename_in *inarg)
 {
     int res;
-    fino_t olddir = in->ino;
-    fino_t newdir = inarg->newdir;
+    nodeid_t olddir = in->nodeid;
+    nodeid_t newdir = inarg->newdir;
     char *oldname = PARAM(inarg);
     char *newname = oldname + strlen(oldname) + 1;
     char *oldpath;
@@ -994,7 +1021,7 @@
     struct fuse_entry_out outarg;
 
     res = -ENOENT;
-    oldpath = get_path(f, in->ino);
+    oldpath = get_path(f, in->nodeid);
     if (oldpath != NULL) {
         newpath =  get_path_name(f, arg->newdir, name);
         if (newpath != NULL) {
@@ -1015,7 +1042,7 @@
     }
     res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
     if (res == 0 && res2 == -ENOENT)
-        destroy_node(f, outarg.ino, in->unique);
+        destroy_node(f, outarg.nodeid, in->unique);
 }
 
 static void do_open(struct fuse *f, struct fuse_in_header *in,
@@ -1026,7 +1053,7 @@
     struct fuse_open_out outarg;
 
     res = -ENOENT;
-    path = get_path(f, in->ino);
+    path = get_path(f, in->nodeid);
     if (path != NULL) {
         res = -ENOSYS;
         if (f->op.open)
@@ -1053,7 +1080,7 @@
             if(f->op.release)
                 f->op.release(path, arg->flags);
         } else
-            get_node(f, in->ino)->open_count ++;
+            get_node(f, in->nodeid)->open_count ++;
         pthread_mutex_unlock(&f->lock);
 
     } else
@@ -1070,7 +1097,7 @@
     int res;
 
     res = -ENOENT;
-    path = get_path(f, in->ino);
+    path = get_path(f, in->nodeid);
     if (path != NULL) {
         if (f->flags & FUSE_DEBUG) {
             printf("FLUSH[%lu]\n", arg->fh);
@@ -1091,11 +1118,11 @@
     char *path;
 
     pthread_mutex_lock(&f->lock);
-    node = get_node(f, in->ino);
+    node = get_node(f, in->nodeid);
     --node->open_count;
     pthread_mutex_unlock(&f->lock);
 
-    path = get_path(f, in->ino);
+    path = get_path(f, in->nodeid);
     if (path != NULL) {
         if (f->flags & FUSE_DEBUG) {
             printf("RELEASE[%lu]\n", arg->fh);
@@ -1128,7 +1155,7 @@
         size_t outsize;
         
         res = -ENOENT;
-        path = get_path(f, in->ino);
+        path = get_path(f, in->nodeid);
         if (path != NULL) {
             if (f->flags & FUSE_DEBUG) {
                 printf("READ[%lu] %u bytes from %llu\n", arg->fh, arg->size,
@@ -1169,7 +1196,7 @@
     struct fuse_write_out outarg;
 
     res = -ENOENT;
-    path = get_path(f, in->ino);
+    path = get_path(f, in->nodeid);
     if (path != NULL) {
         if (f->flags & FUSE_DEBUG) {
             printf("WRITE%s[%lu] %u bytes to %llu\n",
@@ -1235,7 +1262,7 @@
     char *path;
 
     res = -ENOENT;
-    path = get_path(f, in->ino);
+    path = get_path(f, in->nodeid);
     if (path != NULL) {
         if (f->flags & FUSE_DEBUG) {
             printf("FSYNC[%lu]\n", inarg->fh);
@@ -1258,7 +1285,7 @@
     unsigned char *value = name + strlen(name) + 1;
 
     res = -ENOENT;
-    path = get_path(f, in->ino);
+    path = get_path(f, in->nodeid);
     if (path != NULL) {
         res = -ENOSYS;
         if (f->op.setxattr)
@@ -1275,7 +1302,7 @@
     char *path;
 
     res = -ENOENT;
-    path = get_path(f, in->ino);
+    path = get_path(f, in->nodeid);
     if (path != NULL) {
         res = -ENOSYS;
         if (f->op.getxattr)
@@ -1343,7 +1370,7 @@
     char *path;
 
     res = -ENOENT;
-    path = get_path(f, in->ino);
+    path = get_path(f, in->nodeid);
     if (path != NULL) {
         res = -ENOSYS;
         if (f->op.listxattr)
@@ -1408,7 +1435,7 @@
     char *path;
 
     res = -ENOENT;
-    path = get_path(f, in->ino);
+    path = get_path(f, in->nodeid);
     if (path != NULL) {
         res = -ENOSYS;
         if (f->op.removexattr)
@@ -1435,8 +1462,8 @@
     dec_avail(f);
 
     if ((f->flags & FUSE_DEBUG)) {
-        printf("unique: %i, opcode: %s (%i), ino: %li, insize: %i\n",
-               in->unique, opname(in->opcode), in->opcode, in->ino,
+        printf("unique: %i, opcode: %s (%i), nodeid: %li, insize: %i\n",
+               in->unique, opname(in->opcode), in->opcode, in->nodeid,
                cmd->buflen);
         fflush(stdout);
     }
@@ -1634,10 +1661,11 @@
 {
     int res;
     int err;
-    fino_t ino;
+    nodeid_t nodeid;
+    unsigned long ino;
     struct fuse_user_header h;
 
-    err = path_lookup(f, path, &ino);
+    err = path_lookup(f, path, &nodeid, &ino);
     if (err) {
         if (err == -ENOENT)
             return 0;
@@ -1647,10 +1675,11 @@
 
     memset(&h, 0, sizeof(struct fuse_user_header));
     h.opcode = FUSE_INVALIDATE;
+    h.nodeid = nodeid;
     h.ino = ino;
     
     if ((f->flags & FUSE_DEBUG)) {
-        printf("INVALIDATE ino: %li\n", ino);
+        printf("INVALIDATE nodeid: %li\n", nodeid);
         fflush(stdout);
     }
 
@@ -1716,7 +1745,8 @@
 int fuse_is_lib_option(const char *opt)
 {
     if (strcmp(opt, "debug") == 0 ||
-        strcmp(opt, "hard_remove") == 0)
+        strcmp(opt, "hard_remove") == 0 ||
+        strcmp(opt, "use_ino") == 0)
         return 1;
     else
         return 0;
@@ -1737,6 +1767,8 @@
                 f->flags |= FUSE_DEBUG;
             else if (strcmp(opt, "hard_remove") == 0)
                 f->flags |= FUSE_HARD_REMOVE;
+            else if (strcmp(opt, "use_ino") == 0)
+                f->flags |= FUSE_USE_INO;
             else 
                 fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
         }
@@ -1770,10 +1802,10 @@
     if (f->name_table == NULL)
         goto out_free;
 
-    f->ino_table_size = 14057;
-    f->ino_table = (struct node **)
-        calloc(1, sizeof(struct node *) * f->ino_table_size);
-    if (f->ino_table == NULL)
+    f->id_table_size = 14057;
+    f->id_table = (struct node **)
+        calloc(1, sizeof(struct node *) * f->id_table_size);
+    if (f->id_table == NULL)
         goto out_free_name_table;
 
     pthread_mutex_init(&f->lock, NULL);
@@ -1784,7 +1816,7 @@
 
     root = (struct node *) calloc(1, sizeof(struct node));
     if (root == NULL)
-        goto out_free_ino_table;
+        goto out_free_id_table;
 
     root->mode = 0;
     root->rdev = 0;
@@ -1793,16 +1825,16 @@
         goto out_free_root;
 
     root->parent = 0;
-    root->ino = FUSE_ROOT_INO;
+    root->nodeid = FUSE_ROOT_ID;
     root->generation = 0;
-    hash_ino(f, root);
+    hash_id(f, root);
 
     return f;
 
  out_free_root:
     free(root);
- out_free_ino_table:
-    free(f->ino_table);
+ out_free_id_table:
+    free(f->id_table);
  out_free_name_table:
     free(f->name_table);
  out_free:
@@ -1815,27 +1847,27 @@
 void fuse_destroy(struct fuse *f)
 {
     size_t i;
-    for (i = 0; i < f->ino_table_size; i++) {
+    for (i = 0; i < f->id_table_size; i++) {
         struct node *node;
 
-        for (node = f->ino_table[i]; node != NULL; node = node->ino_next) {
+        for (node = f->id_table[i]; node != NULL; node = node->id_next) {
             if (node->is_hidden) {
-                char *path = get_path(f, node->ino);
+                char *path = get_path(f, node->nodeid);
                 if (path)
                     f->op.unlink(path);
             }
         }
     }
-    for (i = 0; i < f->ino_table_size; i++) {
+    for (i = 0; i < f->id_table_size; i++) {
         struct node *node;
         struct node *next;
 
-        for (node = f->ino_table[i]; node != NULL; node = next) {
-            next = node->ino_next;
+        for (node = f->id_table[i]; node != NULL; node = next) {
+            next = node->id_next;
             free_node(node);
         }
     }
-    free(f->ino_table);
+    free(f->id_table);
     free(f->name_table);
     pthread_mutex_destroy(&f->lock);
     free(f);
diff --git a/lib/fuse_i.h b/lib/fuse_i.h
index 2c7e2d0..ca230a9 100644
--- a/lib/fuse_i.h
+++ b/lib/fuse_i.h
@@ -19,18 +19,22 @@
     remove it immediately */
 #define FUSE_HARD_REMOVE (1 << 2)
 
+/** Use st_ino field in getattr instead of generating inode numbers  */
+#define FUSE_USE_INO     (1 << 3)
 
-typedef unsigned long fino_t;
+
+typedef unsigned long nodeid_t;
 
 struct node {
     struct node *name_next;
-    struct node *ino_next;
-    fino_t ino;
+    struct node *id_next;
+    nodeid_t nodeid;
     unsigned int generation;
-    fino_t parent;
+    nodeid_t parent;
     char *name;
     int mode;
     int rdev;
+    unsigned long ino;
     int version;
     int open_count;
     int is_hidden;
@@ -42,9 +46,9 @@
     struct fuse_operations op;
     struct node **name_table;
     size_t name_table_size;
-    struct node **ino_table;
-    size_t ino_table_size;
-    fino_t ctr;
+    struct node **id_table;
+    size_t id_table_size;
+    nodeid_t ctr;
     unsigned int generation;
     unsigned int hidectr;
     unsigned long fh_ctr;
@@ -58,7 +62,7 @@
 
 struct fuse_dirhandle {
     struct fuse *fuse;
-    fino_t dir;
+    nodeid_t dir;
     FILE *fp;
 };