Commit fd2134bb authored by Andrew Morton's avatar Andrew Morton Committed by David S. Miller

[PATCH] inode a/c/mtime modification speedup

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.

The patch does reduce the call rate to ext3_mark_inode_dirty() from 1000/sec
to 1/sec, but it doesn't make much difference at all to performance because
we're calling ext3_mark_inode_dirty() from other callsites as well.  Those
can be optimised too.
parent 00bc7fc6
...@@ -1078,6 +1078,19 @@ sector_t bmap(struct inode * inode, sector_t block) ...@@ -1078,6 +1078,19 @@ sector_t bmap(struct inode * inode, sector_t block)
return res; 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 * update_atime - update the access time
* @inode: inode accessed * @inode: inode accessed
...@@ -1089,19 +1102,23 @@ sector_t bmap(struct inode * inode, sector_t block) ...@@ -1089,19 +1102,23 @@ sector_t bmap(struct inode * inode, sector_t block)
void update_atime(struct inode *inode) 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)) if (IS_NOATIME(inode))
return; return;
if (IS_NODIRATIME(inode) && S_ISDIR(inode->i_mode)) if (IS_NODIRATIME(inode) && S_ISDIR(inode->i_mode))
return; return;
if (IS_RDONLY(inode)) if (IS_RDONLY(inode))
return; return;
now = current_kernel_time();
if (inode_times_differ(inode, &inode->i_atime, &now)) {
inode->i_atime = now; inode->i_atime = now;
mark_inode_dirty_sync(inode); mark_inode_dirty_sync(inode);
} else {
if (!timespec_equal(&inode->i_atime, &now))
inode->i_atime = now;
}
} }
/** /**
...@@ -1110,19 +1127,24 @@ void update_atime(struct inode *inode) ...@@ -1110,19 +1127,24 @@ void update_atime(struct inode *inode)
* @ctime_too: update ctime too * @ctime_too: update ctime too
* *
* Update the mtime time on an inode and mark it for writeback. * 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. * When ctime_too is specified update the ctime too.
*/ */
void inode_update_time(struct inode *inode, int ctime_too) void inode_update_time(struct inode *inode, int ctime_too)
{ {
struct timespec now = CURRENT_TIME; struct timespec now = current_kernel_time();
if (timespec_equal(&inode->i_mtime, &now) && int sync_it = 0;
!(ctime_too && !timespec_equal(&inode->i_ctime, &now)))
return; if (inode_times_differ(inode, &inode->i_mtime, &now))
sync_it = 1;
inode->i_mtime = now; 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; inode->i_ctime = now;
}
if (sync_it)
mark_inode_dirty_sync(inode); mark_inode_dirty_sync(inode);
} }
EXPORT_SYMBOL(inode_update_time); EXPORT_SYMBOL(inode_update_time);
......
...@@ -110,6 +110,7 @@ extern int leases_enable, dir_notify_enable, lease_break_time; ...@@ -110,6 +110,7 @@ extern int leases_enable, dir_notify_enable, lease_break_time;
#define MS_REC 16384 #define MS_REC 16384
#define MS_VERBOSE 32768 #define MS_VERBOSE 32768
#define MS_POSIXACL (1<<16) /* VFS does not apply the umask */ #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_ACTIVE (1<<30)
#define MS_NOUSER (1<<31) #define MS_NOUSER (1<<31)
...@@ -165,6 +166,7 @@ extern int leases_enable, dir_notify_enable, lease_break_time; ...@@ -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_NOATIME(inode) (__IS_FLG(inode, MS_NOATIME) || ((inode)->i_flags & S_NOATIME))
#define IS_NODIRATIME(inode) __IS_FLG(inode, MS_NODIRATIME) #define IS_NODIRATIME(inode) __IS_FLG(inode, MS_NODIRATIME)
#define IS_POSIXACL(inode) __IS_FLG(inode, MS_POSIXACL) #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) #define IS_DEADDIR(inode) ((inode)->i_flags & S_DEAD)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment