diff mbox

[RFC,07/15] fs: ext4: convert to use 64 bit time

Message ID 1452144972-15802-8-git-send-email-deepa.kernel@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Deepa Dinamani Jan. 7, 2016, 5:36 a.m. UTC
struct timespec is not y2038 safe.
The ext4 uses time_extra fields to extend {a,c,m,cr} times until
2446.

Use struct inode_timespec to replace timespec.
inode_timespec will eventually be replaced by struct timespec64
when CONFIG_FS_USES_64BIT_TIME is enabled.

Signed-off-by: Deepa Dinamani <deepa.kernel@gmail.com>
---
 fs/ext4/acl.c     |  3 ++-
 fs/ext4/ext4.h    | 44 ++++++++++++++++++++++++--------------------
 fs/ext4/extents.c | 25 +++++++++++++++++++------
 fs/ext4/ialloc.c  |  9 +++++++--
 fs/ext4/inline.c  | 10 ++++++++--
 fs/ext4/inode.c   | 16 ++++++++++++----
 fs/ext4/ioctl.c   | 16 ++++++++++------
 fs/ext4/namei.c   | 40 ++++++++++++++++++++++++++++------------
 fs/ext4/super.c   |  6 +++++-
 fs/ext4/xattr.c   |  2 +-
 10 files changed, 116 insertions(+), 55 deletions(-)
diff mbox

Patch

diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c
index 69b1e73..e8073d5 100644
--- a/fs/ext4/acl.c
+++ b/fs/ext4/acl.c
@@ -200,7 +200,8 @@  __ext4_set_acl(handle_t *handle, struct inode *inode, int type,
 			if (error < 0)
 				return error;
 			else {
-				inode->i_ctime = ext4_current_time(inode);
+				VFS_INODE_SET_XTIME(i_ctime, inode,
+						    ext4_current_time(inode));
 				ext4_mark_inode_dirty(handle, inode);
 				if (error == 0)
 					acl = NULL;
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index c569430..4bb2604 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -754,14 +754,15 @@  struct move_extent {
  * affected filesystem before 2242.
  */
 
-static inline __le32 ext4_encode_extra_time(struct timespec *time)
+static inline __le32 ext4_encode_extra_time(struct inode_timespec *time)
 {
 	u32 extra = sizeof(time->tv_sec) > 4 ?
 		((time->tv_sec - (s32)time->tv_sec) >> 32) & EXT4_EPOCH_MASK : 0;
 	return cpu_to_le32(extra | (time->tv_nsec << EXT4_EPOCH_BITS));
 }
 
-static inline void ext4_decode_extra_time(struct timespec *time, __le32 extra)
+static inline void ext4_decode_extra_time(struct inode_timespec *time,
+					  __le32 extra)
 {
 	if (unlikely(sizeof(time->tv_sec) > 4 &&
 			(extra & cpu_to_le32(EXT4_EPOCH_MASK)))) {
@@ -784,12 +785,13 @@  static inline void ext4_decode_extra_time(struct timespec *time, __le32 extra)
 	time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS;
 }
 
-#define EXT4_INODE_SET_XTIME(xtime, inode, raw_inode)			       \
-do {									       \
-	(raw_inode)->xtime = cpu_to_le32((inode)->xtime.tv_sec);	       \
-	if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra))     \
-		(raw_inode)->xtime ## _extra =				       \
-				ext4_encode_extra_time(&(inode)->xtime);       \
+#define EXT4_INODE_SET_XTIME(xtime, inode, raw_inode)				\
+do {										\
+	struct inode_timespec __ts = VFS_INODE_GET_XTIME(xtime, inode);		\
+	(raw_inode)->xtime = cpu_to_le32(__ts.tv_sec);				\
+	if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra))	\
+		(raw_inode)->xtime ## _extra =					\
+				ext4_encode_extra_time(&__ts);			\
 } while (0)
 
 #define EXT4_EINODE_SET_XTIME(xtime, einode, raw_inode)			       \
@@ -801,14 +803,16 @@  do {									       \
 				ext4_encode_extra_time(&(einode)->xtime);      \
 } while (0)
 
-#define EXT4_INODE_GET_XTIME(xtime, inode, raw_inode)			       \
-do {									       \
-	(inode)->xtime.tv_sec = (signed)le32_to_cpu((raw_inode)->xtime);       \
-	if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra))     \
-		ext4_decode_extra_time(&(inode)->xtime,			       \
-				       raw_inode->xtime ## _extra);	       \
-	else								       \
-		(inode)->xtime.tv_nsec = 0;				       \
+#define EXT4_INODE_GET_XTIME(xtime, inode, raw_inode)				\
+do {										\
+	struct inode_timespec __ts = VFS_INODE_GET_XTIME(xtime, inode);		\
+	__ts.tv_sec = (signed)le32_to_cpu((raw_inode)->xtime);			\
+	if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra))	\
+		ext4_decode_extra_time(&__ts,					\
+				       raw_inode->xtime ## _extra);		\
+	else									\
+		__ts.tv_nsec = 0;						\
+	VFS_INODE_SET_XTIME(xtime, inode, __ts);				\
 } while (0)
 
 #define EXT4_EINODE_GET_XTIME(xtime, einode, raw_inode)			       \
