aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/linux-2.6
diff options
context:
space:
mode:
authorDavid Chinner <david@fromorbit.com>2008-10-30 02:38:00 -0400
committerLachlan McIlroy <lachlan@sgi.com>2008-10-30 02:38:00 -0400
commit8c38ab032094ff1d903c79db689607b1ebae13ca (patch)
tree06148b37fd9706e842d7653adcd9e9ac83a73f53 /fs/xfs/linux-2.6
parent116545130cbc5214523c2f994a11c81ef9eb9186 (diff)
[XFS] Prevent looping in xfs_sync_inodes_ag
If the last block of the AG has inodes in it and the AG is an exactly power-of-2 size then the last inode in the AG points to the last block in the AG. If we try to find the next inode in the AG by adding one to the inode number, we increment the inode number past the size of the AG. The result is that the macro XFS_INO_TO_AGINO() will strip the AG portion of the inode number and return an inode number of zero. That is, instead of terminating the lookup loop because we hit the inode number went outside the valid range for the AG, the search index returns to zero and we start traversing the radix tree from the start again. This results in an endless loop in xfs_sync_inodes_ag(). Fix it be detecting if the new search index decreases as a result of incrementing the current inode number. That indicate an overflow and hence that we have finished processing the AG so we can terminate the loop. SGI-PV: 988142 SGI-Modid: xfs-linux-melb:xfs-kern:32335a Signed-off-by: David Chinner <david@fromorbit.com> Signed-off-by: Lachlan McIlroy <lachlan@sgi.com> Signed-off-by: Christoph Hellwig <hch@infradead.org>
Diffstat (limited to 'fs/xfs/linux-2.6')
-rw-r--r--fs/xfs/linux-2.6/xfs_sync.c26
1 files changed, 22 insertions, 4 deletions
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c
index 22006b5733c4..ee1648b179f7 100644
--- a/fs/xfs/linux-2.6/xfs_sync.c
+++ b/fs/xfs/linux-2.6/xfs_sync.c
@@ -59,7 +59,7 @@ xfs_sync_inodes_ag(
59{ 59{
60 xfs_perag_t *pag = &mp->m_perag[ag]; 60 xfs_perag_t *pag = &mp->m_perag[ag];
61 int nr_found; 61 int nr_found;
62 int first_index = 0; 62 uint32_t first_index = 0;
63 int error = 0; 63 int error = 0;
64 int last_error = 0; 64 int last_error = 0;
65 int fflag = XFS_B_ASYNC; 65 int fflag = XFS_B_ASYNC;
@@ -97,8 +97,17 @@ xfs_sync_inodes_ag(
97 break; 97 break;
98 } 98 }
99 99
100 /* update the index for the next lookup */ 100 /*
101 * Update the index for the next lookup. Catch overflows
102 * into the next AG range which can occur if we have inodes
103 * in the last block of the AG and we are currently
104 * pointing to the last inode.
105 */
101 first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1); 106 first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1);
107 if (first_index < XFS_INO_TO_AGINO(mp, ip->i_ino)) {
108 read_unlock(&pag->pag_ici_lock);
109 break;
110 }
102 111
103 /* 112 /*
104 * skip inodes in reclaim. Let xfs_syncsub do that for 113 * skip inodes in reclaim. Let xfs_syncsub do that for
@@ -702,7 +711,7 @@ xfs_reclaim_inodes_ag(
702 xfs_inode_t *ip = NULL; 711 xfs_inode_t *ip = NULL;
703 xfs_perag_t *pag = &mp->m_perag[ag]; 712 xfs_perag_t *pag = &mp->m_perag[ag];
704 int nr_found; 713 int nr_found;
705 int first_index; 714 uint32_t first_index;
706 int skipped; 715 int skipped;
707 716
708restart: 717restart:
@@ -724,8 +733,17 @@ restart:
724 break; 733 break;
725 } 734 }
726 735
727 /* update the index for the next lookup */ 736 /*
737 * Update the index for the next lookup. Catch overflows
738 * into the next AG range which can occur if we have inodes
739 * in the last block of the AG and we are currently
740 * pointing to the last inode.
741 */
728 first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1); 742 first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1);
743 if (first_index < XFS_INO_TO_AGINO(mp, ip->i_ino)) {
744 read_unlock(&pag->pag_ici_lock);
745 break;
746 }
729 747
730 ASSERT(xfs_iflags_test(ip, (XFS_IRECLAIMABLE|XFS_IRECLAIM))); 748 ASSERT(xfs_iflags_test(ip, (XFS_IRECLAIMABLE|XFS_IRECLAIM)));
731 749