Skip to content

Commit 81df1ad

Browse files
sandeennamjaejeon
authored andcommitted
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: Eric Sandeen <[email protected]> Signed-off-by: Namjae Jeon <[email protected]>
1 parent 674a998 commit 81df1ad

File tree

5 files changed

+24
-1
lines changed

5 files changed

+24
-1
lines changed

fs/exfat/exfat_fs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,7 @@ void exfat_msg(struct super_block *sb, const char *lv, const char *fmt, ...)
507507
__printf(3, 4) __cold;
508508
void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
509509
u8 tz, __le16 time, __le16 date, u8 time_ms);
510+
void exfat_truncate_atime(struct timespec64 *ts);
510511
void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
511512
u8 *tz, __le16 *time, __le16 *date, u8 *time_ms);
512513
unsigned short exfat_calc_chksum_2byte(void *data, int len,

fs/exfat/file.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ int exfat_getattr(const struct path *path, struct kstat *stat,
273273
struct exfat_inode_info *ei = EXFAT_I(inode);
274274

275275
generic_fillattr(inode, stat);
276+
exfat_truncate_atime(&stat->atime);
276277
stat->result_mask |= STATX_BTIME;
277278
stat->btime.tv_sec = ei->i_crtime.tv_sec;
278279
stat->btime.tv_nsec = ei->i_crtime.tv_nsec;
@@ -339,6 +340,7 @@ int exfat_setattr(struct dentry *dentry, struct iattr *attr)
339340
}
340341

341342
setattr_copy(inode, attr);
343+
exfat_truncate_atime(&inode->i_atime);
342344
mark_inode_dirty(inode);
343345

344346
out:

fs/exfat/misc.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
8888
if (time_ms) {
8989
ts->tv_sec += time_ms / 100;
9090
ts->tv_nsec = (time_ms % 100) * 10 * NSEC_PER_MSEC;
91-
}
91+
} else
92+
ts->tv_nsec = 0;
9293

9394
if (tz & EXFAT_TZ_VALID)
9495
/* Adjust timezone to UTC0. */
@@ -124,6 +125,17 @@ void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
124125
*tz = EXFAT_TZ_VALID;
125126
}
126127

128+
/*
129+
* The timestamp for access_time has double seconds granularity.
130+
* (There is no 10msIncrement field for access_time unlike create/modify_time)
131+
* atime also has only a 2-second resolution.
132+
*/
133+
void exfat_truncate_atime(struct timespec64 *ts)
134+
{
135+
ts->tv_sec = round_down(ts->tv_sec, 2);
136+
ts->tv_nsec = 0;
137+
}
138+
127139
unsigned short exfat_calc_chksum_2byte(void *data, int len,
128140
unsigned short chksum, int type)
129141
{

fs/exfat/namei.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,7 @@ static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode,
595595
inode_inc_iversion(inode);
596596
inode->i_mtime = inode->i_atime = inode->i_ctime =
597597
EXFAT_I(inode)->i_crtime = current_time(inode);
598+
exfat_truncate_atime(&inode->i_atime);
598599
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
599600

600601
d_instantiate(dentry, inode);
@@ -854,13 +855,15 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry)
854855

855856
inode_inc_iversion(dir);
856857
dir->i_mtime = dir->i_atime = current_time(dir);
858+
exfat_truncate_atime(&dir->i_atime);
857859
if (IS_DIRSYNC(dir))
858860
exfat_sync_inode(dir);
859861
else
860862
mark_inode_dirty(dir);
861863

862864
clear_nlink(inode);
863865
inode->i_mtime = inode->i_atime = current_time(inode);
866+
exfat_truncate_atime(&inode->i_atime);
864867
exfat_unhash_inode(inode);
865868
exfat_d_version_set(dentry, inode_query_iversion(dir));
866869
unlock:
@@ -903,6 +906,7 @@ static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
903906
inode_inc_iversion(inode);
904907
inode->i_mtime = inode->i_atime = inode->i_ctime =
905908
EXFAT_I(inode)->i_crtime = current_time(inode);
909+
exfat_truncate_atime(&inode->i_atime);
906910
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
907911

908912
d_instantiate(dentry, inode);
@@ -1019,6 +1023,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
10191023

10201024
inode_inc_iversion(dir);
10211025
dir->i_mtime = dir->i_atime = current_time(dir);
1026+
exfat_truncate_atime(&dir->i_atime);
10221027
if (IS_DIRSYNC(dir))
10231028
exfat_sync_inode(dir);
10241029
else
@@ -1027,6 +1032,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
10271032

10281033
clear_nlink(inode);
10291034
inode->i_mtime = inode->i_atime = current_time(inode);
1035+
exfat_truncate_atime(&inode->i_atime);
10301036
exfat_unhash_inode(inode);
10311037
exfat_d_version_set(dentry, inode_query_iversion(dir));
10321038
unlock:
@@ -1387,6 +1393,7 @@ static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry,
13871393
inode_inc_iversion(new_dir);
13881394
new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime =
13891395
EXFAT_I(new_dir)->i_crtime = current_time(new_dir);
1396+
exfat_truncate_atime(&new_dir->i_atime);
13901397
if (IS_DIRSYNC(new_dir))
13911398
exfat_sync_inode(new_dir);
13921399
else

fs/exfat/super.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ static int exfat_read_root(struct inode *inode)
342342
exfat_save_attr(inode, ATTR_SUBDIR);
343343
inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime =
344344
current_time(inode);
345+
exfat_truncate_atime(&inode->i_atime);
345346
exfat_cache_init_inode(inode);
346347
return 0;
347348
}

0 commit comments

Comments
 (0)