|
@@ -375,6 +375,24 @@ static int calc_chksums(journal_t *journal, struct buffer_head *bh,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int jbd2_commit_block_csum_verify(journal_t *j, void *buf)
|
|
|
+{
|
|
|
+ struct commit_header *h;
|
|
|
+ __u32 provided, calculated;
|
|
|
+
|
|
|
+ if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2))
|
|
|
+ return 1;
|
|
|
+
|
|
|
+ h = buf;
|
|
|
+ provided = h->h_chksum[0];
|
|
|
+ h->h_chksum[0] = 0;
|
|
|
+ calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize);
|
|
|
+ h->h_chksum[0] = provided;
|
|
|
+
|
|
|
+ provided = be32_to_cpu(provided);
|
|
|
+ return provided == calculated;
|
|
|
+}
|
|
|
+
|
|
|
static int do_one_pass(journal_t *journal,
|
|
|
struct recovery_info *info, enum passtype pass)
|
|
|
{
|
|
@@ -685,6 +703,19 @@ static int do_one_pass(journal_t *journal,
|
|
|
}
|
|
|
crc32_sum = ~0;
|
|
|
}
|
|
|
+ if (pass == PASS_SCAN &&
|
|
|
+ !jbd2_commit_block_csum_verify(journal,
|
|
|
+ bh->b_data)) {
|
|
|
+ info->end_transaction = next_commit_ID;
|
|
|
+
|
|
|
+ if (!JBD2_HAS_INCOMPAT_FEATURE(journal,
|
|
|
+ JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) {
|
|
|
+ journal->j_failed_commit =
|
|
|
+ next_commit_ID;
|
|
|
+ brelse(bh);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
brelse(bh);
|
|
|
next_commit_ID++;
|
|
|
continue;
|