Whamcloud - gitweb
e2fsck: detect and repair external journal superblock checksum errors
authorDarrick J. Wong <darrick.wong@oracle.com>
Mon, 8 Sep 2014 23:12:15 +0000 (16:12 -0700)
committerTheodore Ts'o <tytso@mit.edu>
Thu, 11 Sep 2014 16:40:55 +0000 (12:40 -0400)
Verify the (ext4) superblock checksum of an external journal device
and prompt to correct the checksum if nothing else is wrong with the
superblock.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Cc: TR Reardon <thomas_reardon@hotmail.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
e2fsck/journal.c
e2fsck/problem.c
e2fsck/problem.h
tests/j_corrupt_ext_jnl_sb_block/expect [new file with mode: 0644]
tests/j_corrupt_ext_jnl_sb_block/image.tar.bz2 [new file with mode: 0644]
tests/j_corrupt_ext_jnl_sb_block/name [new file with mode: 0644]
tests/j_corrupt_ext_jnl_sb_block/script [new file with mode: 0644]
tests/j_corrupt_ext_jnl_sb_csum/expect [new file with mode: 0644]
tests/j_corrupt_ext_jnl_sb_csum/image.tar.bz2 [new file with mode: 0644]
tests/j_corrupt_ext_jnl_sb_csum/name [new file with mode: 0644]
tests/j_corrupt_ext_jnl_sb_csum/script [new file with mode: 0644]

index a19d40b..16bd757 100644 (file)
@@ -456,7 +456,6 @@ static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal)
                }
                memcpy(&jsuper, start ? bh->b_data :  bh->b_data + SUPERBLOCK_OFFSET,
                       sizeof(jsuper));
-               brelse(bh);
 #ifdef WORDS_BIGENDIAN
                if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
                        ext2fs_swap_super(&jsuper);
@@ -465,6 +464,7 @@ static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal)
                    !(jsuper.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
                        fix_problem(ctx, PR_0_EXT_JOURNAL_BAD_SUPER, &pctx);
                        retval = EXT2_ET_LOAD_EXT_JOURNAL;
+                       brelse(bh);
                        goto errout;
                }
                /* Make sure the journal UUID is correct */
@@ -472,9 +472,32 @@ static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal)
                           sizeof(jsuper.s_uuid))) {
                        fix_problem(ctx, PR_0_JOURNAL_BAD_UUID, &pctx);
                        retval = EXT2_ET_LOAD_EXT_JOURNAL;
+                       brelse(bh);
                        goto errout;
                }
 
+               /* Check the superblock checksum */
+               if (jsuper.s_feature_ro_compat &
+                   EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) {
+                       struct struct_ext2_filsys fsx;
+                       struct ext2_super_block superx;
+                       void *p;
+
+                       p = start ? bh->b_data : bh->b_data + SUPERBLOCK_OFFSET;
+                       memcpy(&fsx, ctx->fs, sizeof(fsx));
+                       memcpy(&superx, ctx->fs->super, sizeof(superx));
+                       fsx.super = &superx;
+                       fsx.super->s_feature_ro_compat |=
+                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM;
+                       if (!ext2fs_superblock_csum_verify(&fsx, p) &&
+                           fix_problem(ctx, PR_0_EXT_JOURNAL_SUPER_CSUM_INVALID,
+                                       &pctx)) {
+                               ext2fs_superblock_csum_set(&fsx, p);
+                               mark_buffer_dirty(bh);
+                       }
+               }
+               brelse(bh);
+
                maxlen = ext2fs_blocks_count(&jsuper);
                journal->j_maxlen = (maxlen < 1ULL << 32) ? maxlen : (1ULL << 32) - 1;
                start++;
index 99ca7cb..4b41a21 100644 (file)
@@ -459,6 +459,11 @@ static struct e2fsck_problem problem_table[] = {
          N_("First_meta_bg is too big.  (%N, max value %g).  "),
          PROMPT_CLEAR, 0 },
 
+       /* External journal has corrupt superblock */
+       { PR_0_EXT_JOURNAL_SUPER_CSUM_INVALID,
+         N_("External @j @S checksum does not match @S.  "),
+         PROMPT_FIX, PR_PREEN_OK },
+
        /* Pass 1 errors */
 
        /* Pass 1: Checking inodes, blocks, and sizes */
