summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrank Sorenson <sorenson@redhat.com>2018-10-30 18:06:53 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-10-31 11:54:14 -0400
commit6bb885ecd746752aa70d146b58f2f83e5e21813d (patch)
treef32ed7a4fda8e9fc8317adf2b024cd87d05fcc5a
parentd9f4d94261d52a5fe31ad2ec00a06824a150af6f (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.h4
-rw-r--r--fs/fat/file.c1
-rw-r--r--fs/fat/inode.c5
-rw-r--r--fs/fat/misc.c75
-rw-r--r--fs/fat/namei_msdos.c1
-rw-r--r--fs/fat/namei_vfat.c1
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);
417extern void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec64 *ts, 417extern 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);
419extern int fat_truncate_time(struct inode *inode, struct timespec64 *now,
420 int flags);
421extern int fat_update_time(struct inode *inode, struct timespec64 *now,
422 int flags);
419extern int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs); 423extern int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs);
420 424
421int fat_cache_init(void); 425int 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);
552const struct inode_operations fat_file_inode_operations = { 552const 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}
266EXPORT_SYMBOL_GPL(fat_time_unix2fat); 267EXPORT_SYMBOL_GPL(fat_time_unix2fat);
267 268
269static 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 */
284int 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}
319EXPORT_SYMBOL_GPL(fat_truncate_time);
320
321int 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}
341EXPORT_SYMBOL_GPL(fat_update_time);
342
268int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs) 343int 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
642static void setup(struct super_block *sb) 643static 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
1037static void setup(struct super_block *sb) 1038static void setup(struct super_block *sb)