For some filesystems (ext3, reiserfs at least), ->dirty_inode() is very expensive. The kernel is currently calling mark_inode_dirty() at up to 1000 times/sec/inode. But there is no need to do this if the filesystem cannot store high-resolution times on-disk. This patch restores the optimisation of only dirtying the filesystem inode when its on-disk representation has actually changed. The filesystem will set the MS_ONE_SECOND flag in sb->s_flags to indicate that it wishes to receive this treatment. 25-akpm/fs/inode.c | 48 ++++++++++++++++++++++++++++++++------------- 25-akpm/include/linux/fs.h | 2 + 2 files changed, 37 insertions(+), 13 deletions(-) diff -puN fs/inode.c~update_atime-ng fs/inode.c --- 25/fs/inode.c~update_atime-ng Wed Mar 5 13:14:51 2003 +++ 25-akpm/fs/inode.c Wed Mar 5 13:32:39 2003 @@ -1077,6 +1077,19 @@ sector_t bmap(struct inode * inode, sect 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 @@ -1088,19 +1101,23 @@ sector_t bmap(struct inode * inode, sect 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; + } } /** @@ -1109,20 +1126,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 -puN include/linux/fs.h~update_atime-ng include/linux/fs.h --- 25/include/linux/fs.h~update_atime-ng Wed Mar 5 13:16:03 2003 +++ 25-akpm/include/linux/fs.h Wed Mar 5 13:17:29 2003 @@ -110,6 +110,7 @@ extern int leases_enable, dir_notify_ena #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_ena #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) _