|
@@ -4139,6 +4139,65 @@ static int ext4_inode_blocks_set(handle_t *handle,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+struct other_inode {
|
|
|
+ unsigned long orig_ino;
|
|
|
+ struct ext4_inode *raw_inode;
|
|
|
+};
|
|
|
+
|
|
|
+static int other_inode_match(struct inode * inode, unsigned long ino,
|
|
|
+ void *data)
|
|
|
+{
|
|
|
+ struct other_inode *oi = (struct other_inode *) data;
|
|
|
+
|
|
|
+ if ((inode->i_ino != ino) ||
|
|
|
+ (inode->i_state & (I_FREEING | I_WILL_FREE | I_NEW |
|
|
|
+ I_DIRTY_SYNC | I_DIRTY_DATASYNC)) ||
|
|
|
+ ((inode->i_state & I_DIRTY_TIME) == 0))
|
|
|
+ return 0;
|
|
|
+ spin_lock(&inode->i_lock);
|
|
|
+ if (((inode->i_state & (I_FREEING | I_WILL_FREE | I_NEW |
|
|
|
+ I_DIRTY_SYNC | I_DIRTY_DATASYNC)) == 0) &&
|
|
|
+ (inode->i_state & I_DIRTY_TIME)) {
|
|
|
+ struct ext4_inode_info *ei = EXT4_I(inode);
|
|
|
+
|
|
|
+ inode->i_state &= ~(I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED);
|
|
|
+ spin_unlock(&inode->i_lock);
|
|
|
+
|
|
|
+ spin_lock(&ei->i_raw_lock);
|
|
|
+ EXT4_INODE_SET_XTIME(i_ctime, inode, oi->raw_inode);
|
|
|
+ EXT4_INODE_SET_XTIME(i_mtime, inode, oi->raw_inode);
|
|
|
+ EXT4_INODE_SET_XTIME(i_atime, inode, oi->raw_inode);
|
|
|
+ ext4_inode_csum_set(inode, oi->raw_inode, ei);
|
|
|
+ spin_unlock(&ei->i_raw_lock);
|
|
|
+ trace_ext4_other_inode_update_time(inode, oi->orig_ino);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ spin_unlock(&inode->i_lock);
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Opportunistically update the other time fields for other inodes in
|
|
|
+ * the same inode table block.
|
|
|
+ */
|
|
|
+static void ext4_update_other_inodes_time(struct super_block *sb,
|
|
|
+ unsigned long orig_ino, char *buf)
|
|
|
+{
|
|
|
+ struct other_inode oi;
|
|
|
+ unsigned long ino;
|
|
|
+ int i, inodes_per_block = EXT4_SB(sb)->s_inodes_per_block;
|
|
|
+ int inode_size = EXT4_INODE_SIZE(sb);
|
|
|
+
|
|
|
+ oi.orig_ino = orig_ino;
|
|
|
+ ino = orig_ino & ~(inodes_per_block - 1);
|
|
|
+ for (i = 0; i < inodes_per_block; i++, ino++, buf += inode_size) {
|
|
|
+ if (ino == orig_ino)
|
|
|
+ continue;
|
|
|
+ oi.raw_inode = (struct ext4_inode *) buf;
|
|
|
+ (void) find_inode_nowait(sb, ino, other_inode_match, &oi);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Post the struct inode info into an on-disk inode location in the
|
|
|
* buffer-cache. This gobbles the caller's reference to the
|
|
@@ -4248,10 +4307,11 @@ static int ext4_do_update_inode(handle_t *handle,
|
|
|
cpu_to_le16(ei->i_extra_isize);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
ext4_inode_csum_set(inode, raw_inode, ei);
|
|
|
-
|
|
|
spin_unlock(&ei->i_raw_lock);
|
|
|
+ if (inode->i_sb->s_flags & MS_LAZYTIME)
|
|
|
+ ext4_update_other_inodes_time(inode->i_sb, inode->i_ino,
|
|
|
+ bh->b_data);
|
|
|
|
|
|
BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
|
|
|
rc = ext4_handle_dirty_metadata(handle, NULL, bh);
|