From: Darrick J. Wong Date: Thu, 25 May 2017 01:56:36 +0000 (-0400) Subject: e2fsck: fix sparse bmap to extent conversion X-Git-Tag: v1.43.5~52 X-Git-Url: https://git.whamcloud.com/gitweb?a=commitdiff_plain;h=855c2ecb21d1556c26d61df9b014e1c79dbbc956;p=tools%2Fe2fsprogs.git e2fsck: fix sparse bmap to extent conversion When e2fsck is trying to convert a sparse block-mapped file to an extent file, we incorrectly merge block mappings that are physically contiguous but not logically contiguous because of insufficient checking with the extent we're constructing. Therefore, compare the logical offsets for contiguity as well. Signed-off-by: Darrick J. Wong Signed-off-by: Theodore Ts'o --- diff --git a/e2fsck/extents.c b/e2fsck/extents.c index 98cf7c3..ef3146d 100644 --- a/e2fsck/extents.c +++ b/e2fsck/extents.c @@ -171,7 +171,8 @@ static int find_blocks(ext2_filsys fs, blk64_t *blocknr, e2_blkcnt_t blockcnt, list->count - 1; blk64_t end = last->e_len + 1; - if (last->e_pblk + last->e_len == *blocknr && + if (last->e_lblk + last->e_len == blockcnt && + last->e_pblk + last->e_len == *blocknr && end < (1ULL << 32)) { last->e_len++; #ifdef DEBUG diff --git a/lib/support/plausible.h b/lib/support/plausible.h index 594e4b1..b85150c 100644 --- a/lib/support/plausible.h +++ b/lib/support/plausible.h @@ -21,6 +21,7 @@ #define CHECK_FS_EXIST 0x0004 #define VERBOSE_CREATE 0x0008 #define NO_SIZE 0x0010 +#define QUIET_CHECK 0x0020 extern int check_plausibility(const char *device, int flags, int *ret_is_dev); diff --git a/tests/f_convert_bmap_sparse/expect.1 b/tests/f_convert_bmap_sparse/expect.1 new file mode 100644 index 0000000..74a8034 --- /dev/null +++ b/tests/f_convert_bmap_sparse/expect.1 @@ -0,0 +1,24 @@ +debugfs: stat /realmode.bin +Inode: 12 Type: regular Mode: 0775 Flags: 0x0 +Generation: 2022334337 Version: 0x00000001 +User: 1000 Group: 1000 Size: 21080 +File ACL: 0 Directory ACL: 0 +Links: 1 Blockcount: 16 +Fragment: Address: 0 Number: 0 Size: 0 +ctime: 0x5924849d -- Tue May 23 18:51:09 2017 +atime: 0x59247d36 -- Tue May 23 18:19:34 2017 +mtime: 0x591e1764 -- Thu May 18 21:51:32 2017 +BLOCKS: +(0):513, (4-8):514-518, (IND):58, (20):2005 +TOTAL: 8 + +Pass 1: Checking inodes, blocks, and sizes +Pass 1E: Optimizing extent trees +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information + +test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** +test_filesys: 12/256 files (8.3% non-contiguous), 65/2048 blocks +Exit status is 0 diff --git a/tests/f_convert_bmap_sparse/expect.2 b/tests/f_convert_bmap_sparse/expect.2 new file mode 100644 index 0000000..e5a3d44 --- /dev/null +++ b/tests/f_convert_bmap_sparse/expect.2 @@ -0,0 +1,12 @@ +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information +test_filesys: 12/256 files (8.3% non-contiguous), 65/2048 blocks +Exit status is 0 +debugfs: ex /realmode.bin +Level Entries Logical Physical Length Flags + 0/ 0 1/ 3 0 - 0 513 - 513 1 + 0/ 0 2/ 3 4 - 8 514 - 518 5 + 0/ 0 3/ 3 20 - 20 2005 - 2005 1 diff --git a/tests/f_convert_bmap_sparse/image.gz b/tests/f_convert_bmap_sparse/image.gz new file mode 100644 index 0000000..1f594fd Binary files /dev/null and b/tests/f_convert_bmap_sparse/image.gz differ diff --git a/tests/f_convert_bmap_sparse/name b/tests/f_convert_bmap_sparse/name new file mode 100644 index 0000000..dc3b985 --- /dev/null +++ b/tests/f_convert_bmap_sparse/name @@ -0,0 +1 @@ +convert sparse blockmap file to extents file diff --git a/tests/f_convert_bmap_sparse/script b/tests/f_convert_bmap_sparse/script new file mode 100644 index 0000000..89b7ed7 --- /dev/null +++ b/tests/f_convert_bmap_sparse/script @@ -0,0 +1,117 @@ +if [ "$DESCRIPTION"x != x ]; then + test_description="$DESCRIPTION" +fi +if [ "$IMAGE"x = x ]; then + IMAGE=$test_dir/image.gz +fi + +if [ "$FSCK_OPT"x = x ]; then + FSCK_OPT=-yf +fi + +if [ "$SECOND_FSCK_OPT"x = x ]; then + SECOND_FSCK_OPT=-yf +fi + +if [ "$OUT1"x = x ]; then + OUT1=$test_name.1.log +fi + +if [ "$OUT2"x = x ]; then + OUT2=$test_name.2.log +fi + +if [ "$EXP1"x = x ]; then + if [ -f $test_dir/expect.1.gz ]; then + EXP1=$test_name.1.tmp + gunzip < $test_dir/expect.1.gz > $EXP1 + else + EXP1=$test_dir/expect.1 + fi +fi + +if [ "$EXP2"x = x ]; then + if [ -f $test_dir/expect.2.gz ]; then + EXP2=$test_name.2.tmp + gunzip < $test_dir/expect.2.gz > $EXP2 + else + EXP2=$test_dir/expect.2 + fi +fi + +if [ "$SKIP_GUNZIP" != "true" ] ; then + gunzip < $IMAGE > $TMPFILE +fi + +cp /dev/null $OUT1 + +eval $PREP_CMD + +echo 'stat /realmode.bin' > $TMPFILE.cmd +$DEBUGFS -f $TMPFILE.cmd $TMPFILE > $OUT1.new 2>&1 +rm -rf $TMPFILE.cmd +$TUNE2FS -O extent $TMPFILE >> $OUT1.new 2>&1 +$FSCK $FSCK_OPT -E bmap2extent -N test_filesys $TMPFILE >> $OUT1.new 2>&1 +status=$? +echo Exit status is $status >> $OUT1.new +sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT1.new >> $OUT1 +rm -f $OUT1.new + +$FSCK $SECOND_FSCK_OPT -N test_filesys $TMPFILE > $OUT2.new 2>&1 +status=$? +echo Exit status is $status >> $OUT2.new +echo 'ex /realmode.bin' > $TMPFILE.cmd +$DEBUGFS -f $TMPFILE.cmd $TMPFILE >> $OUT2.new 2>&1 +rm -rf $TMPFILE.cmd +sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT2.new > $OUT2 +rm -f $OUT2.new + +eval $AFTER_CMD + +if [ "$SKIP_VERIFY" != "true" ] ; then + rm -f $test_name.ok $test_name.failed + cmp -s $OUT1 $EXP1 + status1=$? + if [ "$ONE_PASS_ONLY" != "true" ]; then + cmp -s $OUT2 $EXP2 + status2=$? + else + status2=0 + fi + if [ "$PASS_ZERO" = "true" ]; then + cmp -s $test_name.0.log $test_dir/expect.0 + status3=$? + else + status3=0 + fi + + if [ -z "$test_description" ] ; then + description="$test_name" + else + description="$test_name: $test_description" + fi + + if [ "$status1" -eq 0 -a "$status2" -eq 0 -a "$status3" -eq 0 ] ; then + echo "$description: ok" + touch $test_name.ok + else + echo "$description: failed" + rm -f $test_name.failed + if [ "$PASS_ZERO" = "true" ]; then + diff $DIFF_OPTS $test_dir/expect.0 \ + $test_name.0.log >> $test_name.failed + fi + diff $DIFF_OPTS $EXP1 $OUT1 >> $test_name.failed + if [ "$ONE_PASS_ONLY" != "true" ]; then + diff $DIFF_OPTS $EXP2 $OUT2 >> $test_name.failed + fi + fi + rm -f tmp_expect +fi + +if [ "$SKIP_CLEANUP" != "true" ] ; then + unset IMAGE FSCK_OPT SECOND_FSCK_OPT OUT1 OUT2 EXP1 EXP2 + unset SKIP_VERIFY SKIP_CLEANUP SKIP_GUNZIP ONE_PASS_ONLY PREP_CMD + unset DESCRIPTION SKIP_UNLINK AFTER_CMD PASS_ZERO +fi +