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/inode.c b/fs/tux3/inode.c
index 9d9f6ff..1bfb28f 100644
--- a/fs/tux3/inode.c
+++ b/fs/tux3/inode.c
@@ -572,17 +572,15 @@
 	}
 
 	/* 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 @@
 		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 @@
 	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 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 @@
 #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 cc09623..819a0fd 100644
--- a/fs/tux3/inode_vfslib.c
+++ b/fs/tux3/inode_vfslib.c
@@ -25,8 +25,7 @@
 	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 @@
 		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 53f197b..8e6c42c 100644
--- a/fs/tux3/writeback_iattrfork.c
+++ b/fs/tux3/writeback_iattrfork.c
@@ -45,6 +45,15 @@
 	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);