mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 16:54:21 +00:00 
			
		
		
		
	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>
This commit is contained in:
		
							parent
							
								
									d9f4d94261
								
							
						
					
					
						commit
						6bb885ecd7
					
				
					 6 changed files with 87 additions and 0 deletions
				
			
		|  | @ -416,6 +416,10 @@ extern void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec64 *ts, | |||
| 			      __le16 __time, __le16 __date, u8 time_cs); | ||||
| extern void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec64 *ts, | ||||
| 			      __le16 *time, __le16 *date, u8 *time_cs); | ||||
| extern int fat_truncate_time(struct inode *inode, struct timespec64 *now, | ||||
| 			     int flags); | ||||
| extern int fat_update_time(struct inode *inode, struct timespec64 *now, | ||||
| 			   int flags); | ||||
| extern int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs); | ||||
| 
 | ||||
| int fat_cache_init(void); | ||||
|  |  | |||
|  | @ -552,4 +552,5 @@ EXPORT_SYMBOL_GPL(fat_setattr); | |||
| const struct inode_operations fat_file_inode_operations = { | ||||
| 	.setattr	= fat_setattr, | ||||
| 	.getattr	= fat_getattr, | ||||
| 	.update_time	= fat_update_time, | ||||
| }; | ||||
|  |  | |||
|  | @ -1626,6 +1626,11 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, | |||
| 	sb->s_magic = MSDOS_SUPER_MAGIC; | ||||
| 	sb->s_op = &fat_sops; | ||||
| 	sb->s_export_op = &fat_export_ops; | ||||
| 	/*
 | ||||
| 	 * fat timestamps are complex and truncated by fat itself, so | ||||
| 	 * we set 1 here to be fast | ||||
| 	 */ | ||||
| 	sb->s_time_gran = 1; | ||||
| 	mutex_init(&sbi->nfs_build_inode_lock); | ||||
| 	ratelimit_state_init(&sbi->ratelimit, DEFAULT_RATELIMIT_INTERVAL, | ||||
| 			     DEFAULT_RATELIMIT_BURST); | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ | |||
|  */ | ||||
| 
 | ||||
| #include "fat.h" | ||||
| #include <linux/iversion.h> | ||||
| 
 | ||||
| /*
 | ||||
|  * 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, | |||
| } | ||||
| EXPORT_SYMBOL_GPL(fat_time_unix2fat); | ||||
| 
 | ||||
| static inline struct timespec64 fat_timespec64_trunc_2secs(struct timespec64 ts) | ||||
| { | ||||
| 	return (struct timespec64){ ts.tv_sec & ~1ULL, 0 }; | ||||
| } | ||||
| /*
 | ||||
|  * truncate the various times with appropriate granularity: | ||||
|  *   root inode: | ||||
|  *     all times always 0 | ||||
|  *   all other inodes: | ||||
|  *     mtime - 2 seconds | ||||
|  *     ctime | ||||
|  *       msdos - 2 seconds | ||||
|  *       vfat  - 10 milliseconds | ||||
|  *     atime - 24 hours (00:00:00 in local timezone) | ||||
|  */ | ||||
| int fat_truncate_time(struct inode *inode, struct timespec64 *now, int flags) | ||||
| { | ||||
| 	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | ||||
| 	struct timespec64 ts; | ||||
| 
 | ||||
| 	if (inode->i_ino == MSDOS_ROOT_INO) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (now == NULL) { | ||||
| 		now = &ts; | ||||
| 		ts = current_time(inode); | ||||
| 	} | ||||
| 
 | ||||
| 	if (flags & S_ATIME) { | ||||
| 		/* to localtime */ | ||||
| 		time64_t seconds = now->tv_sec - fat_tz_offset(sbi); | ||||
| 		s32 remainder; | ||||
| 
 | ||||
| 		div_s64_rem(seconds, SECS_PER_DAY, &remainder); | ||||
| 		/* to day boundary, and back to unix time */ | ||||
| 		seconds = seconds + fat_tz_offset(sbi) - remainder; | ||||
| 
 | ||||
| 		inode->i_atime = (struct timespec64){ seconds, 0 }; | ||||
| 	} | ||||
| 	if (flags & S_CTIME) { | ||||
| 		if (sbi->options.isvfat) | ||||
| 			inode->i_ctime = timespec64_trunc(*now, 10000000); | ||||
| 		else | ||||
| 			inode->i_ctime = fat_timespec64_trunc_2secs(*now); | ||||
| 	} | ||||
| 	if (flags & S_MTIME) | ||||
| 		inode->i_mtime = fat_timespec64_trunc_2secs(*now); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(fat_truncate_time); | ||||
| 
 | ||||
| int fat_update_time(struct inode *inode, struct timespec64 *now, int flags) | ||||
| { | ||||
| 	int iflags = I_DIRTY_TIME; | ||||
| 	bool dirty = false; | ||||
| 
 | ||||
| 	if (inode->i_ino == MSDOS_ROOT_INO) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	fat_truncate_time(inode, now, flags); | ||||
| 	if (flags & S_VERSION) | ||||
| 		dirty = inode_maybe_inc_iversion(inode, false); | ||||
| 	if ((flags & (S_ATIME | S_CTIME | S_MTIME)) && | ||||
| 	    !(inode->i_sb->s_flags & SB_LAZYTIME)) | ||||
| 		dirty = true; | ||||
| 
 | ||||
| 	if (dirty) | ||||
| 		iflags |= I_DIRTY_SYNC; | ||||
| 	__mark_inode_dirty(inode, iflags); | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(fat_update_time); | ||||
| 
 | ||||
| int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs) | ||||
| { | ||||
| 	int i, err = 0; | ||||
|  |  | |||
|  | @ -637,6 +637,7 @@ static const struct inode_operations msdos_dir_inode_operations = { | |||
| 	.rename		= msdos_rename, | ||||
| 	.setattr	= fat_setattr, | ||||
| 	.getattr	= fat_getattr, | ||||
| 	.update_time	= fat_update_time, | ||||
| }; | ||||
| 
 | ||||
| static void setup(struct super_block *sb) | ||||
|  |  | |||
|  | @ -1032,6 +1032,7 @@ static const struct inode_operations vfat_dir_inode_operations = { | |||
| 	.rename		= vfat_rename, | ||||
| 	.setattr	= fat_setattr, | ||||
| 	.getattr	= fat_getattr, | ||||
| 	.update_time	= fat_update_time, | ||||
| }; | ||||
| 
 | ||||
| static void setup(struct super_block *sb) | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Frank Sorenson
						Frank Sorenson