aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2004-11-02 17:32:03 +0000
committerMiklos Szeredi <miklos@szeredi.hu>2004-11-02 17:32:03 +0000
commita13d90020721d30c3ac03b4e6905aa54cab1aed7 (patch)
tree7a919bf696f6fedbca5177bec5451894d5f81433
parent874e3c166213a1dec3d191f78adc87b156c3f6e8 (diff)
downloadlibfuse-a13d90020721d30c3ac03b4e6905aa54cab1aed7.tar.gz
added support for setting the st_ino field
-rw-r--r--ChangeLog5
-rw-r--r--include/linux/fuse.h17
-rw-r--r--kernel/dev.c24
-rw-r--r--kernel/dir.c168
-rw-r--r--kernel/file.c24
-rw-r--r--kernel/fuse_i.h18
-rw-r--r--kernel/inode.c74
-rw-r--r--lib/fuse.c258
-rw-r--r--lib/fuse_i.h20
9 files changed, 369 insertions, 239 deletions
diff --git a/ChangeLog b/ChangeLog
index 0781488..450d956 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2004-11-02 Miklos Szeredi <miklos@szeredi.hu>
+
+ * Added "use_ino" mount option. This enables the filesystems to
+ set the st_ino field on files
+
2004-11-01 Miklos Szeredi <miklos@szeredi.hu>
* Fix compile problems with ancient (<=2.4.18) kernels (reported
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index 21ecc47..e5f9a6c 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -9,13 +9,13 @@
/* This file defines the kernel interface of FUSE */
/** Version number of this interface */
-#define FUSE_KERNEL_VERSION 3
+#define FUSE_KERNEL_VERSION 4
/** Minor version number of this interface */
#define FUSE_KERNEL_MINOR_VERSION 1
-/** The inode number of the root indode */
-#define FUSE_ROOT_INO 1
+/** The node ID of the root inode */
+#define FUSE_ROOT_ID 1
/** Opening this will yield a new control file */
#define FUSE_DEV "/proc/fs/fuse/dev"
@@ -24,6 +24,7 @@
#define FUSE_VERSION_FILE "/proc/fs/fuse/version"
struct fuse_attr {
+ unsigned long ino;
unsigned int mode;
unsigned int nlink;
unsigned int uid;
@@ -93,8 +94,8 @@ 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;
};