bugfixes
diff --git a/kernel/dir.c b/kernel/dir.c
index 1dac0c8..f506816 100644
--- a/kernel/dir.c
+++ b/kernel/dir.c
@@ -16,7 +16,6 @@
static struct inode_operations fuse_dir_inode_operations;
static struct inode_operations fuse_file_inode_operations;
static struct inode_operations fuse_symlink_inode_operations;
-static struct inode_operations fuse_special_inode_operations;
static struct file_operations fuse_dir_operations;
@@ -24,6 +23,9 @@
static void change_attributes(struct inode *inode, struct fuse_attr *attr)
{
+ if(S_ISREG(inode->i_mode) && inode->i_size != attr->size)
+ invalidate_inode_pages(inode);
+
inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777);
inode->i_nlink = attr->nlink;
inode->i_uid = attr->uid;
@@ -36,9 +38,10 @@
inode->i_ctime = attr->ctime;
}
-static void fuse_init_inode(struct inode *inode, int mode, int rdev)
+static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
{
- inode->i_mode = mode & S_IFMT;
+ inode->i_mode = attr->mode & S_IFMT;
+ inode->i_size = attr->size;
if(S_ISREG(inode->i_mode)) {
inode->i_op = &fuse_file_inode_operations;
fuse_init_file_inode(inode);
@@ -51,23 +54,24 @@
inode->i_op = &fuse_symlink_inode_operations;
}
else {
- inode->i_op = &fuse_special_inode_operations;
- init_special_inode(inode, inode->i_mode, rdev);
+ inode->i_op = &fuse_file_inode_operations;
+ init_special_inode(inode, inode->i_mode, attr->rdev);
}
inode->u.generic_ip = inode;
}
struct inode *fuse_iget(struct super_block *sb, ino_t ino,
- struct fuse_attr *attr)
+ struct fuse_attr *attr, int version)
{
struct inode *inode;
inode = iget(sb, ino);
if(inode) {
if(!inode->u.generic_ip)
- fuse_init_inode(inode, attr->mode, attr->rdev);
+ fuse_init_inode(inode, attr);
change_attributes(inode, attr);
+ inode->i_version = version;
}
return inode;
@@ -75,12 +79,13 @@
static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
{
+ int ret;
struct fuse_conn *fc = INO_FC(dir);
struct fuse_in in = FUSE_IN_INIT;
struct fuse_out out = FUSE_OUT_INIT;
struct fuse_lookup_out arg;
struct inode *inode;
-
+
in.h.opcode = FUSE_LOOKUP;
in.h.ino = dir->i_ino;
in.argsize = entry->d_name.len + 1;
@@ -91,16 +96,24 @@
inode = NULL;
if(!out.h.error) {
- inode = fuse_iget(dir->i_sb, arg.ino, &arg.attr);
+ ret = -ENOMEM;
+ inode = fuse_iget(dir->i_sb, arg.ino, &arg.attr, out.h.unique);
if(!inode)
- return ERR_PTR(-ENOMEM);
+ goto err;
}
- else if(out.h.error != -ENOENT)
- return ERR_PTR(out.h.error);
+ else if(out.h.error != -ENOENT) {
+ ret = out.h.error;
+ goto err;
+ }
+ entry->d_time = jiffies;
entry->d_op = &fuse_dentry_opertations;
d_add(entry, inode);
+
return NULL;
+
+ err:
+ return ERR_PTR(ret);
}
/* create needs to return a positive entry, so this also does a lookup */
@@ -136,12 +149,11 @@
if(out.h.error)
return out.h.error;
- inode = fuse_iget(dir->i_sb, outarg.ino, &outarg.attr);
+ inode = fuse_iget(dir->i_sb, outarg.ino, &outarg.attr, out.h.unique);
if(!inode)
return -ENOMEM;
d_instantiate(entry, inode);
-
return 0;
}
@@ -293,17 +305,16 @@
return 0;
}
-/* Only revalidate the root inode, since lookup is always redone on
- the last path segment, and lookup refreshes the attributes */
-static int fuse_revalidate(struct dentry *dentry)
+static int fuse_revalidate(struct dentry *entry)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = entry->d_inode;
struct fuse_conn *fc = INO_FC(inode);
struct fuse_in in = FUSE_IN_INIT;
struct fuse_out out = FUSE_OUT_INIT;
struct fuse_getattr_out arg;
- if(inode->i_ino != FUSE_ROOT_INO)
+ if(inode->i_ino != FUSE_ROOT_INO &&
+ time_before_eq(jiffies, entry->d_time + HZ / 100))
return 0;
in.h.opcode = FUSE_GETATTR;
@@ -435,7 +446,7 @@
struct fuse_getdir_out outarg;
if(!(file->f_flags & O_DIRECTORY))
- return -EISDIR;
+ return 0;
in.h.opcode = FUSE_GETDIR;
in.h.ino = inode->i_ino;
@@ -465,7 +476,9 @@
static int fuse_dir_release(struct inode *inode, struct file *file)
{
struct file *cfile = file->private_data;
- fput(cfile);
+
+ if(cfile)
+ fput(cfile);
return 0;
}
@@ -502,16 +515,26 @@
struct fuse_conn *fc = INO_FC(inode);
struct fuse_in in = FUSE_IN_INIT;
struct fuse_out out = FUSE_OUT_INIT;
- struct fuse_setattr_in arg;
+ struct fuse_setattr_in inarg;
+ struct fuse_setattr_out outarg;
- arg.valid = iattr_to_fattr(attr, &arg.attr);
+ inarg.valid = iattr_to_fattr(attr, &inarg.attr);
in.h.opcode = FUSE_SETATTR;
in.h.ino = inode->i_ino;
- in.argsize = sizeof(arg);
- in.arg = &arg;
+ in.argsize = sizeof(inarg);
+ in.arg = &inarg;
+ out.argsize = sizeof(outarg);
+ out.arg = &outarg;
request_send(fc, &in, &out);
+ if(!out.h.error && (attr->ia_valid & ATTR_SIZE)) {
+ if(outarg.newsize > attr->ia_size)
+ outarg.newsize = attr->ia_size;
+
+ vmtruncate(inode, outarg.newsize);
+ }
+
return out.h.error;
}
@@ -552,12 +575,6 @@
revalidate: fuse_revalidate,
};
-static struct inode_operations fuse_special_inode_operations = {
- setattr: fuse_setattr,
- permission: fuse_permission,
- revalidate: fuse_revalidate,
-};
-
static struct inode_operations fuse_symlink_inode_operations =
{
setattr: fuse_setattr,