diff options
author | Frank Sorenson <sorenson@redhat.com> | 2018-10-30 18:06:53 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-10-31 11:54:14 -0400 |
commit | 6bb885ecd746752aa70d146b58f2f83e5e21813d (patch) | |
tree | f32ed7a4fda8e9fc8317adf2b024cd87d05fcc5a | |
parent | d9f4d94261d52a5fe31ad2ec00a06824a150af6f (diff) |
fat: add functions to update and truncate timestamps appropriately
Add the fat-specific inode_operation ->update_time() and
fat_truncate_time() function to truncate the inode timestamps from 1
nanosecond to the appropriate granularity.
Link: http://lkml.kernel.org/r/38af1ba3c3cf0d7381ce7b63077ef8af75901532.1538363961.git.sorenson@redhat.com
Signed-off-by: Frank Sorenson <sorenson@redhat.com>
Acked-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | fs/fat/fat.h | 4 | ||||
-rw-r--r-- | fs/fat/file.c | 1 | ||||
-rw-r--r-- | fs/fat/inode.c | 5 | ||||
-rw-r--r-- | fs/fat/misc.c | 75 | ||||
-rw-r--r-- | fs/fat/namei_msdos.c | 1 | ||||
-rw-r--r-- | fs/fat/namei_vfat.c | 1 |
6 files changed, 87 insertions, 0 deletions
diff --git a/fs/fat/fat.h b/fs/fat/fat.h index 9d7d2d5da28b..4e1b2f6df5e6 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h | |||
@@ -416,6 +416,10 @@ extern void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec64 *ts, | |||
416 | __le16 __time, __le16 __date, u8 time_cs); | 416 | __le16 __time, __le16 __date, u8 time_cs); |
417 | extern void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec64 *ts, | 417 | extern void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec64 *ts, |
418 | __le16 *time, __le16 *date, u8 *time_cs); | 418 | __le16 *time, __le16 *date, u8 *time_cs); |
419 | extern int fat_truncate_time(struct inode *inode, struct timespec64 *now, | ||
420 | int flags); | ||
421 | extern int fat_update_time(struct inode *inode, struct timespec64 *now, | ||
422 | int flags); | ||
419 | extern int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs); | 423 | extern int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs); |
420 | 424 | ||
421 | int fat_cache_init(void); | 425 | int fat_cache_init(void); |
diff --git a/fs/fat/file.c b/fs/fat/file.c index 4f3d72fb1e60..19b6b0566411 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c | |||
@@ -552,4 +552,5 @@ EXPORT_SYMBOL_GPL(fat_setattr); | |||
552 | const struct inode_operations fat_file_inode_operations = { | 552 | const struct inode_operations fat_file_inode_operations = { |
553 | .setattr = fat_setattr, | 553 | .setattr = fat_setattr, |
554 | .getattr = fat_getattr, | 554 | .getattr = fat_getattr, |
555 | .update_time = fat_update_time, | ||
555 | }; | 556 | }; |
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index d6b81e31f9f5..3bf60f19b6d3 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c | |||
@@ -1626,6 +1626,11 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, | |||
1626 | sb->s_magic = MSDOS_SUPER_MAGIC; | 1626 | sb->s_magic = MSDOS_SUPER_MAGIC; |
1627 | sb->s_op = &fat_sops; | 1627 | sb->s_op = &fat_sops; |
1628 | sb->s_export_op = &fat_export_ops; | 1628 | sb->s_export_op = &fat_export_ops; |
1629 | /* | ||
1630 | * fat timestamps are complex and truncated by fat itself, so | ||
1631 | * we set 1 here to be fast | ||
1632 | */ | ||
1633 | sb->s_time_gran = 1; | ||
1629 | mutex_init(&sbi->nfs_build_inode_lock); | 1634 | mutex_init(&sbi->nfs_build_inode_lock); |
1630 | ratelimit_state_init(&sbi->ratelimit, DEFAULT_RATELIMIT_INTERVAL, | 1635 | ratelimit_state_init(&sbi->ratelimit, DEFAULT_RATELIMIT_INTERVAL, |
1631 | DEFAULT_RATELIMIT_BURST); | 1636 | DEFAULT_RATELIMIT_BURST); |
diff --git a/fs/fat/misc.c b/fs/fat/misc.c index 2eca073fe785..fce0a76f3f1e 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c | |||
@@ -7,6 +7,7 @@ | |||
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include "fat.h" | 9 | #include "fat.h" |
10 | #include <linux/iversion.h> | ||
10 | 11 | ||
11 | /* | 12 | /* |
12 | * fat_fs_error reports a file system problem that might indicate fa data | 13 | * fat_fs_error reports a file system problem that might indicate fa data |
@@ -265,6 +266,80 @@ void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec64 *ts, | |||
265 | } | 266 | } |
266 | EXPORT_SYMBOL_GPL(fat_time_unix2fat); | 267 | EXPORT_SYMBOL_GPL(fat_time_unix2fat); |
267 | 268 | ||
269 | static inline struct timespec64 fat_timespec64_trunc_2secs(struct timespec64 ts) | ||
270 | { | ||
271 | return (struct timespec64){ ts.tv_sec & ~1ULL, 0 }; | ||
272 | } | ||
273 | /* | ||
274 | * truncate the various times with appropriate granularity: | ||
275 | * root inode: | ||
276 | * all times always 0 | ||
277 | * all other inodes: | ||
278 | * mtime - 2 seconds | ||
279 | * ctime | ||
280 | * msdos - 2 seconds | ||
281 | * vfat - 10 milliseconds | ||
282 | * atime - 24 hours (00:00:00 in local timezone) | ||
283 | */ | ||
284 | int fat_truncate_time(struct inode *inode, struct timespec64 *now, int flags) | ||
285 | { | ||
286 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | ||
287 | struct timespec64 ts; | ||
288 | |||
289 | if (inode->i_ino == MSDOS_ROOT_INO) | ||
290 | return 0; | ||
291 | |||
292 | if (now == NULL) { | ||
293 | now = &ts; | ||
294 | ts = current_time(inode); | ||
295 | } | ||
296 | |||
297 | if (flags & S_ATIME) { | ||
298 | /* to localtime */ | ||
299 | time64_t seconds = now->tv_sec - fat_tz_offset(sbi); | ||
300 | s32 remainder; | ||
301 | |||
302 | div_s64_rem(seconds, SECS_PER_DAY, &remainder); | ||
303 | /* to day boundary, and back to unix time */ | ||
304 | seconds = seconds + fat_tz_offset(sbi) - remainder; | ||
305 | |||
306 | inode->i_atime = (struct timespec64){ seconds, 0 }; | ||
307 | } | ||
308 | if (flags & S_CTIME) { | ||
309 | if (sbi->options.isvfat) | ||
310 | inode->i_ctime = timespec64_trunc(*now, 10000000); | ||
311 | else | ||
312 | inode->i_ctime = fat_timespec64_trunc_2secs(*now); | ||
313 | } | ||
314 | if (flags & S_MTIME) | ||
315 | inode->i_mtime = fat_timespec64_trunc_2secs(*now); | ||
316 | |||
317 | return 0; | ||
318 | } | ||
319 | EXPORT_SYMBOL_GPL(fat_truncate_time); | ||
320 | |||
321 | int fat_update_time(struct inode *inode, struct timespec64 *now, int flags) | ||
322 | { | ||
323 | int iflags = I_DIRTY_TIME; | ||
324 | bool dirty = false; | ||
325 | |||
326 | if (inode->i_ino == MSDOS_ROOT_INO) | ||
327 | return 0; | ||
328 | |||
329 | fat_truncate_time(inode, now, flags); | ||
330 | if (flags & S_VERSION) | ||
331 | dirty = inode_maybe_inc_iversion(inode, false); | ||
332 | if ((flags & (S_ATIME | S_CTIME | S_MTIME)) && | ||
333 | !(inode->i_sb->s_flags & SB_LAZYTIME)) | ||
334 | dirty = true; | ||
335 | |||
336 | if (dirty) | ||
337 | iflags |= I_DIRTY_SYNC; | ||
338 | __mark_inode_dirty(inode, iflags); | ||
339 | return 0; | ||
340 | } | ||
341 | EXPORT_SYMBOL_GPL(fat_update_time); | ||
342 | |||
268 | int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs) | 343 | int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs) |
269 | { | 344 | { |
270 | int i, err = 0; | 345 | int i, err = 0; |
diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index efb8c40c9d27..effbdd5fbf6e 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c | |||
@@ -637,6 +637,7 @@ static const struct inode_operations msdos_dir_inode_operations = { | |||
637 | .rename = msdos_rename, | 637 | .rename = msdos_rename, |
638 | .setattr = fat_setattr, | 638 | .setattr = fat_setattr, |
639 | .getattr = fat_getattr, | 639 | .getattr = fat_getattr, |
640 | .update_time = fat_update_time, | ||
640 | }; | 641 | }; |
641 | 642 | ||
642 | static void setup(struct super_block *sb) | 643 | static void setup(struct super_block *sb) |
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index 82cd1e69cbdf..1daa57cf4bf3 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c | |||
@@ -1032,6 +1032,7 @@ static const struct inode_operations vfat_dir_inode_operations = { | |||
1032 | .rename = vfat_rename, | 1032 | .rename = vfat_rename, |
1033 | .setattr = fat_setattr, | 1033 | .setattr = fat_setattr, |
1034 | .getattr = fat_getattr, | 1034 | .getattr = fat_getattr, |
1035 | .update_time = fat_update_time, | ||
1035 | }; | 1036 | }; |
1036 | 1037 | ||
1037 | static void setup(struct super_block *sb) | 1038 | static void setup(struct super_block *sb) |