From 7d7bdd578b307cad1dc248310eb279c6fb73b682 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Tue, 24 Jun 2003 17:34:02 -0400 Subject: [PATCH] Fix bug in resize2fs which caused it to fail on filesystems with a non-empty bad block list. Resize2fs now discards any blocks on the badblock list which are no longer part of the filesystem as the result of a filesystem shrink. (Note: this means that shrinking and then enlarging a filesystem is no longer a reversible operation; information about bad blocks in the part of the filesystem which is to be chopped off will be lost.) --- lib/ext2fs/ChangeLog | 8 ++++ lib/ext2fs/badblocks.c | 85 +++++++++++++++++++++++++++----------- lib/ext2fs/ext2fs.h | 2 + lib/ext2fs/tst_badblocks.c | 76 +++++++++++++++++++++++++++++++--- resize/ChangeLog | 9 ++++ resize/resize2fs.c | 17 ++++++++ 6 files changed, 167 insertions(+), 30 deletions(-) diff --git a/lib/ext2fs/ChangeLog b/lib/ext2fs/ChangeLog index d9a50191..76102e58 100644 --- a/lib/ext2fs/ChangeLog +++ b/lib/ext2fs/ChangeLog @@ -1,3 +1,11 @@ +2003-06-24 + + * badblocks.c, ext2fs.h (ext2fs_u32_list_find, + ext2fs_u32_list_test, ext2fs_u32_list_del, + ext2fs_badblocks_list_del): Add functions to delete a + block from the badblocks list. + * tst_badblocks.c: Add test cases for ext2fs_badblocks_list_del(). + 2003-05-21 Theodore Ts'o * getsectsize.c (ext2fs_get_device_sectsize): New function which diff --git a/lib/ext2fs/badblocks.c b/lib/ext2fs/badblocks.c index 7e1d24f3..9fda70cc 100644 --- a/lib/ext2fs/badblocks.c +++ b/lib/ext2fs/badblocks.c @@ -156,7 +156,40 @@ errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb, blk_t blk) return ext2fs_u32_list_add((ext2_u32_list) bb, (__u32) blk); } +/* + * This procedure finds a particular block is on a badblocks + * list. + */ +int ext2fs_u32_list_find(ext2_u32_list bb, __u32 blk) +{ + int low, high, mid; + if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST) + return -1; + + if (bb->num == 0) + return -1; + + low = 0; + high = bb->num-1; + if (blk == bb->list[low]) + return low; + if (blk == bb->list[high]) + return high; + + while (low < high) { + mid = (low+high)/2; + if (mid == low || mid == high) + break; + if (blk == bb->list[mid]) + return mid; + if (blk < bb->list[mid]) + high = mid; + else + low = mid; + } + return -1; +} /* * This procedure tests to see if a particular block is on a badblocks @@ -164,33 +197,10 @@ errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb, blk_t blk) */ int ext2fs_u32_list_test(ext2_u32_list bb, __u32 blk) { - int low, high, mid; - - if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST) + if (ext2fs_u32_list_find(bb, blk) < 0) return 0; - - if (bb->num == 0) - return 0; - - low = 0; - high = bb->num-1; - if (blk == bb->list[low]) + else return 1; - if (blk == bb->list[high]) - return 1; - - while (low < high) { - mid = (low+high)/2; - if (mid == low || mid == high) - break; - if (blk == bb->list[mid]) - return 1; - if (blk < bb->list[mid]) - high = mid; - else - low = mid; - } - return 0; } int ext2fs_badblocks_list_test(ext2_badblocks_list bb, blk_t blk) @@ -199,6 +209,31 @@ int ext2fs_badblocks_list_test(ext2_badblocks_list bb, blk_t blk) } +/* + * Remove a block from the badblock list + */ +int ext2fs_u32_list_del(ext2_u32_list bb, __u32 blk) +{ + int remloc, i; + + if (bb->num == 0) + return -1; + + remloc = ext2fs_u32_list_find(bb, blk); + if (remloc < 0) + return -1; + + for (i = remloc ; i < bb->num-1; i++) + bb->list[i] = bb->list[i+1]; + bb->num--; + return 0; +} + +void ext2fs_badblocks_list_del(ext2_u32_list bb, __u32 blk) +{ + ext2fs_u32_list_del(bb, blk); +} + errcode_t ext2fs_u32_list_iterate_begin(ext2_u32_list bb, ext2_u32_iterate *ret) { diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h index cd9344d4..d15d08a8 100644 --- a/lib/ext2fs/ext2fs.h +++ b/lib/ext2fs/ext2fs.h @@ -491,6 +491,8 @@ extern errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb, blk_t blk); extern int ext2fs_badblocks_list_test(ext2_badblocks_list bb, blk_t blk); +extern int ext2fs_u32_list_del(ext2_u32_list bb, __u32 blk); +extern void ext2fs_badblocks_list_del(ext2_u32_list bb, __u32 blk); extern errcode_t ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb, ext2_badblocks_iterate *ret); diff --git a/lib/ext2fs/tst_badblocks.c b/lib/ext2fs/tst_badblocks.c index 2ae35856..a42e4cd8 100644 --- a/lib/ext2fs/tst_badblocks.c +++ b/lib/ext2fs/tst_badblocks.c @@ -25,6 +25,9 @@ #include "ext2_fs.h" #include "ext2fs.h" +#define ADD_BLK 0x0001 +#define DEL_BLK 0x0002 + blk_t test1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0 }; blk_t test2[] = { 11, 10, 9, 8, 7, 6, 5, 4, 3, 3, 2, 1 }; blk_t test3[] = { 3, 1, 4, 5, 9, 2, 7, 10, 5, 6, 10, 8, 0 }; @@ -44,6 +47,20 @@ blk_t test4a[] = { 45, 0, 66, 1, 0 }; +blk_t test5[] = { 31, 20, 17, 51, 23, 1, 56, 57, 0 }; +blk_t test5a[] = { + 50, ADD_BLK, + 51, DEL_BLK, + 57, DEL_BLK, + 66, ADD_BLK, + 31, DEL_BLK, + 12, ADD_BLK, + 2, ADD_BLK, + 13, ADD_BLK, + 1, DEL_BLK, + 0 + }; + static int test_fail = 0; @@ -118,6 +135,38 @@ static void validate_test_seq(badblocks_list bb, blk_t *vec) } } +static void do_test_seq(badblocks_list bb, blk_t *vec) +{ + int i, match; + + for (i = 0; vec[i]; i += 2) { + switch (vec[i+1]) { + case ADD_BLK: + ext2fs_badblocks_list_add(bb, vec[i]); + match = ext2fs_badblocks_list_test(bb, vec[i]); + printf("Adding block %d --- now %s\n", vec[i], + match ? "present" : "absent"); + if (!match) { + printf("FAILURE!\n"); + test_fail++; + } + break; + case DEL_BLK: + ext2fs_badblocks_list_del(bb, vec[i]); + match = ext2fs_badblocks_list_test(bb, vec[i]); + printf("Removing block %d --- now %s\n", vec[i], + ext2fs_badblocks_list_test(bb, vec[i]) ? + "present" : "absent"); + if (match) { + printf("FAILURE!\n"); + test_fail++; + } + break; + } + } +} + + int file_test(badblocks_list bb) { badblocks_list new_bb = 0; @@ -156,11 +205,11 @@ int file_test(badblocks_list bb) int main(int argc, char **argv) { - badblocks_list bb1, bb2, bb3, bb4; + badblocks_list bb1, bb2, bb3, bb4, bb5; int equal; errcode_t retval; - bb1 = bb2 = bb3 = bb4 = 0; + bb1 = bb2 = bb3 = bb4 = bb5 = 0; printf("test1: "); retval = create_test_list(test1, &bb1); @@ -189,7 +238,19 @@ int main(int argc, char **argv) } printf("\n"); - if (bb1 && bb2 && bb3 && bb4) { + printf("test5: "); + retval = create_test_list(test5, &bb5); + if (retval == 0) { + print_list(bb5, 0); + printf("\n"); + do_test_seq(bb5, test5a); + printf("After test5 sequence: "); + print_list(bb5, 0); + printf("\n"); + } + printf("\n"); + + if (bb1 && bb2 && bb3 && bb4 && bb5) { printf("Comparison tests:\n"); equal = ext2fs_badblocks_equal(bb1, bb2); printf("bb1 and bb2 are %sequal.\n", equal ? "" : "NOT "); @@ -205,14 +266,19 @@ int main(int argc, char **argv) printf("bb1 and bb4 are %sequal.\n", equal ? "" : "NOT "); if (equal) test_fail++; + + equal = ext2fs_badblocks_equal(bb4, bb5); + printf("bb4 and bb5 are %sequal.\n", equal ? "" : "NOT "); + if (!equal) + test_fail++; printf("\n"); } + file_test(bb4); + if (test_fail == 0) printf("ext2fs library badblocks tests checks out OK!\n"); - file_test(bb4); - if (bb1) ext2fs_badblocks_list_free(bb1); if (bb2) diff --git a/resize/ChangeLog b/resize/ChangeLog index e7667c8c..b0598738 100644 --- a/resize/ChangeLog +++ b/resize/ChangeLog @@ -1,3 +1,12 @@ +2003-06-24 + + * resize2fs.c (block_mover): Don't move blocks associated with the + bad blocks inode. Instead, just remove them from the + badblocks list. (Note this means that shrinking and then + enlarging a filesystem is not a reversible operation; + information about bad blocks in the part of the filesystem + which is to be chopped off is discarded.) + 2003-06-08 Theodore Ts'o * resize2fs.8.in: Make explicit that you need to run resize2fs diff --git a/resize/resize2fs.c b/resize/resize2fs.c index f9543ccb..6f60cfcd 100644 --- a/resize/resize2fs.c +++ b/resize/resize2fs.c @@ -837,6 +837,12 @@ static errcode_t block_mover(ext2_resize_t rfs) errcode_t retval; int size, c; int to_move, moved; + ext2_badblocks_list badblock_list = 0; + int bb_modified = 0; + + retval = ext2fs_read_bb_inode(old_fs, &badblock_list); + if (retval) + return retval; new_blk = fs->super->s_first_data_block; if (!rfs->itable_buf) { @@ -862,6 +868,11 @@ static errcode_t block_mover(ext2_resize_t rfs) continue; if (!ext2fs_test_block_bitmap(rfs->move_blocks, blk)) continue; + if (ext2fs_badblocks_list_test(badblock_list, blk)) { + ext2fs_badblocks_list_del(badblock_list, blk); + bb_modified++; + continue; + } new_blk = get_new_block(rfs); if (!new_blk) { @@ -931,6 +942,12 @@ static errcode_t block_mover(ext2_resize_t rfs) } errout: + if (badblock_list) { + if (!retval && bb_modified) + retval = ext2fs_update_bb_inode(old_fs, + badblock_list); + ext2fs_badblocks_list_free(badblock_list); + } return retval; }