tux3: Fix tux3_iattrdirty() usages
Now, on some paths, mark_inode_dirty() is not called after
tux3_iattrdirty() was called.
E.g. If inode->i_ctime is same with current time, file_update_time()
skips to dirty inode.
tux3_iattrdirty()
file_update_time() {
if (!timespec_equal(&inode->i_ctime, &now))
sync_it |= S_CTIME;
if (sync_it)
mark_inode_dirty_sync()
}
This is wrong as tux3_iattrdirty() usage. tux3_iattrdirty() was
called, the caller must call mark_inode_dirty() too.
Otherwise,
delta = 1
tux3_iattrdirty(inode)
iattr_delta = delta
/* flush delta 1 */
inode is not dirty, so iattr_delta == 1 is remaining
/* flush delta 2 for data pages */
read_idata_for_i_size()
if (iattr_delta != delta)
/*
* iattr_delta is still 1, so read from idata[], but
* idata[] is invalid.
*/
By remaining iattr_delta, future inode flush is confused, and hits to
assertion.
To fix this, this makes sure to call tux3_iattrdirty() only when we call
mark_inode_dirty().
[FIXME: file_update_time() of mmap and write can race.]
Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
diff --git a/fs/tux3/user/inode.c b/fs/tux3/user/inode.c
index acc815c..56df92d 100644
--- a/fs/tux3/user/inode.c
+++ b/fs/tux3/user/inode.c
@@ -351,7 +351,6 @@
int err;
change_begin(sb);
- tux3_iattrdirty(inode);
err = __tuxtruncate(inode, size);
change_end(sb);
diff --git a/fs/tux3/user/tux3fuse.c b/fs/tux3/user/tux3fuse.c
index 8c17fbe..121d815 100644
--- a/fs/tux3/user/tux3fuse.c
+++ b/fs/tux3/user/tux3fuse.c
@@ -224,6 +224,10 @@
static void tux3fuse_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
int to_set, struct fuse_file_info *fi)
{
+#define SET_ATTRS (FUSE_SET_ATTR_MODE | FUSE_SET_ATTR_UID | \
+ FUSE_SET_ATTR_GID | FUSE_SET_ATTR_ATIME | \
+ FUSE_SET_ATTR_MTIME)
+
trace("(%lx)", ino);
struct sb *sb = tux3fuse_get_sb(req);
struct inode *inode;
@@ -235,23 +239,22 @@
}
change_begin(sb);
-
- tux3_iattrdirty(inode);
-
if (to_set & FUSE_SET_ATTR_SIZE)
__tuxtruncate(inode, attr->st_size);
- if (to_set & FUSE_SET_ATTR_MODE)
- inode->i_mode = attr->st_mode;
- if (to_set & FUSE_SET_ATTR_UID)
- i_uid_write(inode, attr->st_uid);
- if (to_set & FUSE_SET_ATTR_GID)
- i_gid_write(inode, attr->st_gid);
- if (to_set & FUSE_SET_ATTR_ATIME)
- inode->i_atime = attr->st_atim;
- if (to_set & FUSE_SET_ATTR_MTIME)
- inode->i_mtime = attr->st_mtim;
- if (to_set)
+ if (to_set & SET_ATTRS) {
+ tux3_iattrdirty(inode);
+ if (to_set & FUSE_SET_ATTR_MODE)
+ inode->i_mode = attr->st_mode;
+ if (to_set & FUSE_SET_ATTR_UID)
+ i_uid_write(inode, attr->st_uid);
+ if (to_set & FUSE_SET_ATTR_GID)
+ i_gid_write(inode, attr->st_gid);
+ if (to_set & FUSE_SET_ATTR_ATIME)
+ inode->i_atime = attr->st_atim;
+ if (to_set & FUSE_SET_ATTR_MTIME)
+ inode->i_mtime = attr->st_mtim;
tux3_mark_inode_dirty(inode);
+ }
change_end(sb);
struct stat stbuf;