diff options
author | Nathan Scott <nathans@sgi.com> | 2006-03-17 01:26:04 -0500 |
---|---|---|
committer | Nathan Scott <nathans@sgi.com> | 2006-03-17 01:26:04 -0500 |
commit | b12dd34298cf0cff9f337f667045335140873039 (patch) | |
tree | 0f2ef353bc17f247e538a28137a0a3f8ad3b5e0e | |
parent | 2ddd5928d01ca8eb49f55166411b64a5844a8959 (diff) |
[XFS] Fix an infinite loop issue in bulkstat when a corrupt inode is
detected. Thanks to Roger Willcocks.
SGI-PV: 951054
SGI-Modid: xfs-linux-melb:xfs-kern:25477a
Signed-off-by: Nathan Scott <nathans@sgi.com>
-rw-r--r-- | fs/xfs/xfs_inode.c | 28 | ||||
-rw-r--r-- | fs/xfs/xfs_inode.h | 7 | ||||
-rw-r--r-- | fs/xfs/xfs_itable.c | 5 | ||||
-rw-r--r-- | fs/xfs/xfs_log_recover.c | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_vfsops.c | 2 |
5 files changed, 24 insertions, 20 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 86a8451d10fc..b1e95707e7cf 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
@@ -253,7 +253,8 @@ xfs_itobp( | |||
253 | xfs_inode_t *ip, | 253 | xfs_inode_t *ip, |
254 | xfs_dinode_t **dipp, | 254 | xfs_dinode_t **dipp, |
255 | xfs_buf_t **bpp, | 255 | xfs_buf_t **bpp, |
256 | xfs_daddr_t bno) | 256 | xfs_daddr_t bno, |
257 | uint imap_flags) | ||
257 | { | 258 | { |
258 | xfs_buf_t *bp; | 259 | xfs_buf_t *bp; |
259 | int error; | 260 | int error; |
@@ -269,10 +270,9 @@ xfs_itobp( | |||
269 | * inode on disk. | 270 | * inode on disk. |
270 | */ | 271 | */ |
271 | imap.im_blkno = bno; | 272 | imap.im_blkno = bno; |
272 | error = xfs_imap(mp, tp, ip->i_ino, &imap, XFS_IMAP_LOOKUP); | 273 | if ((error = xfs_imap(mp, tp, ip->i_ino, &imap, |
273 | if (error != 0) { | 274 | XFS_IMAP_LOOKUP | imap_flags))) |
274 | return error; | 275 | return error; |
275 | } | ||
276 | 276 | ||
277 | /* | 277 | /* |
278 | * If the inode number maps to a block outside the bounds | 278 | * If the inode number maps to a block outside the bounds |
@@ -336,9 +336,10 @@ xfs_itobp( | |||
336 | * (if DEBUG kernel) or the first inode in the buffer, otherwise. | 336 | * (if DEBUG kernel) or the first inode in the buffer, otherwise. |
337 | */ | 337 | */ |
338 | #ifdef DEBUG | 338 | #ifdef DEBUG |
339 | ni = BBTOB(imap.im_len) >> mp->m_sb.sb_inodelog; | 339 | ni = (imap_flags & XFS_IMAP_BULKSTAT) ? 0 : |
340 | (BBTOB(imap.im_len) >> mp->m_sb.sb_inodelog); | ||
340 | #else | 341 | #else |
341 | ni = 1; | 342 | ni = (imap_flags & XFS_IMAP_BULKSTAT) ? 0 : 1; |
342 | #endif | 343 | #endif |
343 | for (i = 0; i < ni; i++) { | 344 | for (i = 0; i < ni; i++) { |
344 | int di_ok; | 345 | int di_ok; |
@@ -868,9 +869,8 @@ xfs_iread( | |||
868 | * return NULL as well. Set i_blkno to 0 so that xfs_itobp() will | 869 | * return NULL as well. Set i_blkno to 0 so that xfs_itobp() will |
869 | * know that this is a new incore inode. | 870 | * know that this is a new incore inode. |
870 | */ | 871 | */ |
871 | error = xfs_itobp(mp, tp, ip, &dip, &bp, bno); | 872 | error = xfs_itobp(mp, tp, ip, &dip, &bp, bno, 0); |
872 | 873 | if (error) { | |
873 | if (error != 0) { | ||
874 | kmem_zone_free(xfs_inode_zone, ip); | 874 | kmem_zone_free(xfs_inode_zone, ip); |
875 | return error; | 875 | return error; |
876 | } | 876 | } |
@@ -1895,7 +1895,7 @@ xfs_iunlink( | |||
1895 | * Here we put the head pointer into our next pointer, | 1895 | * Here we put the head pointer into our next pointer, |
1896 | * and then we fall through to point the head at us. | 1896 | * and then we fall through to point the head at us. |
1897 | */ | 1897 | */ |
1898 | error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0); | 1898 | error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0, 0); |
1899 | if (error) { | 1899 | if (error) { |
1900 | return error; | 1900 | return error; |
1901 | } | 1901 | } |
@@ -2004,7 +2004,7 @@ xfs_iunlink_remove( | |||
2004 | * of dealing with the buffer when there is no need to | 2004 | * of dealing with the buffer when there is no need to |
2005 | * change it. | 2005 | * change it. |
2006 | */ | 2006 | */ |
2007 | error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0); | 2007 | error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0, 0); |
2008 | if (error) { | 2008 | if (error) { |
2009 | cmn_err(CE_WARN, | 2009 | cmn_err(CE_WARN, |
2010 | "xfs_iunlink_remove: xfs_itobp() returned an error %d on %s. Returning error.", | 2010 | "xfs_iunlink_remove: xfs_itobp() returned an error %d on %s. Returning error.", |
@@ -2066,7 +2066,7 @@ xfs_iunlink_remove( | |||
2066 | * Now last_ibp points to the buffer previous to us on | 2066 | * Now last_ibp points to the buffer previous to us on |
2067 | * the unlinked list. Pull us from the list. | 2067 | * the unlinked list. Pull us from the list. |
2068 | */ | 2068 | */ |
2069 | error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0); | 2069 | error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0, 0); |
2070 | if (error) { | 2070 | if (error) { |
2071 | cmn_err(CE_WARN, | 2071 | cmn_err(CE_WARN, |
2072 | "xfs_iunlink_remove: xfs_itobp() returned an error %d on %s. Returning error.", | 2072 | "xfs_iunlink_remove: xfs_itobp() returned an error %d on %s. Returning error.", |
@@ -3023,8 +3023,8 @@ xfs_iflush( | |||
3023 | /* | 3023 | /* |
3024 | * Get the buffer containing the on-disk inode. | 3024 | * Get the buffer containing the on-disk inode. |
3025 | */ | 3025 | */ |
3026 | error = xfs_itobp(mp, NULL, ip, &dip, &bp, 0); | 3026 | error = xfs_itobp(mp, NULL, ip, &dip, &bp, 0, 0); |
3027 | if (error != 0) { | 3027 | if (error) { |
3028 | xfs_ifunlock(ip); | 3028 | xfs_ifunlock(ip); |
3029 | return error; | 3029 | return error; |
3030 | } | 3030 | } |
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 006396764cbc..39ef9c36ea55 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h | |||
@@ -95,9 +95,10 @@ typedef struct xfs_ifork { | |||
95 | #define XFS_IFEXTIREC 0x08 /* Indirection array of extent blocks */ | 95 | #define XFS_IFEXTIREC 0x08 /* Indirection array of extent blocks */ |
96 | 96 | ||
97 | /* | 97 | /* |
98 | * Flags for xfs_imap() and xfs_dilocate(). | 98 | * Flags for xfs_itobp(), xfs_imap() and xfs_dilocate(). |
99 | */ | 99 | */ |
100 | #define XFS_IMAP_LOOKUP 0x1 | 100 | #define XFS_IMAP_LOOKUP 0x1 |
101 | #define XFS_IMAP_BULKSTAT 0x2 | ||
101 | 102 | ||
102 | #ifdef __KERNEL__ | 103 | #ifdef __KERNEL__ |
103 | struct bhv_desc; | 104 | struct bhv_desc; |
@@ -421,7 +422,7 @@ int xfs_finish_reclaim_all(struct xfs_mount *, int); | |||
421 | */ | 422 | */ |
422 | int xfs_itobp(struct xfs_mount *, struct xfs_trans *, | 423 | int xfs_itobp(struct xfs_mount *, struct xfs_trans *, |
423 | xfs_inode_t *, xfs_dinode_t **, struct xfs_buf **, | 424 | xfs_inode_t *, xfs_dinode_t **, struct xfs_buf **, |
424 | xfs_daddr_t); | 425 | xfs_daddr_t, uint); |
425 | int xfs_iread(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, | 426 | int xfs_iread(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, |
426 | xfs_inode_t **, xfs_daddr_t); | 427 | xfs_inode_t **, xfs_daddr_t); |
427 | int xfs_iread_extents(struct xfs_trans *, xfs_inode_t *, int); | 428 | int xfs_iread_extents(struct xfs_trans *, xfs_inode_t *, int); |
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c index c59450e1be40..32247b6bfee7 100644 --- a/fs/xfs/xfs_itable.c +++ b/fs/xfs/xfs_itable.c | |||
@@ -562,7 +562,8 @@ xfs_bulkstat( | |||
562 | if (bp) | 562 | if (bp) |
563 | xfs_buf_relse(bp); | 563 | xfs_buf_relse(bp); |
564 | error = xfs_itobp(mp, NULL, ip, | 564 | error = xfs_itobp(mp, NULL, ip, |
565 | &dip, &bp, bno); | 565 | &dip, &bp, bno, |
566 | XFS_IMAP_BULKSTAT); | ||
566 | if (!error) | 567 | if (!error) |
567 | clustidx = ip->i_boffset / mp->m_sb.sb_inodesize; | 568 | clustidx = ip->i_boffset / mp->m_sb.sb_inodesize; |
568 | kmem_zone_free(xfs_inode_zone, ip); | 569 | kmem_zone_free(xfs_inode_zone, ip); |
@@ -570,6 +571,8 @@ xfs_bulkstat( | |||
570 | mp, XFS_ERRTAG_BULKSTAT_READ_CHUNK, | 571 | mp, XFS_ERRTAG_BULKSTAT_READ_CHUNK, |
571 | XFS_RANDOM_BULKSTAT_READ_CHUNK)) { | 572 | XFS_RANDOM_BULKSTAT_READ_CHUNK)) { |
572 | bp = NULL; | 573 | bp = NULL; |
574 | ubleft = 0; | ||
575 | rval = error; | ||
573 | break; | 576 | break; |
574 | } | 577 | } |
575 | } | 578 | } |
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 7d46cbd6a07a..add13f507ed2 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c | |||
@@ -3249,7 +3249,7 @@ xlog_recover_process_iunlinks( | |||
3249 | * next inode in the bucket. | 3249 | * next inode in the bucket. |
3250 | */ | 3250 | */ |
3251 | error = xfs_itobp(mp, NULL, ip, &dip, | 3251 | error = xfs_itobp(mp, NULL, ip, &dip, |
3252 | &ibp, 0); | 3252 | &ibp, 0, 0); |
3253 | ASSERT(error || (dip != NULL)); | 3253 | ASSERT(error || (dip != NULL)); |
3254 | } | 3254 | } |
3255 | 3255 | ||
diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c index 5dd84fe609cc..811a4261fa2c 100644 --- a/fs/xfs/xfs_vfsops.c +++ b/fs/xfs/xfs_vfsops.c | |||
@@ -1229,7 +1229,7 @@ xfs_sync_inodes( | |||
1229 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | 1229 | xfs_iunlock(ip, XFS_ILOCK_SHARED); |
1230 | 1230 | ||
1231 | error = xfs_itobp(mp, NULL, ip, | 1231 | error = xfs_itobp(mp, NULL, ip, |
1232 | &dip, &bp, 0); | 1232 | &dip, &bp, 0, 0); |
1233 | if (!error) { | 1233 | if (!error) { |
1234 | xfs_buf_relse(bp); | 1234 | xfs_buf_relse(bp); |
1235 | } else { | 1235 | } else { |