@@ -931,9 +935,9 @@  struct ext4_inode_info {
 
 	/*
 	 * File creation time. Its function is same as that of
-	 * struct timespec i_{a,c,m}time in the generic inode.
+	 * struct inode_timespec i_{a,c,m}time in the generic inode.
 	 */
-	struct timespec i_crtime;
+	struct inode_timespec i_crtime;
 
 	/* mballoc */
 	struct list_head i_prealloc_list;
@@ -1441,10 +1445,10 @@  static inline struct ext4_inode_info *EXT4_I(struct inode *inode)
 	return container_of(inode, struct ext4_inode_info, vfs_inode);
 }
 
-static inline struct timespec ext4_current_time(struct inode *inode)
+static inline struct inode_timespec ext4_current_time(struct inode *inode)
 {
 	return (inode->i_sb->s_time_gran < NSEC_PER_SEC) ?
-		current_fs_time(inode->i_sb) : CURRENT_TIME_SEC;
+		current_fs_time(inode->i_sb) : current_fs_time_sec(inode->i_sb);
 }
 
 static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index b52fea3..99c4800 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -4726,12 +4726,13 @@  retry:
 		map.m_lblk += ret;
 		map.m_len = len = len - ret;
 		epos = (loff_t)map.m_lblk << inode->i_blkbits;
