summaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_iget.c
diff options
context:
space:
mode:
authorDavid Chinner <dgc@sgi.com>2006-04-11 15:11:12 +1000
committerNathan Scott <nathans@sgi.com>2006-04-11 15:11:12 +1000
commit1fc5d959d88a5f77aa7e4435f6c9d0e2d2236704 (patch)
tree0a2d3fce6b4e296f2d2dfbfdd5a58c19624d754b /fs/xfs/xfs_iget.c
parent8272145c05c6d01a34f5114357c5e8093fb66472 (diff)
downloadlinux-1fc5d959d88a5f77aa7e4435f6c9d0e2d2236704.tar.gz
linux-1fc5d959d88a5f77aa7e4435f6c9d0e2d2236704.tar.bz2
linux-1fc5d959d88a5f77aa7e4435f6c9d0e2d2236704.zip
[XFS] Fix inode reclaim scalability regression. When a filesystem has
millions of inodes cached and has sparse cluster population, removing inodes from the cluster hash consumes excessive amounts of CPU time. Reduce the CPU cost by making removal O(1) via use of a double linked list for the hash chains. SGI-PV: 951551 SGI-Modid: xfs-linux-melb:xfs-kern:25683a Signed-off-by: David Chinner <dgc@sgi.com> Signed-off-by: Nathan Scott <nathans@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_iget.c')
-rw-r--r--fs/xfs/xfs_iget.c29
1 files changed, 12 insertions, 17 deletions
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c
index bb33113eef9f..b53854325266 100644
--- a/fs/xfs/xfs_iget.c
+++ b/fs/xfs/xfs_iget.c
@@ -421,7 +421,10 @@ finish_inode:
ip->i_chash = chlnew;
chlnew->chl_ip = ip;
chlnew->chl_blkno = ip->i_blkno;
+ if (ch->ch_list)
+ ch->ch_list->chl_prev = chlnew;
chlnew->chl_next = ch->ch_list;
+ chlnew->chl_prev = NULL;
ch->ch_list = chlnew;
chlnew = NULL;
}
@@ -723,23 +726,15 @@ xfs_iextract(
ASSERT(ip->i_cnext == ip && ip->i_cprev == ip);
ASSERT(ip->i_chash != NULL);
chm=NULL;
- for (chl = ch->ch_list; chl != NULL; chl = chl->chl_next) {
- if (chl->chl_blkno == ip->i_blkno) {
- if (chm == NULL) {
- /* first item on the list */
- ch->ch_list = chl->chl_next;
- } else {
- chm->chl_next = chl->chl_next;
- }
- kmem_zone_free(xfs_chashlist_zone, chl);
- break;
- } else {
- ASSERT(chl->chl_ip != ip);
- chm = chl;
- }
- }
- ASSERT_ALWAYS(chl != NULL);
- } else {
+ chl = ip->i_chash;
+ if (chl->chl_prev)
+ chl->chl_prev->chl_next = chl->chl_next;
+ else
+ ch->ch_list = chl->chl_next;
+ if (chl->chl_next)
+ chl->chl_next->chl_prev = chl->chl_prev;
+ kmem_zone_free(xfs_chashlist_zone, chl);
+ } else {
/* delete one inode from a non-empty list */
iq = ip->i_cnext;
iq->i_cprev = ip->i_cprev;