2020-04-18 22:03 GMT+09:00, Namjae Jeon <linkinjeon@xxxxxxxxxx>: > 2020-04-16 13:11 GMT+09:00, Eric Sandeen <sandeen@xxxxxxxxxxx>: > Hi Eric, > >> exfat atimes are restricted to only 2s granularity so after >> we set an atime, round it down to the nearest 2s and set the >> sub-second component of the timestamp to 0. > Is there any reason why only atime is truncated with 2s granularity ? I will directly update description more. Sorry to bother you! > > Thanks. >> >> Signed-off-by: Eric Sandeen <sandeen@xxxxxxxxxxx> >> --- >> >> V2: don't just zero tv_nsec, must also round down tv_sec I think. >> >> diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h >> index 67d4e46fb810..d67fb8a6f770 100644 >> --- a/fs/exfat/exfat_fs.h >> +++ b/fs/exfat/exfat_fs.h >> @@ -507,6 +507,7 @@ void exfat_msg(struct super_block *sb, const char >> *lv, >> const char *fmt, ...) >> __printf(3, 4) __cold; >> 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/fs/exfat/file.c b/fs/exfat/file.c >> index 483f683757aa..4f76764165cf 100644 >> --- a/fs/exfat/file.c >> +++ b/fs/exfat/file.c >> @@ -273,6 +273,7 @@ int exfat_getattr(const struct path *path, struct >> kstat >> *stat, >> struct exfat_inode_info *ei = EXFAT_I(inode); >> >> generic_fillattr(inode, stat); >> + exfat_truncate_atime(&stat->atime); >> stat->result_mask |= STATX_BTIME; >> stat->btime.tv_sec = ei->i_crtime.tv_sec; >> stat->btime.tv_nsec = ei->i_crtime.tv_nsec; >> @@ -339,6 +340,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/fs/exfat/misc.c b/fs/exfat/misc.c >> index 14a3300848f6..c8b33278d474 100644 >> --- a/fs/exfat/misc.c >> +++ b/fs/exfat/misc.c >> @@ -88,7 +88,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 >> + exfat_truncate_atime(ts); >> >> if (tz & EXFAT_TZ_VALID) >> /* Adjust timezone to UTC0. */ >> @@ -124,6 +125,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/fs/exfat/namei.c b/fs/exfat/namei.c >> index a8681d91f569..b72d782568b8 100644 >> --- a/fs/exfat/namei.c >> +++ b/fs/exfat/namei.c >> @@ -595,6 +595,7 @@ static int exfat_create(struct inode *dir, struct >> dentry >> *dentry, umode_t mode, >> inode_inc_iversion(inode); >> inode->i_mtime = inode->i_atime = inode->i_ctime = >> EXFAT_I(inode)->i_crtime = current_time(inode); >> + exfat_truncate_atime(&inode->i_atime); >> /* timestamp is already written, so mark_inode_dirty() is unneeded. */ >> >> d_instantiate(dentry, inode); >> @@ -854,6 +855,7 @@ static int exfat_unlink(struct inode *dir, struct >> dentry >> *dentry) >> >> inode_inc_iversion(dir); >> dir->i_mtime = dir->i_atime = current_time(dir); >> + exfat_truncate_atime(&dir->i_atime); >> if (IS_DIRSYNC(dir)) >> exfat_sync_inode(dir); >> else >> @@ -861,6 +863,7 @@ static int exfat_unlink(struct inode *dir, struct >> dentry >> *dentry) >> >> clear_nlink(inode); >> inode->i_mtime = inode->i_atime = current_time(inode); >> + exfat_truncate_atime(&inode->i_atime); >> exfat_unhash_inode(inode); >> exfat_d_version_set(dentry, inode_query_iversion(dir)); >> unlock: >> @@ -903,6 +906,7 @@ static int exfat_mkdir(struct inode *dir, struct >> dentry >> *dentry, umode_t mode) >> inode_inc_iversion(inode); >> inode->i_mtime = inode->i_atime = inode->i_ctime = >> EXFAT_I(inode)->i_crtime = current_time(inode); >> + exfat_truncate_atime(&inode->i_atime); >> /* timestamp is already written, so mark_inode_dirty() is unneeded. */ >> >> d_instantiate(dentry, inode); >> @@ -1019,6 +1023,7 @@ static int exfat_rmdir(struct inode *dir, struct >> dentry *dentry) >> >> inode_inc_iversion(dir); >> dir->i_mtime = dir->i_atime = current_time(dir); >> + exfat_truncate_atime(&dir->i_atime); >> if (IS_DIRSYNC(dir)) >> exfat_sync_inode(dir); >> else >> @@ -1027,6 +1032,7 @@ static int exfat_rmdir(struct inode *dir, struct >> dentry *dentry) >> >> clear_nlink(inode); >> inode->i_mtime = inode->i_atime = current_time(inode); >> + exfat_truncate_atime(&inode->i_atime); >> exfat_unhash_inode(inode); >> exfat_d_version_set(dentry, inode_query_iversion(dir)); >> unlock: >> @@ -1387,6 +1393,7 @@ static int exfat_rename(struct inode *old_dir, >> struct >> dentry *old_dentry, >> inode_inc_iversion(new_dir); >> new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime = >> EXFAT_I(new_dir)->i_crtime = current_time(new_dir); >> + exfat_truncate_atime(&new_dir->i_atime); >> if (IS_DIRSYNC(new_dir)) >> exfat_sync_inode(new_dir); >> else >> diff --git a/fs/exfat/super.c b/fs/exfat/super.c >> index 16ed202ef527..aed62cafb0da 100644 >> --- a/fs/exfat/super.c >> +++ b/fs/exfat/super.c >> @@ -351,6 +351,7 @@ static int exfat_read_root(struct inode *inode) >> exfat_save_attr(inode, ATTR_SUBDIR); >> inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime = >> current_time(inode); >> + exfat_truncate_atime(&inode->i_atime); >> exfat_cache_init_inode(inode); >> return 0; >> } >> >> >