added support for setting the st_ino field
authorMiklos Szeredi <miklos@szeredi.hu>
Tue, 2 Nov 2004 17:32:03 +0000 (17:32 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Tue, 2 Nov 2004 17:32:03 +0000 (17:32 +0000)
ChangeLog
include/linux/fuse.h
kernel/dev.c
kernel/dir.c
kernel/file.c
kernel/fuse_i.h
kernel/inode.c
lib/fuse.c
lib/fuse_i.h

index 07814883eb8961d2362344ec4c5fa8ef07f93c48..450d95629550210648e70ba1e98c055485582675 100644 (file)
--- 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
index 21ecc47f6375ef536990783dc29f7186a4a35ee3..e5f9a6cc1917e4e9cbbab4a41348fa20e0937ab6 100644 (file)
@@ -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 @@ enum fuse_opcode {
 #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_getxattr_out {
 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_out_header {
 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 {
index c783ead3e8da4c582ce0a54ead19e04cc7d898f0..2e081d00ab8e0101fb697d4a0395a6bc5f9316ef 100644 (file)
@@ -433,33 +433,21 @@ static inline int copy_out_header(struct fuse_out_header *oh, const char *buf,
        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)
index 36eb3bf3c62e4ce4c4b40194922a64f7eb3415af..ce6df5ddd779c3ea489fa88630207c107234d4d6 100644 (file)
@@ -35,6 +35,7 @@ static void change_attributes(struct inode *inode, struct fuse_attr *attr)
 #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 @@ static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
                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);
-
-               change_attributes(inode, attr);
-               inode->i_version = version;
-       }
- out:
+       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;
+               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 @@ static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
 
        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 @@ static int lookup_new_entry(struct fuse_conn *fc, struct fuse_req *req,
 {
        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 @@ static int _fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
                      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 @@ static int _fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
        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_create(struct inode *dir, struct dentry *entry, int mode)
 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 @@ static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
        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 @@ static int fuse_symlink(struct inode *dir, struct dentry *entry,
                        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 @@ static int fuse_symlink(struct inode *dir, struct dentry *entry,
                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_symlink(struct inode *dir, struct dentry *entry,
 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 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry)
                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_unlink(struct inode *dir, struct dentry *entry)
 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 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry)
                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 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent,
                       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 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent,
                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 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
 {
        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 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
                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 @@ int fuse_do_getattr(struct inode *inode)
                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 @@ static int fuse_revalidate(struct dentry *entry)
        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 @@ static int fuse_getdir(struct file *file)
 {
        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 @@ static int fuse_getdir(struct file *file)
                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 @@ static char *read_link(struct dentry *dentry)
 {
        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 @@ static char *read_link(struct dentry *dentry)
                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 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
        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 @@ static int _fuse_dentry_revalidate(struct dentry *entry)
                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 @@ static int fuse_setxattr(struct dentry *entry, const char *name,
 {
        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 @@ static int fuse_setxattr(struct dentry *entry, const char *name,
        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 @@ static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
 {
        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 @@ static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
        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 @@ static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
 {
        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 @@ static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
        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 @@ static int fuse_removexattr(struct dentry *entry, const char *name)
 {
        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 @@ static int fuse_removexattr(struct dentry *entry, const char *name)
                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;
index f4e0b56e4a98a9281823682b5d57712264535d4a..aa9dba369458ecb36c81f4a6d41b9227ab1988f2 100644 (file)
@@ -33,6 +33,7 @@ MODULE_PARM_DESC(user_mmap, "Allow non root user to create a shared writable map
 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 @@ static int fuse_open(struct inode *inode, struct file *file)
 
        /* 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 @@ static int fuse_open(struct inode *inode, struct file *file)
                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 @@ static int fuse_release(struct inode *inode, struct file *file)
        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 @@ static int fuse_flush(struct file *file)
 {
        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 @@ static int fuse_flush(struct file *file)
        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 @@ static int fuse_fsync(struct file *file, struct dentry *de, int datasync)
        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 @@ static ssize_t fuse_send_read(struct file *file, struct inode *inode,
                              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 @@ static ssize_t fuse_send_read(struct file *file, struct inode *inode,
        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 @@ static void fuse_send_readpages(struct fuse_req *req, struct file *file,
                                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 @@ static void fuse_send_readpages(struct fuse_req *req, struct file *file,
        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 @@ static ssize_t fuse_send_write(struct fuse_req *req, int writepage,
                               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 @@ static ssize_t fuse_send_write(struct fuse_req *req, int writepage,
        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 @@ static void send_write_nonblock(struct fuse_req *req, struct inode *inode,
        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;
index 8e3b416d85cfe7b5ce602af3835eed222f4e2b23..d0cde759ad310eaa5ae703104fad66955a5184c2 100644 (file)
@@ -79,6 +79,7 @@ permission checking is done in the kernel */
 
 /** 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 @@ struct fuse_getdir_out_i {
 #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 @@ extern spinlock_t fuse_lock;
 /**
  * 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 @@ int fuse_do_getattr(struct inode *inode);
  */
 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
index 8de566ccb491a2e9e6d4f62594782ae7d93211ac..6ad42eed7c2ca5dc0c3033199652a13c9c5e8688 100644 (file)
@@ -58,32 +58,39 @@ struct fuse_mount_data {
        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;
+
+#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 fi;
+       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 @@ static void fuse_read_inode(struct inode *inode)
        /* 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 @@ void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, ino_t ino,
 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 @@ static struct inode *get_root_inode(struct super_block *sb, unsigned int mode)
        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 @@ static struct export_operations fuse_export_operations = {
 #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 struct super_block *fuse_read_super_compat(struct super_block *sb,
 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 @@ int fuse_fs_init()
                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;
index 22d650920dd2ef92b7f75b0a89ac58630e95423d..6b42252bfcdeb08a6ef0498a7a9f5fd5e433fcc9 100644 (file)
@@ -64,48 +64,48 @@ static inline void dec_avail(struct fuse *f)
     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 @@ static void free_node(struct node *node)
     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 @@ static unsigned int name_hash(struct fuse *f, fino_t parent, const char *name)
     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 @@ static struct node *__lookup_node(struct fuse *f, fino_t parent,
     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 @@ static struct node *lookup_node(struct fuse *f, fino_t parent,
     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 @@ static void unhash_name(struct fuse *f, struct node *node)
                 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 @@ static struct node *find_node(struct fuse *f, fino_t parent, char *name,
     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 @@ static struct node *find_node(struct fuse *f, fino_t parent, char *name,
     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 @@ static struct node *find_node(struct fuse *f, fino_t parent, char *name,
     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 @@ static int path_lookup(struct fuse *f, const char *path, fino_t *inop)
         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 @@ static char *add_name(char *buf, char *s, const char *name)
     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 @@ static char *get_path_name(struct fuse *f, fino_t ino, const char *name)
     }
 
     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 @@ static char *get_path_name(struct fuse *f, fino_t ino, const char *name)
         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 @@ static void remove_node(struct fuse *f, fino_t dir, const char *name)
     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 int rename_node(struct fuse *f, fino_t olddir, const char *oldname,
 
 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 @@ static int send_reply(struct fuse *f, struct fuse_in_header *in, int error,
     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 @@ static int is_open(struct fuse *f, fino_t dir, const char *name)
     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 @@ static char *hidden_name(struct fuse *f, fino_t dir, const char *oldname,
         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 @@ static char *hidden_name(struct fuse *f, fino_t dir, const char *oldname,
     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 @@ static int hide_node(struct fuse *f, const char *oldpath, fino_t dir,
     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 @@ static int lookup_path(struct fuse *f, fino_t ino, int version,  char *name,
 
         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 @@ static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
     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 @@ static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
         }
         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 @@ static void do_getattr(struct fuse *f, struct fuse_in_header *in)
     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 @@ static void do_getattr(struct fuse *f, struct fuse_in_header *in)
         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 @@ static void do_setattr(struct fuse *f, struct fuse_in_header *in,
     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 @@ static void do_setattr(struct fuse *f, struct fuse_in_header *in,
                     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 @@ static void do_readlink(struct fuse *f, struct fuse_in_header *in)
     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 @@ static void do_getdir(struct fuse *f, struct fuse_in_header *in)
 
     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 @@ static void do_mknod(struct fuse *f, struct fuse_in_header *in,
     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 @@ static void do_mknod(struct fuse *f, struct fuse_in_header *in,
         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 @@ static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
     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 @@ static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
         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 @@ static void do_unlink(struct fuse *f, struct fuse_in_header *in, char *name)
     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 @@ static void do_unlink(struct fuse *f, struct fuse_in_header *in, char *name)
         }
         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 @@ static void do_rmdir(struct fuse *f, struct fuse_in_header *in, char *name)
     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 @@ static void do_rmdir(struct fuse *f, struct fuse_in_header *in, char *name)
         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 @@ static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
     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 @@ static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
         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 @@ static void do_rename(struct fuse *f, struct fuse_in_header *in,
                       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 @@ static void do_link(struct fuse *f, struct fuse_in_header *in,
     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 @@ static void do_link(struct fuse *f, struct fuse_in_header *in,
     }
     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 @@ static void do_open(struct fuse *f, struct fuse_in_header *in,
     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 @@ static void do_open(struct fuse *f, struct fuse_in_header *in,
             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 @@ static void do_flush(struct fuse *f, struct fuse_in_header *in,
     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 @@ static void do_release(struct fuse *f, struct fuse_in_header *in,
     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 @@ static void do_read(struct fuse *f, struct fuse_in_header *in,
         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 @@ static void do_write(struct fuse *f, struct fuse_in_header *in,
     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 @@ static void do_fsync(struct fuse *f, struct fuse_in_header *in,
     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 @@ static void do_setxattr(struct fuse *f, struct fuse_in_header *in,
     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 @@ static int common_getxattr(struct fuse *f, struct fuse_in_header *in,
     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 @@ static int common_listxattr(struct fuse *f, struct fuse_in_header *in,
     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 @@ static void do_removexattr(struct fuse *f, struct fuse_in_header *in,
     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 @@ void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
     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 fuse_invalidate(struct fuse *f, const char *path)
 {
     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 @@ int fuse_invalidate(struct fuse *f, const char *path)
 
     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 @@ static int check_version(struct fuse *f)
 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 @@ static int parse_lib_opts(struct fuse *f, const char *opts)
                 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 @@ struct fuse *fuse_new(int fd, const char *opts, const struct fuse_operations *op
     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 @@ struct fuse *fuse_new(int fd, const char *opts, const struct fuse_operations *op
 
     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 @@ struct fuse *fuse_new(int fd, const char *opts, const struct fuse_operations *op
         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 @@ struct fuse *fuse_new(int fd, const char *opts, const struct fuse_operations *op
 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);
index 2c7e2d0c751fc6fe2cd88b1d922179cde8729ba1..ca230a9bfd08c7b656f54489432f9643687e3461 100644 (file)
     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 {
     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 {
 
 struct fuse_dirhandle {
     struct fuse *fuse;
-    fino_t dir;
+    nodeid_t dir;
     FILE *fp;
 };