diff --git a/fs/inode.c b/fs/inode.c index e54c9ae0169b9cc74792d531947231ca56cf5428..1bb36f17bc9a7f6f07ed59bd15ac8abe06a52b3b 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1078,6 +1078,19 @@ sector_t bmap(struct inode * inode, sector_t block) return res; } +/* + * Return true if the filesystem which backs this inode considers the two + * passed timespecs to be sufficiently different to warrant flushing the + * altered time out to disk. + */ +static int inode_times_differ(struct inode *inode, + struct timespec *old, struct timespec *new) +{ + if (IS_ONE_SECOND(inode)) + return old->tv_sec != new->tv_sec; + return !timespec_equal(old, new); +} + /** * update_atime - update the access time * @inode: inode accessed @@ -1089,19 +1102,23 @@ sector_t bmap(struct inode * inode, sector_t block) void update_atime(struct inode *inode) { - struct timespec now = CURRENT_TIME; + struct timespec now; - /* Can later do this more lazily with a per superblock interval */ - if (timespec_equal(&inode->i_atime, &now)) - return; if (IS_NOATIME(inode)) return; if (IS_NODIRATIME(inode) && S_ISDIR(inode->i_mode)) return; if (IS_RDONLY(inode)) return; - inode->i_atime = now; - mark_inode_dirty_sync(inode); + + now = current_kernel_time(); + if (inode_times_differ(inode, &inode->i_atime, &now)) { + inode->i_atime = now; + mark_inode_dirty_sync(inode); + } else { + if (!timespec_equal(&inode->i_atime, &now)) + inode->i_atime = now; + } } /** @@ -1110,20 +1127,25 @@ void update_atime(struct inode *inode) * @ctime_too: update ctime too * * Update the mtime time on an inode and mark it for writeback. - * This function automatically handles read only file systems and media. * When ctime_too is specified update the ctime too. */ void inode_update_time(struct inode *inode, int ctime_too) { - struct timespec now = CURRENT_TIME; - if (timespec_equal(&inode->i_mtime, &now) && - !(ctime_too && !timespec_equal(&inode->i_ctime, &now))) - return; + struct timespec now = current_kernel_time(); + int sync_it = 0; + + if (inode_times_differ(inode, &inode->i_mtime, &now)) + sync_it = 1; inode->i_mtime = now; - if (ctime_too) + + if (ctime_too) { + if (inode_times_differ(inode, &inode->i_ctime, &now)) + sync_it = 1; inode->i_ctime = now; - mark_inode_dirty_sync(inode); + } + if (sync_it) + mark_inode_dirty_sync(inode); } EXPORT_SYMBOL(inode_update_time); diff --git a/include/linux/fs.h b/include/linux/fs.h index d6741ac40fb47b68430fcee84f4a169c00606935..45013c04e8720a9e67e3b41e402e400231785a60 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -110,6 +110,7 @@ extern int leases_enable, dir_notify_enable, lease_break_time; #define MS_REC 16384 #define MS_VERBOSE 32768 #define MS_POSIXACL (1<<16) /* VFS does not apply the umask */ +#define MS_ONE_SECOND (1<<17) /* fs has 1 sec a/m/ctime resolution */ #define MS_ACTIVE (1<<30) #define MS_NOUSER (1<<31) @@ -165,6 +166,7 @@ extern int leases_enable, dir_notify_enable, lease_break_time; #define IS_NOATIME(inode) (__IS_FLG(inode, MS_NOATIME) || ((inode)->i_flags & S_NOATIME)) #define IS_NODIRATIME(inode) __IS_FLG(inode, MS_NODIRATIME) #define IS_POSIXACL(inode) __IS_FLG(inode, MS_POSIXACL) +#define IS_ONE_SECOND(inode) __IS_FLG(inode, MS_ONE_SECOND) #define IS_DEADDIR(inode) ((inode)->i_flags & S_DEAD)