Whamcloud - gitweb
e2fsck: fix sparse bmap to extent conversion
authorDarrick J. Wong <darrick.wong@oracle.com>
Thu, 25 May 2017 01:56:36 +0000 (21:56 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Thu, 25 May 2017 02:12:39 +0000 (22:12 -0400)
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 <darrick.wong@oracle.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
e2fsck/extents.c
lib/support/plausible.h
tests/f_convert_bmap_sparse/expect.1 [new file with mode: 0644]
tests/f_convert_bmap_sparse/expect.2 [new file with mode: 0644]
tests/f_convert_bmap_sparse/image.gz [new file with mode: 0644]
tests/f_convert_bmap_sparse/name [new file with mode: 0644]
tests/f_convert_bmap_sparse/script [new file with mode: 0644]

index 98cf7c3..ef3146d 100644 (file)
@@ -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
index 594e4b1..b85150c 100644 (file)
@@ -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 (file)
index 0000000..74a8034
--- /dev/null
@@ -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 (file)
index 0000000..e5a3d44
--- /dev/null
@@ -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 (file)
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 (file)
index 0000000..dc3b985
--- /dev/null
@@ -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 (file)
index 0000000..89b7ed7
--- /dev/null
@@ -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
+