-		inode->i_ctime = ext4_current_time(inode);
+		VFS_INODE_SET_XTIME(i_ctime, inode, ext4_current_time(inode));
 		if (new_size) {
 			if (epos > new_size)
 				epos = new_size;
 			if (ext4_update_inode_size(inode, epos) & 0x1)
-				inode->i_mtime = inode->i_ctime;
+				VFS_INODE_SET_XTIME(i_mtime, inode,
+					VFS_INODE_GET_XTIME(i_ctime, inode));
 		} else {
 			if (epos > inode->i_size)
 				ext4_set_inode_flag(inode,
@@ -4755,6 +4756,7 @@  static long ext4_zero_range(struct file *file, loff_t offset,
 			    loff_t len, int mode)
 {
 	struct inode *inode = file_inode(file);
+	struct inode_timespec now;
 	handle_t *handle = NULL;
 	unsigned int max_blocks;
 	loff_t new_size = 0;
@@ -4854,7 +4856,9 @@  static long ext4_zero_range(struct file *file, loff_t offset,
 		}
 		/* Now release the pages and zero block aligned part of pages */
 		truncate_pagecache_range(inode, start, end - 1);
-		inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
+		now = ext4_current_time(inode);
+		VFS_INODE_SET_XTIME(i_mtime, inode, now);
+		VFS_INODE_SET_XTIME(i_ctime, inode, now);
 
 		ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size,
 					     flags, mode);
@@ -4879,7 +4883,9 @@  static long ext4_zero_range(struct file *file, loff_t offset,
 		goto out_dio;
 	}
 
-	inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
+	now = ext4_current_time(inode);
+	VFS_INODE_SET_XTIME(i_mtime, inode, now);
+	VFS_INODE_SET_XTIME(i_ctime, inode, now);
 	if (new_size) {
 		ext4_update_inode_size(inode, new_size);
 	} else {
@@ -5459,6 +5465,7 @@  int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len)
 {
 	struct super_block *sb = inode->i_sb;
 	ext4_lblk_t punch_start, punch_stop;
+	struct inode_timespec now;
 	handle_t *handle;
 	unsigned int credits;
 	loff_t new_size, ioffset;
@@ -5578,7 +5585,10 @@  int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len)
 	up_write(&EXT4_I(inode)->i_data_sem);
 	if (IS_SYNC(inode))
 		ext4_handle_sync(handle);
-	inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
+	now = ext4_current_time(inode);
+	VFS_INODE_SET_XTIME(i_mtime, inode, now);
+	VFS_INODE_SET_XTIME(i_ctime, inode, now);
+
 	ext4_mark_inode_dirty(handle, inode);
 
 out_stop:
@@ -5606,6 +5616,7 @@  int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len)
 	struct ext4_ext_path *path;
 	struct ext4_extent *extent;
 	ext4_lblk_t offset_lblk, len_lblk, ee_start_lblk = 0;
+	struct inode_timespec now;
 	unsigned int credits, ee_len;
 	int ret = 0, depth, split_flag = 0;
 	loff_t ioffset;
@@ -5688,7 +5699,9 @@  int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len)
 	/* Expand file to avoid data loss if there is error while shifting */
 	inode->i_size += len;
 	EXT4_I(inode)->i_disksize += len;
-	inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
+	now = ext4_current_time(inode);
+	VFS_INODE_SET_XTIME(i_mtime, inode, now);
+	VFS_INODE_SET_XTIME(i_ctime, inode, now);
 	ret = ext4_mark_inode_dirty(handle, inode);
 	if (ret)
 		goto out_stop;
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 1b8024d..6f16598 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -756,6 +756,7 @@  struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
 	ext4_group_t i;
 	ext4_group_t flex_group;
 	struct ext4_group_info *grp;
+	struct inode_timespec ts;
 	int encrypt = 0;
 
 	/* Cannot create files in a deleted directory */
@@ -1029,8 +1030,12 @@  got:
 	inode->i_ino = ino + group * EXT4_INODES_PER_GROUP(sb);
 	/* This is the optimal IO size (for stat), not the fs block size */
 	inode->i_blocks = 0;
