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)
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);
......
......@@ -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)
......
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