From 9234d41635186d89fc87cc4890305426e40ca916 Mon Sep 17 00:00:00 2001 From: Barry Naujok Date: Fri, 16 Mar 2007 03:00:32 +0000 Subject: [PATCH] Make sure xfs_repair detects invalid btree roots in inodes Merge of master-melb:xfs-cmds:28254a by kenmcd. Bump version to 2.8.20 --- VERSION | 2 +- debian/changelog | 7 ++++++ doc/CHANGES | 8 ++++-- io/pwrite.c | 1 + repair/dinode.c | 64 +++++++++++++++++++++++------------------------- repair/dir2.c | 1 + 6 files changed, 46 insertions(+), 37 deletions(-) diff --git a/VERSION b/VERSION index 5acea6259..f70b7c9c8 100644 --- a/VERSION +++ b/VERSION @@ -3,5 +3,5 @@ # PKG_MAJOR=2 PKG_MINOR=8 -PKG_REVISION=19 +PKG_REVISION=20 PKG_BUILD=1 diff --git a/debian/changelog b/debian/changelog index 39c799e5a..626848587 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +xfsprogs (2.8.20-1) unstable; urgency=low + + * New upstream release (closes: #414079) + * Fixed up autoconf version dependency (closes: #414073) + + -- Nathan Scott Fri, 16 Mar 2007 08:24:33 +1100 + xfsprogs (2.8.19-1) unstable; urgency=low * New upstream release (closes: #409063) diff --git a/doc/CHANGES b/doc/CHANGES index 4473ed2a3..3d7e8c8b8 100644 --- a/doc/CHANGES +++ b/doc/CHANGES @@ -1,6 +1,10 @@ -xfsprogs-2.8.XX +xfsprogs-2.8.20 (23 February 2007) + - Fix xfs_repair not detecting invalid btree root in inodes. + - Fix xfs_repair restoring corrupted superblock after repairing it. + - Fix xfs_repair crashing on invalid quota inode values. - Fix xfs_quota gracetime reporting. Thanks to Utako Kusaka for this. + - Fix libxfs IO_DEBUG output. - Instead of using AC_CHECK_TYPES which isn't supported for older versions of autoconf, add our own type check in the m4/package_types.m4 file for __u32. @@ -27,7 +31,7 @@ xfsprogs-2.8.18 (8 December 2006) Thanks to Utako Kusaka for the above three fixes. -xfsprogs-2.8.17 (?) +xfsprogs-2.8.17 (5 December 2006) - Fix up libxfs SEGV when attempting to mount a non-XFS filesystem. Thanks to Utako Kusaka for this. - Fix up xfs_repair aborting if it finds an inode with an invalid diff --git a/io/pwrite.c b/io/pwrite.c index ca12a5b82..54c3f7820 100644 --- a/io/pwrite.c +++ b/io/pwrite.c @@ -310,6 +310,7 @@ pwrite_f( c = write_backward(offset, &count, &total); break; default: + total = 0; ASSERT(0); } if (c < 0) diff --git a/repair/dinode.c b/repair/dinode.c index b23731978..eba620cea 100644 --- a/repair/dinode.c +++ b/repair/dinode.c @@ -307,8 +307,8 @@ clear_dinode(xfs_mount_t *mp, xfs_dinode_t *dino, xfs_ino_t ino_num) * misc. inode-related utility routines */ -/* - * verify_ag_bno is heavily used. In the common case, it +/* + * verify_ag_bno is heavily used. In the common case, it * performs just two number of compares */ static __inline int @@ -802,7 +802,7 @@ process_bmbt_reclist_int( PROCESS_BMBT_UNLOCK_RETURN(1); } - /* Process in chunks of 16 (XR_BB_UNIT/XR_BB) + /* Process in chunks of 16 (XR_BB_UNIT/XR_BB) * for common XR_E_UNKNOWN to XR_E_INUSE transition */ if (((agbno & XR_BB_MASK) == 0) && ((s + c - b) >= (XR_BB_UNIT/XR_BB))) { @@ -1223,6 +1223,8 @@ process_btinode( xfs_bmbt_key_t *pkey; char *forkname; int i; + int level; + int numrecs; bmap_cursor_t cursor; dib = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork); @@ -1235,13 +1237,11 @@ process_btinode( else forkname = _("attr"); - if (INT_GET(dib->bb_level, ARCH_CONVERT) == 0) { + level = INT_GET(dib->bb_level, ARCH_CONVERT); + numrecs = INT_GET(dib->bb_numrecs, ARCH_CONVERT); + + if ((level == 0) || (level > XFS_BM_MAXLEVELS(mp, whichfork))) { /* - * This should never happen since a btree inode - * has to have at least one other block in the - * bmap in addition to the root block in the - * inode's data fork. - * * XXX - if we were going to fix up the inode, * we'd try to treat the fork as an interior * node and see if we could get an accurate @@ -1249,28 +1249,30 @@ process_btinode( * to by the pointers in the fork. For now * though, we just bail (and blow out the inode). */ - do_warn(_("bad level 0 in inode %llu bmap btree root block\n"), + do_warn(_("bad level %d in inode %llu bmap btree root block\n"), + level, XFS_AGINO_TO_INO(mp, agno, ino)); + return(1); + } + if (numrecs == 0) { + do_warn(_("bad numrecs 0 in inode %llu bmap btree root block\n"), XFS_AGINO_TO_INO(mp, agno, ino)); return(1); } /* * use bmdr/dfork_dsize since the root block is in the data fork */ - init_bm_cursor(&cursor, INT_GET(dib->bb_level, ARCH_CONVERT) + 1); - - if (XFS_BMDR_SPACE_CALC(INT_GET(dib->bb_numrecs, ARCH_CONVERT)) > - ((whichfork == XFS_DATA_FORK) ? + if (XFS_BMDR_SPACE_CALC(numrecs) > ((whichfork == XFS_DATA_FORK) ? XFS_DFORK_DSIZE(dip, mp) : XFS_DFORK_ASIZE(dip, mp))) { do_warn( _("indicated size of %s btree root (%d bytes) greater than space in " "inode %llu %s fork\n"), - forkname, XFS_BMDR_SPACE_CALC(INT_GET(dib->bb_numrecs, - ARCH_CONVERT)), - lino, forkname); + forkname, XFS_BMDR_SPACE_CALC(numrecs), lino, forkname); return(1); } + init_bm_cursor(&cursor, level + 1); + pp = XFS_BTREE_PTR_ADDR( XFS_DFORK_SIZE(dip, mp, whichfork), xfs_bmdr, dib, 1, @@ -1286,7 +1288,7 @@ process_btinode( last_key = NULLDFILOFF; - for (i = 0; i < INT_GET(dib->bb_numrecs, ARCH_CONVERT); i++) { + for (i = 0; i < numrecs; i++) { /* * XXX - if we were going to do more to fix up the inode * btree, we'd do it right here. For now, if there's a @@ -1298,8 +1300,8 @@ process_btinode( return(1); } - if (scan_lbtree((xfs_dfsbno_t)INT_GET(pp[i], ARCH_CONVERT), INT_GET(dib->bb_level, ARCH_CONVERT), - scanfunc_bmap, type, whichfork, + if (scan_lbtree((xfs_dfsbno_t)INT_GET(pp[i], ARCH_CONVERT), + level, scanfunc_bmap, type, whichfork, lino, tot, nex, blkmapp, &cursor, 1, check_dups)) return(1); @@ -1310,8 +1312,7 @@ process_btinode( * blocks but the parent hasn't been updated */ if (check_dups == 0 && - cursor.level[INT_GET(dib->bb_level, - ARCH_CONVERT)-1].first_key != + cursor.level[level-1].first_key != INT_GET(pkey[i].br_startoff, ARCH_CONVERT)) { if (!no_modify) { do_warn( @@ -1319,22 +1320,19 @@ process_btinode( "%llu %s fork\n"), INT_GET(pkey[i].br_startoff, ARCH_CONVERT), - cursor.level[INT_GET(dib->bb_level, - ARCH_CONVERT)-1].first_key, + cursor.level[level-1].first_key, XFS_AGINO_TO_INO(mp, agno, ino), forkname); *dirty = 1; INT_SET(pkey[i].br_startoff, ARCH_CONVERT, - cursor.level[INT_GET(dib->bb_level, - ARCH_CONVERT)-1].first_key); + cursor.level[level-1].first_key); } else { do_warn( _("bad key in bmbt root (is %llu, would reset to %llu) in inode " "%llu %s fork\n"), INT_GET(pkey[i].br_startoff, ARCH_CONVERT), - cursor.level[INT_GET(dib->bb_level, - ARCH_CONVERT)-1].first_key, + cursor.level[level-1].first_key, XFS_AGINO_TO_INO(mp, agno, ino), forkname); } @@ -1345,8 +1343,7 @@ process_btinode( */ if (check_dups == 0) { if (last_key != NULLDFILOFF && last_key >= - cursor.level[INT_GET(dib->bb_level, - ARCH_CONVERT)-1].first_key) { + cursor.level[level-1].first_key) { do_warn( _("out of order bmbt root key %llu in inode %llu %s fork\n"), first_key, @@ -1354,8 +1351,7 @@ process_btinode( forkname); return(1); } - last_key = cursor.level[INT_GET(dib->bb_level, - ARCH_CONVERT)-1].first_key; + last_key = cursor.level[level-1].first_key; } } /* @@ -2064,9 +2060,9 @@ process_dinode_int(xfs_mount_t *mp, if (!verify_mode) { do_warn(_("bad inode type %#o inode %llu\n"), (int) (INT_GET(dinoc->di_mode, ARCH_CONVERT) & S_IFMT), lino); - if (!no_modify) + if (!no_modify) *dirty += clear_dinode(mp, dino, lino); - else + else *dirty = 1; *cleared = 1; *used = is_free; diff --git a/repair/dir2.c b/repair/dir2.c index 4687c7b9d..46240769f 100644 --- a/repair/dir2.c +++ b/repair/dir2.c @@ -1805,6 +1805,7 @@ process_leaf_level_dir2( prev_bno = 0; bmp = NULL; current_hashval = 0; + greatest_hashval = 0; buf_dirty = 0; do { -- 2.47.2