-	inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime =
-						       ext4_current_time(inode);
+	ts = ei->i_crtime = ext4_current_time(inode);
+	if (unlikely(is_fs_timestamp_bad(ei->i_crtime)))
+		ei->i_crtime.tv_nsec = 0;
+	VFS_INODE_SET_XTIME(i_mtime, inode, ts);
+	VFS_INODE_SET_XTIME(i_atime, inode, ts);
+	VFS_INODE_SET_XTIME(i_ctime, inode, ts);
 
 	memset(ei->i_data, 0, sizeof(ei->i_data));
 	ei->i_dir_start_lookup = 0;
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index d884989..a53fb3b 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -1003,6 +1003,7 @@  static int ext4_add_dirent_to_inline(handle_t *handle,
 	struct inode	*dir = d_inode(dentry->d_parent);
 	int		err;
 	struct ext4_dir_entry_2 *de;
+	struct inode_timespec now;
 
 	err = ext4_find_dest_de(dir, inode, iloc->bh, inline_start,
 				inline_size, fname, &de);
@@ -1028,7 +1029,9 @@  static int ext4_add_dirent_to_inline(handle_t *handle,
 	 * happen is that the times are slightly out of date
 	 * and/or different from the directory change time.
 	 */
-	dir->i_mtime = dir->i_ctime = ext4_current_time(dir);
+	now = ext4_current_time(dir);
+	VFS_INODE_SET_XTIME(i_mtime, dir, now);
+	VFS_INODE_SET_XTIME(i_ctime, dir, now);
 	ext4_update_dx_flag(dir);
 	dir->i_version++;
 	ext4_mark_inode_dirty(handle, dir);
@@ -1896,6 +1899,7 @@  void ext4_inline_data_truncate(struct inode *inode, int *has_inline)
 	int inline_size, value_len, needed_blocks;
 	size_t i_size;
 	void *value = NULL;
+	struct inode_timespec now;
 	struct ext4_xattr_ibody_find is = {
 		.s = { .not_found = -ENODATA, },
 	};
@@ -1973,7 +1977,9 @@  out:
 	if (inode->i_nlink)
 		ext4_orphan_del(handle, inode);
 
-	inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
+	now = ext4_current_time(inode);
+	VFS_INODE_SET_XTIME(i_mtime, inode, now);
+	VFS_INODE_SET_XTIME(i_ctime, inode, now);
 	ext4_mark_inode_dirty(handle, inode);
 	if (IS_SYNC(inode))
 		ext4_handle_sync(handle);
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 3ce5db6..078fd58 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3689,6 +3689,7 @@  int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
 	struct super_block *sb = inode->i_sb;
 	ext4_lblk_t first_block, stop_block;
 	struct address_space *mapping = inode->i_mapping;
+	struct inode_timespec now;
 	loff_t first_block_offset, last_block_offset;
 	handle_t *handle;
 	unsigned int credits;
@@ -3804,7 +3805,9 @@  int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
 	if (IS_SYNC(inode))
 		ext4_handle_sync(handle);
 
-	inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
+	now = ext4_current_time(inode);
+	VFS_INODE_SET_XTIME(i_mtime, inode, now);
+	VFS_INODE_SET_XTIME(i_ctime, inode, now);
 	ext4_mark_inode_dirty(handle, inode);
 out_stop:
 	ext4_journal_stop(handle);
@@ -3875,6 +3878,7 @@  void ext4_truncate(struct inode *inode)
 	unsigned int credits;
 	handle_t *handle;
 	struct address_space *mapping = inode->i_mapping;
+	struct inode_timespec now;
 
 	/*
 	 * There is a possibility that we're either freeing the inode
@@ -3958,7 +3962,9 @@  out_stop:
 	if (inode->i_nlink)
 		ext4_orphan_del(handle, inode);
 
-	inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
+	now = ext4_current_time(inode);
+	VFS_INODE_SET_XTIME(i_mtime, inode, now);
+	VFS_INODE_SET_XTIME(i_ctime, inode, now);
 	ext4_mark_inode_dirty(handle, inode);
 	ext4_journal_stop(handle);
 
@@ -4825,6 +4831,7 @@  static void ext4_wait_for_tail_page_commit(struct inode *inode)
 int ext4_setattr(struct dentry *dentry, struct iattr *attr)
 {
 	struct inode *inode = d_inode(dentry);
+	struct inode_timespec now;
 	int error, rc = 0;
 	int orphan = 0;
 	const unsigned int ia_valid = attr->ia_valid;
@@ -4905,8 +4912,9 @@  int ext4_setattr(struct dentry *dentry, struct iattr *attr)
 			 * update c/mtime in shrink case below
 			 */
 			if (!shrink) {
-				inode->i_mtime = ext4_current_time(inode);
-				inode->i_ctime = inode->i_mtime;
+				now = ext4_current_time(inode);
+				VFS_INODE_SET_XTIME(i_mtime, inode, now);
+				VFS_INODE_SET_XTIME(i_ctime, inode, now);
 			}
 			down_write(&EXT4_I(inode)->i_data_sem);
 			EXT4_I(inode)->i_disksize = attr->ia_size;
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index afb51f5..3825eb7 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -67,9 +67,9 @@  static void swap_inode_data(struct inode *inode1, struct inode *inode2)
 	memswap(&inode1->i_blocks, &inode2->i_blocks,
 		  sizeof(inode1->i_blocks));
 	memswap(&inode1->i_bytes, &inode2->i_bytes, sizeof(inode1->i_bytes));
-	memswap(&inode1->i_atime, &inode2->i_atime, sizeof(inode1->i_atime));
-	memswap(&inode1->i_mtime, &inode2->i_mtime, sizeof(inode1->i_mtime));
-
+	VFS_INODE_SWAP_XTIME(i_ctime, inode1, inode2);
+	VFS_INODE_SWAP_XTIME(i_atime, inode1, inode2);
+	VFS_INODE_SWAP_XTIME(i_mtime, inode1, inode2);
 	memswap(ei1->i_data, ei2->i_data, sizeof(ei1->i_data));
 	memswap(&ei1->i_flags, &ei2->i_flags, sizeof(ei1->i_flags));
 	memswap(&ei1->i_disksize, &ei2->i_disksize, sizeof(ei1->i_disksize));
@@ -98,6 +98,7 @@  static long swap_inode_boot_loader(struct super_block *sb,
 	struct inode *inode_bl;
 	struct ext4_inode_info *ei_bl;
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
+	struct inode_timespec now;
 
 	if (inode->i_nlink != 1 || !S_ISREG(inode->i_mode))
 		return -EINVAL;
@@ -154,7 +155,9 @@  static long swap_inode_boot_loader(struct super_block *sb,
 
 	swap_inode_data(inode, inode_bl);
 
-	inode->i_ctime = inode_bl->i_ctime = ext4_current_time(inode);
+	now = ext4_current_time(inode);
+	VFS_INODE_SET_XTIME(i_ctime, inode, now);
+	VFS_INODE_SET_XTIME(i_ctime, inode_bl, now);
 
 	spin_lock(&sbi->s_next_gen_lock);
 	inode->i_generation = sbi->s_next_generation++;
@@ -298,7 +301,7 @@  long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 		}
 
 		ext4_set_inode_flags(inode);
-		inode->i_ctime = ext4_current_time(inode);
+		VFS_INODE_SET_XTIME(i_ctime, inode, ext4_current_time(inode));
 
 		err = ext4_mark_iloc_dirty(handle, inode, &iloc);
 flags_err:
@@ -357,7 +360,8 @@  flags_out:
 		}
 		err = ext4_reserve_inode_write(handle, inode, &iloc);
 		if (err == 0) {
-			inode->i_ctime = ext4_current_time(inode);
+			VFS_INODE_SET_XTIME(i_ctime, inode,
+					    ext4_current_time(inode));
 			inode->i_generation = generation;
 			err = ext4_mark_iloc_dirty(handle, inode, &iloc);
 		}
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index bfc026d..34c2d91 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -1876,6 +1876,7 @@  static int add_dirent_to_buf(handle_t *handle, struct ext4_filename *fname,
 			     struct buffer_head *bh)
 {
 	unsigned int	blocksize = dir->i_sb->s_blocksize;
+	struct inode_timespec now;
 	int		csum_size = 0;
 	int		err;
 
@@ -1912,7 +1913,9 @@  static int add_dirent_to_buf(handle_t *handle, struct ext4_filename *fname,
 	 * happen is that the times are slightly out of date
 	 * and/or different from the directory change time.
 	 */
-	dir->i_mtime = dir->i_ctime = ext4_current_time(dir);
+	now = ext4_current_time(dir);
+	VFS_INODE_SET_XTIME(i_mtime, dir, now);
+	VFS_INODE_SET_XTIME(i_ctime, dir, now);
 	ext4_update_dx_flag(dir);
 	dir->i_version++;
 	ext4_mark_inode_dirty(handle, dir);
@@ -2911,6 +2914,7 @@  static int ext4_rmdir(struct inode *dir, struct dentry *dentry)
 	struct buffer_head *bh;
 	struct ext4_dir_entry_2 *de;
 	handle_t *handle = NULL;
+	struct inode_timespec now;
 
 	/* Initialize quotas before so that eventual writes go in
 	 * separate transaction */
@@ -2964,7 +2968,10 @@  static int ext4_rmdir(struct inode *dir, struct dentry *dentry)
 	 * recovery. */
 	inode->i_size = 0;
 	ext4_orphan_add(handle, inode);
-	inode->i_ctime = dir->i_ctime = dir->i_mtime = ext4_current_time(inode);
+	now = ext4_current_time(inode);
+	VFS_INODE_SET_XTIME(i_mtime, dir, now);
+	VFS_INODE_SET_XTIME(i_ctime, dir, now);
+	VFS_INODE_SET_XTIME(i_ctime, inode, now);
 	ext4_mark_inode_dirty(handle, inode);
 	ext4_dec_count(handle, dir);
 	ext4_update_dx_flag(dir);
@@ -2984,6 +2991,7 @@  static int ext4_unlink(struct inode *dir, struct dentry *dentry)
 	struct buffer_head *bh;
 	struct ext4_dir_entry_2 *de;
 	handle_t *handle = NULL;
+	struct inode_timespec now;
 
 	trace_ext4_unlink_enter(dir, dentry);
 	/* Initialize quotas before so that eventual writes go
@@ -3027,13 +3035,15 @@  static int ext4_unlink(struct inode *dir, struct dentry *dentry)
 	retval = ext4_delete_entry(handle, dir, de, bh);
 	if (retval)
 		goto end_unlink;
-	dir->i_ctime = dir->i_mtime = ext4_current_time(dir);
+	now = ext4_current_time(dir);
+	VFS_INODE_SET_XTIME(i_mtime, dir, now);
+	VFS_INODE_SET_XTIME(i_ctime, dir, now);
 	ext4_update_dx_flag(dir);
 	ext4_mark_inode_dirty(handle, dir);
 	drop_nlink(inode);
 	if (!inode->i_nlink)
 		ext4_orphan_add(handle, inode);
-	inode->i_ctime = ext4_current_time(inode);
+	VFS_INODE_SET_XTIME(i_ctime, inode, ext4_current_time(inode));
 	ext4_mark_inode_dirty(handle, inode);
 
 end_unlink:
@@ -3226,7 +3236,7 @@  retry:
 	if (IS_DIRSYNC(dir))
 		ext4_handle_sync(handle);
 
-	inode->i_ctime = ext4_current_time(inode);
+	VFS_INODE_SET_XTIME(i_ctime, inode, ext4_current_time(inode));
 	ext4_inc_count(handle, inode);
 	ihold(inode);
 
@@ -3342,6 +3352,7 @@  static int ext4_rename_dir_finish(handle_t *handle, struct ext4_renament *ent,
 static int ext4_setent(handle_t *handle, struct ext4_renament *ent,
 		       unsigned ino, unsigned file_type)
 {
+	struct inode_timespec now;
 	int retval;
 
 	BUFFER_TRACE(ent->bh, "get write access");
@@ -3352,8 +3363,9 @@  static int ext4_setent(handle_t *handle, struct ext4_renament *ent,
 	if (ext4_has_feature_filetype(ent->dir->i_sb))
 		ent->de->file_type = file_type;
 	ent->dir->i_version++;
-	ent->dir->i_ctime = ent->dir->i_mtime =
-		ext4_current_time(ent->dir);
+	now = ext4_current_time(ent->dir);
+	VFS_INODE_SET_XTIME(i_mtime, ent->dir, now);
+	VFS_INODE_SET_XTIME(i_ctime, ent->dir, now);
 	ext4_mark_inode_dirty(handle, ent->dir);
 	BUFFER_TRACE(ent->bh, "call ext4_handle_dirty_metadata");
 	if (!ent->inlined) {
@@ -3489,6 +3501,7 @@  static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
 	int force_reread;
 	int retval;
 	struct inode *whiteout = NULL;
+	struct inode_timespec now;
 	int credits;
 	u8 old_file_type;
 
@@ -3619,7 +3632,7 @@  static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
 	 * Like most other Unix systems, set the ctime for inodes on a
 	 * rename.
 	 */
-	old.inode->i_ctime = ext4_current_time(old.inode);
+	VFS_INODE_SET_XTIME(i_ctime, old.inode, ext4_current_time(old.inode));
 	ext4_mark_inode_dirty(handle, old.inode);
 
 	if (!whiteout) {
@@ -3631,9 +3644,12 @@  static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
 
 	if (new.inode) {
 		ext4_dec_count(handle, new.inode);
-		new.inode->i_ctime = ext4_current_time(new.inode);
+		VFS_INODE_SET_XTIME(i_ctime, new.inode,
+				    ext4_current_time(new.inode));
 	}
-	old.dir->i_ctime = old.dir->i_mtime = ext4_current_time(old.dir);
+	now = ext4_current_time(old.dir);
+	VFS_INODE_SET_XTIME(i_mtime, old.dir, now);
+	VFS_INODE_SET_XTIME(i_ctime, old.dir, now);
 	ext4_update_dx_flag(old.dir);
 	if (old.dir_bh) {
 		retval = ext4_rename_dir_finish(handle, &old, new.dir->i_ino);
@@ -3785,8 +3801,8 @@  static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
 	 * Like most other Unix systems, set the ctime for inodes on a
 	 * rename.
 	 */
-	old.inode->i_ctime = ext4_current_time(old.inode);
-	new.inode->i_ctime = ext4_current_time(new.inode);
+	VFS_INODE_SET_XTIME(i_ctime, old.inode, ext4_current_time(old.inode));
+	VFS_INODE_SET_XTIME(i_ctime, new.inode, ext4_current_time(new.inode));
 	ext4_mark_inode_dirty(handle, old.inode);
 	ext4_mark_inode_dirty(handle, new.inode);
 
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 8f8aa69..2547697 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -5116,6 +5116,7 @@  static int ext4_enable_quotas(struct super_block *sb)
 static int ext4_quota_off(struct super_block *sb, int type)
 {
 	struct inode *inode = sb_dqopt(sb)->files[type];
+	struct inode_timespec now;
 	handle_t *handle;
 
 	/* Force all delayed allocation blocks to be allocated.
@@ -5131,7 +5132,10 @@  static int ext4_quota_off(struct super_block *sb, int type)
 	handle = ext4_journal_start(inode, EXT4_HT_QUOTA, 1);
 	if (IS_ERR(handle))
 		goto out;
-	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+
+	now = ext4_current_time(inode);
+	VFS_INODE_SET_XTIME(i_mtime, inode, now);
+	VFS_INODE_SET_XTIME(i_ctime, inode, now);
 	ext4_mark_inode_dirty(handle, inode);
 	ext4_journal_stop(handle);
 
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index e9b9afd..58a9392 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -1170,7 +1170,7 @@  ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
 	}
 	if (!error) {
 		ext4_xattr_update_super_block(handle, inode->i_sb);
-		inode->i_ctime = ext4_current_time(inode);
+		VFS_INODE_SET_XTIME(i_ctime, inode, ext4_current_time(inode));
 		if (!value)
 			ext4_clear_inode_state(inode, EXT4_STATE_NO_EXPAND);
 		error = ext4_mark_iloc_dirty(handle, inode, &is.iloc);