index 5c92d0a..f86c531 100644 (file)
@@ -264,6 +264,9 @@ struct problem_context {
 /* The first_meta_bg is too big */
 #define PR_0_FIRST_META_BG_TOO_BIG             0x000049
 
+/* External journal has corrupt superblock */
+#define PR_0_EXT_JOURNAL_SUPER_CSUM_INVALID    0x00004A
+
 /*
  * Pass 1 errors
  */
diff --git a/tests/j_corrupt_ext_jnl_sb_block/expect b/tests/j_corrupt_ext_jnl_sb_block/expect
new file mode 100644 (file)
index 0000000..e638e11
--- /dev/null
@@ -0,0 +1,5 @@
+External journal does not support this filesystem
+
+test_filesys: ********** WARNING: Filesystem still has errors **********
+
+Exit status is 12
diff --git a/tests/j_corrupt_ext_jnl_sb_block/image.tar.bz2 b/tests/j_corrupt_ext_jnl_sb_block/image.tar.bz2
new file mode 100644 (file)
index 0000000..efb382f
Binary files /dev/null and b/tests/j_corrupt_ext_jnl_sb_block/image.tar.bz2 differ
diff --git a/tests/j_corrupt_ext_jnl_sb_block/name b/tests/j_corrupt_ext_jnl_sb_block/name
new file mode 100644 (file)
index 0000000..a5188be
--- /dev/null
@@ -0,0 +1 @@
+corrupt external journal fs superblock block (metadata_csum)
diff --git a/tests/j_corrupt_ext_jnl_sb_block/script b/tests/j_corrupt_ext_jnl_sb_block/script
new file mode 100644 (file)
index 0000000..02b8e65
--- /dev/null
@@ -0,0 +1,36 @@
+FSCK_OPT=-fy
+OUT=$test_name.log
+if [ -f $test_dir/expect.gz ]; then
+       EXP=$test_name.tmp
+       gunzip < $test_dir/expect.gz > $EXP1
+else
+       EXP=$test_dir/expect
+fi
+
+cp /dev/null $OUT
+
+bzip2 -dc < $test_dir/image.tar.bz2 | tar x
+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp $test_name.img "$JOURNAL_DUMP_DIR/$test_name.img"
+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp $test_name.img.jnl "$JOURNAL_DUMP_DIR/$test_name.img.jnl"
+
+$FSCK $FSCK_OPT -N test_filesys -j $test_name.img.jnl $test_name.img > $OUT.new 2>&1
+status=$?
+echo Exit status is $status >> $OUT.new
+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT
+rm -f $OUT.new
+
+rm -f $TMPFILE $test_name.img $test_name.img.jnl
+
+cmp -s $OUT $EXP
+status=$?
+
+if [ "$status" = 0 ] ; then
+       echo "$test_name: $test_description: ok"
+       touch $test_name.ok
+else
+       echo "$test_name: $test_description: failed"
+       diff $DIFF_OPTS $EXP $OUT > $test_name.failed
+       rm -f $test_name.tmp
+fi
+
+unset IMAGE FSCK_OPT OUT EXP
diff --git a/tests/j_corrupt_ext_jnl_sb_csum/expect b/tests/j_corrupt_ext_jnl_sb_csum/expect
new file mode 100644 (file)
index 0000000..70a4fe7
--- /dev/null
@@ -0,0 +1,25 @@
+External journal superblock checksum does not match superblock.  Fix? yes
+
+test_filesys: recovering journal
+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
+Block bitmap differences:  +(1--31) +34 +(50--82)
+Fix? yes
+
+Inode bitmap differences:  +(1--11)
+Fix? yes
+
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 11/128 files (0.0% non-contiguous), 66/2048 blocks
+Exit status is 1
+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: 11/128 files (0.0% non-contiguous), 66/2048 blocks
+Exit status is 0
diff --git a/tests/j_corrupt_ext_jnl_sb_csum/image.tar.bz2 b/tests/j_corrupt_ext_jnl_sb_csum/image.tar.bz2
new file mode 100644 (file)
index 0000000..d04d584
Binary files /dev/null and b/tests/j_corrupt_ext_jnl_sb_csum/image.tar.bz2 differ
diff --git a/tests/j_corrupt_ext_jnl_sb_csum/name b/tests/j_corrupt_ext_jnl_sb_csum/name
new file mode 100644 (file)
index 0000000..c182f81
--- /dev/null
@@ -0,0 +1 @@
+corrupt external journal fs superblock csum (metadata_csum)
diff --git a/tests/j_corrupt_ext_jnl_sb_csum/script b/tests/j_corrupt_ext_jnl_sb_csum/script
new file mode 100644 (file)
index 0000000..7a110bf
--- /dev/null
@@ -0,0 +1,42 @@
+FSCK_OPT=-fy
+OUT=$test_name.log
+if [ -f $test_dir/expect.gz ]; then
+       EXP=$test_name.tmp
+       gunzip < $test_dir/expect.gz > $EXP1
+else
+       EXP=$test_dir/expect
+fi
+
+cp /dev/null $OUT
+
+bzip2 -dc < $test_dir/image.tar.bz2 | tar x
+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp $test_name.img "$JOURNAL_DUMP_DIR/$test_name.img"
+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp $test_name.img.jnl "$JOURNAL_DUMP_DIR/$test_name.img.jnl"
+
+$FSCK $FSCK_OPT -N test_filesys -j $test_name.img.jnl $test_name.img > $OUT.new 2>&1
+status=$?
+echo Exit status is $status >> $OUT.new
+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT
+rm -f $OUT.new
+
+$FSCK $FSCK_OPT -N test_filesys -j $test_name.img.jnl $test_name.img > $OUT.new 2>&1
+status=$?
+echo Exit status is $status >> $OUT.new
+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT
+rm -f $OUT.new
+
+rm -f $TMPFILE $test_name.img $test_name.img.jnl
+
+cmp -s $OUT $EXP
+status=$?
+
+if [ "$status" = 0 ] ; then
+       echo "$test_name: $test_description: ok"
+       touch $test_name.ok
+else
+       echo "$test_name: $test_description: failed"
+       diff $DIFF_OPTS $EXP $OUT > $test_name.failed
+       rm -f $test_name.tmp
+fi
+
+unset IMAGE FSCK_OPT OUT EXP