Commit 81df1ad4 authored by Eric Sandeen's avatar Eric Sandeen Committed by Namjae Jeon

exfat: truncate atimes to 2s granularity

The timestamp for access_time has double seconds granularity(There is no
10msIncrement field for access_time unlike create/modify_time).
exfat's 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.
Signed-off-by: default avatarEric Sandeen <sandeen@sandeen.net>
Signed-off-by: default avatarNamjae Jeon <namjae.jeon@samsung.com>
parent 674a9985
...@@ -507,6 +507,7 @@ void exfat_msg(struct super_block *sb, const char *lv, const char *fmt, ...) ...@@ -507,6 +507,7 @@ void exfat_msg(struct super_block *sb, const char *lv, const char *fmt, ...)
__printf(3, 4) __cold; __printf(3, 4) __cold;
void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
u8 tz, __le16 time, __le16 date, u8 time_ms); 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, void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
u8 *tz, __le16 *time, __le16 *date, u8 *time_ms); u8 *tz, __le16 *time, __le16 *date, u8 *time_ms);
unsigned short exfat_calc_chksum_2byte(void *data, int len, unsigned short exfat_calc_chksum_2byte(void *data, int len,
......
...@@ -273,6 +273,7 @@ int exfat_getattr(const struct path *path, struct kstat *stat, ...@@ -273,6 +273,7 @@ int exfat_getattr(const struct path *path, struct kstat *stat,
struct exfat_inode_info *ei = EXFAT_I(inode); struct exfat_inode_info *ei = EXFAT_I(inode);
generic_fillattr(inode, stat); generic_fillattr(inode, stat);
exfat_truncate_atime(&stat->atime);
stat->result_mask |= STATX_BTIME; stat->result_mask |= STATX_BTIME;
stat->btime.tv_sec = ei->i_crtime.tv_sec; stat->btime.tv_sec = ei->i_crtime.tv_sec;
stat->btime.tv_nsec = ei->i_crtime.tv_nsec; stat->btime.tv_nsec = ei->i_crtime.tv_nsec;
...@@ -339,6 +340,7 @@ int exfat_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -339,6 +340,7 @@ int exfat_setattr(struct dentry *dentry, struct iattr *attr)
} }
setattr_copy(inode, attr); setattr_copy(inode, attr);
exfat_truncate_atime(&inode->i_atime);
mark_inode_dirty(inode); mark_inode_dirty(inode);
out: out:
......
...@@ -88,7 +88,8 @@ void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, ...@@ -88,7 +88,8 @@ void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
if (time_ms) { if (time_ms) {
ts->tv_sec += time_ms / 100; ts->tv_sec += time_ms / 100;
ts->tv_nsec = (time_ms % 100) * 10 * NSEC_PER_MSEC; ts->tv_nsec = (time_ms % 100) * 10 * NSEC_PER_MSEC;
} } else
ts->tv_nsec = 0;
if (tz & EXFAT_TZ_VALID) if (tz & EXFAT_TZ_VALID)
/* Adjust timezone to UTC0. */ /* Adjust timezone to UTC0. */
...@@ -124,6 +125,17 @@ void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, ...@@ -124,6 +125,17 @@ void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
*tz = EXFAT_TZ_VALID; *tz = EXFAT_TZ_VALID;
} }
/*
* The timestamp for access_time has double seconds granularity.
* (There is no 10msIncrement field for access_time unlike create/modify_time)
* atime also 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 exfat_calc_chksum_2byte(void *data, int len,
unsigned short chksum, int type) unsigned short chksum, int type)
{ {
......
...@@ -595,6 +595,7 @@ static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, ...@@ -595,6 +595,7 @@ static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode,
inode_inc_iversion(inode); inode_inc_iversion(inode);
inode->i_mtime = inode->i_atime = inode->i_ctime = inode->i_mtime = inode->i_atime = inode->i_ctime =
EXFAT_I(inode)->i_crtime = current_time(inode); EXFAT_I(inode)->i_crtime = current_time(inode);
exfat_truncate_atime(&inode->i_atime);
/* timestamp is already written, so mark_inode_dirty() is unneeded. */ /* timestamp is already written, so mark_inode_dirty() is unneeded. */
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
...@@ -854,6 +855,7 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry) ...@@ -854,6 +855,7 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry)
inode_inc_iversion(dir); inode_inc_iversion(dir);
dir->i_mtime = dir->i_atime = current_time(dir); dir->i_mtime = dir->i_atime = current_time(dir);
exfat_truncate_atime(&dir->i_atime);
if (IS_DIRSYNC(dir)) if (IS_DIRSYNC(dir))
exfat_sync_inode(dir); exfat_sync_inode(dir);
else else
...@@ -861,6 +863,7 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry) ...@@ -861,6 +863,7 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry)
clear_nlink(inode); clear_nlink(inode);
inode->i_mtime = inode->i_atime = current_time(inode); inode->i_mtime = inode->i_atime = current_time(inode);
exfat_truncate_atime(&inode->i_atime);
exfat_unhash_inode(inode); exfat_unhash_inode(inode);
exfat_d_version_set(dentry, inode_query_iversion(dir)); exfat_d_version_set(dentry, inode_query_iversion(dir));
unlock: unlock:
...@@ -903,6 +906,7 @@ static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -903,6 +906,7 @@ static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
inode_inc_iversion(inode); inode_inc_iversion(inode);
inode->i_mtime = inode->i_atime = inode->i_ctime = inode->i_mtime = inode->i_atime = inode->i_ctime =
EXFAT_I(inode)->i_crtime = current_time(inode); EXFAT_I(inode)->i_crtime = current_time(inode);
exfat_truncate_atime(&inode->i_atime);
/* timestamp is already written, so mark_inode_dirty() is unneeded. */ /* timestamp is already written, so mark_inode_dirty() is unneeded. */
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
...@@ -1019,6 +1023,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -1019,6 +1023,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
inode_inc_iversion(dir); inode_inc_iversion(dir);
dir->i_mtime = dir->i_atime = current_time(dir); dir->i_mtime = dir->i_atime = current_time(dir);
exfat_truncate_atime(&dir->i_atime);
if (IS_DIRSYNC(dir)) if (IS_DIRSYNC(dir))
exfat_sync_inode(dir); exfat_sync_inode(dir);
else else
...@@ -1027,6 +1032,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -1027,6 +1032,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
clear_nlink(inode); clear_nlink(inode);
inode->i_mtime = inode->i_atime = current_time(inode); inode->i_mtime = inode->i_atime = current_time(inode);
exfat_truncate_atime(&inode->i_atime);
exfat_unhash_inode(inode); exfat_unhash_inode(inode);
exfat_d_version_set(dentry, inode_query_iversion(dir)); exfat_d_version_set(dentry, inode_query_iversion(dir));
unlock: unlock:
...@@ -1387,6 +1393,7 @@ static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1387,6 +1393,7 @@ static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry,
inode_inc_iversion(new_dir); inode_inc_iversion(new_dir);
new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime = new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime =
EXFAT_I(new_dir)->i_crtime = current_time(new_dir); EXFAT_I(new_dir)->i_crtime = current_time(new_dir);
exfat_truncate_atime(&new_dir->i_atime);
if (IS_DIRSYNC(new_dir)) if (IS_DIRSYNC(new_dir))
exfat_sync_inode(new_dir); exfat_sync_inode(new_dir);
else else
......
...@@ -342,6 +342,7 @@ static int exfat_read_root(struct inode *inode) ...@@ -342,6 +342,7 @@ static int exfat_read_root(struct inode *inode)
exfat_save_attr(inode, ATTR_SUBDIR); exfat_save_attr(inode, ATTR_SUBDIR);
inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime = inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime =
current_time(inode); current_time(inode);
exfat_truncate_atime(&inode->i_atime);
exfat_cache_init_inode(inode); exfat_cache_init_inode(inode);
return 0; return 0;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment