Whamcloud - gitweb
e2fsck: verify data block checksums when recovering journal
authorDarrick J. Wong <djwong@us.ibm.com>
Fri, 3 Aug 2012 00:47:46 +0000 (20:47 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Fri, 3 Aug 2012 00:47:46 +0000 (20:47 -0400)
Check the data block checksums when recovering the journal.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
e2fsck/jfs_user.h
e2fsck/recovery.c
lib/ext2fs/kernel-jbd.h

index 92f8ae2..0a8a9e2 100644 (file)
@@ -104,17 +104,6 @@ _INLINE_ void do_cache_destroy(lkmem_cache_t *cache)
        free(cache);
 }
 
-/*
- * helper functions to deal with 32 or 64bit block numbers.
- */
-_INLINE_ size_t journal_tag_bytes(journal_t *journal)
-{
-       if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT))
-               return JBD_TAG_SIZE64;
-       else
-               return JBD_TAG_SIZE32;
-}
-
 #undef _INLINE_
 #endif
 
index 897a3ff..f09791c 100644 (file)
@@ -393,6 +393,25 @@ static int jbd2_commit_block_csum_verify(journal_t *j, void *buf)
        return provided == calculated;
 }
 
+static int jbd2_block_tag_csum_verify(journal_t *j, journal_block_tag_t *tag,
+                                     void *buf, __u32 sequence)
+{
+       __u32 provided, calculated;
+
+       if (!JFS_HAS_INCOMPAT_FEATURE(j, JFS_FEATURE_INCOMPAT_CSUM_V2))
+               return 1;
+
+       sequence = ext2fs_cpu_to_be32(sequence);
+       calculated = ext2fs_crc32c_le(~0, j->j_superblock->s_uuid,
+                                     sizeof(j->j_superblock->s_uuid));
+       calculated = ext2fs_crc32c_le(calculated, (__u8 *)&sequence,
+                                     sizeof(sequence));
+       calculated = ext2fs_crc32c_le(calculated, buf, j->j_blocksize) & 0xffff;
+       provided = ext2fs_be16_to_cpu(tag->t_checksum);
+
+       return provided == ext2fs_cpu_to_be32(calculated);
+}
+
 static int do_one_pass(journal_t *journal,
                        struct recovery_info *info, enum passtype pass)
 {
@@ -574,6 +593,19 @@ static int do_one_pass(journal_t *journal,
                                                goto skip_write;
                                        }
 
+                                       /* Look for block corruption */
+                                       if (!jbd2_block_tag_csum_verify(
+                                               journal, tag, obh->b_data,
+                                               be32_to_cpu(tmp->h_sequence))) {
+                                               brelse(obh);
+                                               success = -EIO;
+                                               printk(KERN_ERR "JBD: Invalid "
+                                                      "checksum recovering "
+                                                      "block %ld in log\n",
+                                                      blocknr);
+                                               continue;
+                                       }
+
                                        /* Find a buffer for the new
                                         * data being restored */
                                        nbh = __getblk(journal->j_fs_dev,
index accd29c..8e0b4d6 100644 (file)
@@ -261,6 +261,36 @@ typedef struct journal_superblock_s
                                         JFS_FEATURE_INCOMPAT_ASYNC_COMMIT|\
                                         JFS_FEATURE_INCOMPAT_64BIT)
 
+#if (defined(E2FSCK_INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS))
+#ifdef E2FSCK_INCLUDE_INLINE_FUNCS
+#define _INLINE_ extern
+#else
+#ifdef __GNUC__
+#define _INLINE_ extern __inline__
+#else                          /* For Watcom C */
+#define _INLINE_ extern inline
+#endif
+#endif
+
+/*
+ * helper functions to deal with 32 or 64bit block numbers.
+ */
+_INLINE_ size_t journal_tag_bytes(journal_t *journal)
+{
+       journal_block_tag_t tag;
+       size_t x = 0;
+
+       if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V2))
+               x += sizeof(tag.t_checksum);
+
+       if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT))
+               return x + JBD_TAG_SIZE64;
+       else
+               return x + JBD_TAG_SIZE32;
+}
+#undef _INLINE_
+#endif
+
 #ifdef __KERNEL__
 
 #include <linux/fs.h>