From: Miklos Szeredi Date: Tue, 2 Nov 2004 17:32:03 +0000 (+0000) Subject: added support for setting the st_ino field X-Git-Tag: fuse_2_0_merge1~7^2~4 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=a13d90020721d30c3ac03b4e6905aa54cab1aed7;p=qemu-gpiodev%2Flibfuse.git 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 + + * Added "use_ino" mount option. This enables the filesystems to + set the st_ino field on files + 2004-11-01 Miklos Szeredi * 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 @@ 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 { 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 @@ 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) 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 @@ 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; 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 @@ 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; 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 @@ 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 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 @@ 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; 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 @@ 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); 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 { 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; };