diff --git a/exfat_fs.h b/exfat_fs.h index ca683ab1de47..828262c03eb9 100644 --- a/exfat_fs.h +++ b/exfat_fs.h @@ -519,6 +519,7 @@ void exfat_msg(struct super_block *sb, const char *lv, const char *fmt, ...) void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, u8 tz, __le16 time, __le16 date, u8 time_ms); +void exfat_truncate_atime(struct timespec64 *ts); void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, u8 *tz, __le16 *time, __le16 *date, u8 *time_ms); unsigned short exfat_calc_chksum_2byte(void *data, int len, diff --git a/file.c b/file.c index 415a8d48849e..93d044959c49 100644 --- a/file.c +++ b/file.c @@ -300,6 +300,7 @@ int exfat_getattr(struct vfsmount *mnt, struct dentry *dentry, #endif generic_fillattr(inode, stat); + exfat_truncate_atime(&stat->atime); #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) stat->result_mask |= STATX_BTIME; stat->btime.tv_sec = ei->i_crtime.tv_sec; @@ -374,6 +375,7 @@ int exfat_setattr(struct dentry *dentry, struct iattr *attr) } setattr_copy(inode, attr); + exfat_truncate_atime(&inode->i_atime); mark_inode_dirty(inode); out: diff --git a/misc.c b/misc.c index 234a2d8ec515..bf6e8cdd5d36 100644 --- a/misc.c +++ b/misc.c @@ -94,7 +94,8 @@ void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, if (time_ms) { ts->tv_sec += time_ms / 100; ts->tv_nsec = (time_ms % 100) * 10 * NSEC_PER_MSEC; - } + } else + ts->tv_nsec = 0; if (tz & EXFAT_TZ_VALID) /* Adjust timezone to UTC0. */ @@ -134,6 +135,13 @@ void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, *tz = EXFAT_TZ_VALID; } +/* atime has only a 2-second resolution */ +void exfat_truncate_atime(struct timespec64 *ts) +{ + ts->tv_sec = round_down(ts->tv_sec, 2); + ts->tv_nsec = 0; +} + unsigned short exfat_calc_chksum_2byte(void *data, int len, unsigned short chksum, int type) { diff --git a/namei.c b/namei.c index 9920203271c1..1987864e66e9 100644 --- a/namei.c +++ b/namei.c @@ -629,6 +629,7 @@ static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, inode->i_mtime = inode->i_atime = inode->i_ctime = EXFAT_I(inode)->i_crtime = CURRENT_TIME_SEC; #endif + exfat_truncate_atime(&inode->i_atime); /* timestamp is already written, so mark_inode_dirty() is unneeded. */ d_instantiate(dentry, inode); @@ -908,6 +909,7 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry) #else dir->i_mtime = dir->i_atime = CURRENT_TIME_SEC; #endif + exfat_truncate_atime(&dir->i_atime); if (IS_DIRSYNC(dir)) exfat_sync_inode(dir); else @@ -919,6 +921,7 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry) #else inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC; #endif + exfat_truncate_atime(&inode->i_atime); exfat_unhash_inode(inode); #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0) exfat_d_version_set(dentry, inode_query_iversion(dir)); @@ -983,6 +986,7 @@ static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) inode->i_mtime = inode->i_atime = inode->i_ctime = EXFAT_I(inode)->i_crtime = CURRENT_TIME_SEC; #endif + exfat_truncate_atime(&inode->i_atime); /* timestamp is already written, so mark_inode_dirty() is unneeded. */ d_instantiate(dentry, inode); @@ -1104,6 +1108,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry) #else dir->i_mtime = dir->i_atime = CURRENT_TIME_SEC; #endif + exfat_truncate_atime(&dir->i_atime); if (IS_DIRSYNC(dir)) exfat_sync_inode(dir); else @@ -1116,6 +1121,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry) #else inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC; #endif + exfat_truncate_atime(&inode->i_atime); exfat_unhash_inode(inode); #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0) exfat_d_version_set(dentry, inode_query_iversion(dir)); @@ -1494,6 +1500,7 @@ static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime = EXFAT_I(new_dir)->i_crtime = CURRENT_TIME_SEC; #endif + exfat_truncate_atime(&new_dir->i_atime); if (IS_DIRSYNC(new_dir)) exfat_sync_inode(new_dir); else diff --git a/super.c b/super.c index bcc362dcb52a..391cc171f04e 100644 --- a/super.c +++ b/super.c @@ -547,6 +547,7 @@ static int exfat_read_root(struct inode *inode) inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime = CURRENT_TIME_SEC; #endif + exfat_truncate_atime(&inode->i_atime); exfat_cache_init_inode(inode); return 0; }