aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOGAWA Hirofumi <hirofumi@mail.parknet.co.jp>2014-05-13 20:56:34 +0900
committerDaniel Phillips <daniel@tux3.org>2014-05-13 20:56:34 +0900
commit9f27a764bbc6b388a80dd1aaf8b86b5c7077511f (patch)
treeccf8d6a15469cc549bece040379db248c1056746
parentf84ac75d56bd4b8319198d1d4cb9ee64f96492c0 (diff)
downloadlinux-tux3-9f27a764bbc6b388a80dd1aaf8b86b5c7077511f.tar.gz
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>
-rw-r--r--fs/tux3/inode.c37
-rw-r--r--fs/tux3/inode_vfslib.c7
-rw-r--r--fs/tux3/writeback_iattrfork.c9
3 files changed, 39 insertions, 14 deletions
diff --git a/fs/tux3/inode.c b/fs/tux3/inode.c
index 9d9f6ff9bffb74..1bfb28f3f5c184 100644
--- a/fs/tux3/inode.c
+++ b/fs/tux3/inode.c
@@ -572,17 +572,15 @@ static int tux3_truncate(struct inode *inode, loff_t newsize)
}
/* Change i_size, then clean buffers */
+ tux3_iattrdirty(inode);
i_size_write(inode, newsize);
/* Roundup. Partial page is handled by tux3_truncate_partial_block() */
holebegin = round_up(newsize, boundary);
if (newsize <= holebegin) /* Check overflow */
tux3_truncate_pagecache(inode, holebegin);
- if (!is_expand) {
+ if (!is_expand)
err = tux3_add_truncate_hole(inode, newsize);
- if (err)
- goto error;
- }
inode->i_mtime = inode->i_ctime = gettime();
tux3_mark_inode_dirty(inode);
@@ -833,13 +831,13 @@ int tux3_setattr(struct dentry *dentry, struct iattr *iattr)
down_write(&tux_inode(inode)->truncate_lock);
change_begin(sb);
- tux3_iattrdirty(inode);
-
if (need_truncate)
err = tux3_truncate(inode, iattr->ia_size);
- if (!err)
+ if (!err) {
+ tux3_iattrdirty(inode);
setattr_copy(inode, iattr);
- tux3_mark_inode_dirty(inode);
+ tux3_mark_inode_dirty(inode);
+ }
change_end(sb);
if (need_lock)
@@ -848,6 +846,26 @@ int tux3_setattr(struct dentry *dentry, struct iattr *iattr)
return err;
}
+static int tux3_file_update_time(struct inode *inode, struct timespec *time,
+ int flags)
+{
+ /* FIXME: atime is not supported yet */
+ if (flags & S_ATIME)
+ inode->i_atime = *time;
+ if (!(flags & ~S_ATIME))
+ return 0;
+
+ tux3_iattrdirty(inode);
+ if (flags & S_VERSION)
+ inode_inc_iversion(inode);
+ if (flags & S_CTIME)
+ inode->i_ctime = *time;
+ if (flags & S_MTIME)
+ inode->i_mtime = *time;
+ mark_inode_dirty_sync(inode);
+ return 0;
+}
+
#include "inode_vfslib.c"
static const struct file_operations tux_file_fops = {
@@ -870,7 +888,7 @@ static const struct file_operations tux_file_fops = {
static const struct inode_operations tux_file_iops = {
// .permission = ext4_permission,
.setattr = tux3_setattr,
- .getattr = tux3_getattr
+ .getattr = tux3_getattr,
#ifdef CONFIG_EXT4DEV_FS_XATTR
// .setxattr = generic_setxattr,
// .getxattr = generic_getxattr,
@@ -879,6 +897,7 @@ static const struct inode_operations tux_file_iops = {
#endif
// .fallocate = ext4_fallocate,
// .fiemap = ext4_fiemap,
+ .update_time = tux3_file_update_time,
};
static const struct inode_operations tux_special_iops = {
diff --git a/fs/tux3/inode_vfslib.c b/fs/tux3/inode_vfslib.c
index cc096230859875..819a0fd12f8d8d 100644
--- a/fs/tux3/inode_vfslib.c
+++ b/fs/tux3/inode_vfslib.c
@@ -25,8 +25,7 @@ static ssize_t tux3_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
mutex_lock(&inode->i_mutex);
/* For each ->write_end() calls change_end(). */
change_begin(sb);
- /* For timestamp. FIXME: convert this to ->update_time handler? */
- tux3_iattrdirty(inode);
+ /* FIXME: file_update_time() in this can be race with mmap */
ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos);
change_end_if_needed(sb);
mutex_unlock(&inode->i_mutex);
@@ -71,11 +70,9 @@ static ssize_t tux3_file_splice_write(struct pipe_inode_info *pipe,
mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
/* For each ->write_end() calls change_end(). */
change_begin(sb);
- /* For timestamp. FIXME: convert this to ->update_time
- * handler? */
- tux3_iattrdirty(inode);
ret = file_remove_suid(out);
if (!ret) {
+ /* FIXME: file_update_time() can be race with mmap */
ret = file_update_time(out);
if (!ret)
ret = splice_from_pipe_feed(pipe, &sd,
diff --git a/fs/tux3/writeback_iattrfork.c b/fs/tux3/writeback_iattrfork.c
index 53f197b377e3e6..8e6c42ca9424e3 100644
--- a/fs/tux3/writeback_iattrfork.c
+++ b/fs/tux3/writeback_iattrfork.c
@@ -45,6 +45,15 @@ static void idata_copy(struct inode *inode, struct tux3_iattr_data *idata)
idata->i_version = inode->i_version;
}
+/*
+ * Inode attributes fork. (See comment on top of this source)
+ *
+ * NOTE: caller must call tux3_mark_inode_dirty() after
+ * this. Otherwise, inode state will be remaining after flush, and
+ * will confuses flusher in future.
+ *
+ * FIXME: this is better to call tux3_mark_inode_dirty() too?
+ */
void tux3_iattrdirty(struct inode *inode)
{
struct tux3_inode *tuxnode = tux_inode(inode);