aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorDavid Chinner <dgc@sgi.com>2006-04-11 01:11:12 -0400
committerNathan Scott <nathans@sgi.com>2006-04-11 01:11:12 -0400
commit1fc5d959d88a5f77aa7e4435f6c9d0e2d2236704 (patch)
tree0a2d3fce6b4e296f2d2dfbfdd5a58c19624d754b /fs/xfs
parent8272145c05c6d01a34f5114357c5e8093fb66472 (diff)
[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')
-rw-r--r--fs/xfs/xfs_iget.c29
-rw-r--r--fs/xfs/xfs_inode.h1
2 files changed, 13 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:
421 ip->i_chash = chlnew; 421 ip->i_chash = chlnew;
422 chlnew->chl_ip = ip; 422 chlnew->chl_ip = ip;
423 chlnew->chl_blkno = ip->i_blkno; 423 chlnew->chl_blkno = ip->i_blkno;
424 if (ch->ch_list)
425 ch->ch_list->chl_prev = chlnew;
424 chlnew->chl_next = ch->ch_list; 426 chlnew->chl_next = ch->ch_list;
427 chlnew->chl_prev = NULL;
425 ch->ch_list = chlnew; 428 ch->ch_list = chlnew;
426 chlnew = NULL; 429 chlnew = NULL;
427 } 430 }
@@ -723,23 +726,15 @@ xfs_iextract(
723 ASSERT(ip->i_cnext == ip && ip->i_cprev == ip); 726 ASSERT(ip->i_cnext == ip && ip->i_cprev == ip);
724 ASSERT(ip->i_chash != NULL); 727 ASSERT(ip->i_chash != NULL);
725 chm=NULL; 728 chm=NULL;
726 for (chl = ch->ch_list; chl != NULL; chl = chl->chl_next) { 729 chl = ip->i_chash;
727 if (chl->chl_blkno == ip->i_blkno) { 730 if (chl->chl_prev)
728 if (chm == NULL) { 731 chl->chl_prev->chl_next = chl->chl_next;
729 /* first item on the list */ 732 else
730 ch->ch_list = chl->chl_next; 733 ch->ch_list = chl->chl_next;
731 } else { 734 if (chl->chl_next)
732 chm->chl_next = chl->chl_next; 735 chl->chl_next->chl_prev = chl->chl_prev;
733 } 736 kmem_zone_free(xfs_chashlist_zone, chl);
734 kmem_zone_free(xfs_chashlist_zone, chl); 737 } else {
735 break;
736 } else {
737 ASSERT(chl->chl_ip != ip);
738 chm = chl;
739 }
740 }
741 ASSERT_ALWAYS(chl != NULL);
742 } else {
743 /* delete one inode from a non-empty list */ 738 /* delete one inode from a non-empty list */
744 iq = ip->i_cnext; 739 iq = ip->i_cnext;
745 iq->i_cprev = ip->i_cprev; 740 iq->i_cprev = ip->i_cprev;
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index 39ef9c36ea55..3b544db1790b 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -189,6 +189,7 @@ typedef struct xfs_ihash {
189 */ 189 */
190typedef struct xfs_chashlist { 190typedef struct xfs_chashlist {
191 struct xfs_chashlist *chl_next; 191 struct xfs_chashlist *chl_next;
192 struct xfs_chashlist *chl_prev;
192 struct xfs_inode *chl_ip; 193 struct xfs_inode *chl_ip;
193 xfs_daddr_t chl_blkno; /* starting block number of 194 xfs_daddr_t chl_blkno; /* starting block number of
194 * the cluster */ 195 * the cluster */