diff options
author | Darrick J. Wong <djwong@us.ibm.com> | 2012-05-27 08:12:12 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2012-05-27 08:12:12 -0400 |
commit | c390087591dcbecd244c31d979ccdad49ae83364 (patch) | |
tree | c3ccbd028cb7970070114a8b0f45adfbebb113cb /fs/jbd2 | |
parent | 1f56c5890e3e815c6f4eabfc87a8a81f439b6f3d (diff) |
jbd2: checksum data blocks that are stored in the journal
Calculate and verify checksums of each data block being stored in the journal.
Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/jbd2')
-rw-r--r-- | fs/jbd2/commit.c | 22 | ||||
-rw-r--r-- | fs/jbd2/journal.c | 10 | ||||
-rw-r--r-- | fs/jbd2/recovery.c | 30 |
3 files changed, 60 insertions, 2 deletions
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 16e1fe2a769f..216f4299f65e 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c | |||
@@ -338,6 +338,26 @@ static void jbd2_descr_block_csum_set(journal_t *j, | |||
338 | tail->t_checksum = cpu_to_be32(csum); | 338 | tail->t_checksum = cpu_to_be32(csum); |
339 | } | 339 | } |
340 | 340 | ||
341 | static void jbd2_block_tag_csum_set(journal_t *j, journal_block_tag_t *tag, | ||
342 | struct buffer_head *bh, __u32 sequence) | ||
343 | { | ||
344 | struct page *page = bh->b_page; | ||
345 | __u8 *addr; | ||
346 | __u32 csum; | ||
347 | |||
348 | if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
349 | return; | ||
350 | |||
351 | sequence = cpu_to_be32(sequence); | ||
352 | addr = kmap_atomic(page, KM_USER0); | ||
353 | csum = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&sequence, | ||
354 | sizeof(sequence)); | ||
355 | csum = jbd2_chksum(j, csum, addr + offset_in_page(bh->b_data), | ||
356 | bh->b_size); | ||
357 | kunmap_atomic(addr, KM_USER0); | ||
358 | |||
359 | tag->t_checksum = cpu_to_be32(csum); | ||
360 | } | ||
341 | /* | 361 | /* |
342 | * jbd2_journal_commit_transaction | 362 | * jbd2_journal_commit_transaction |
343 | * | 363 | * |
@@ -669,6 +689,8 @@ void jbd2_journal_commit_transaction(journal_t *journal) | |||
669 | tag = (journal_block_tag_t *) tagp; | 689 | tag = (journal_block_tag_t *) tagp; |
670 | write_tag_block(tag_bytes, tag, jh2bh(jh)->b_blocknr); | 690 | write_tag_block(tag_bytes, tag, jh2bh(jh)->b_blocknr); |
671 | tag->t_flags = cpu_to_be16(tag_flag); | 691 | tag->t_flags = cpu_to_be16(tag_flag); |
692 | jbd2_block_tag_csum_set(journal, tag, jh2bh(new_jh), | ||
693 | commit_transaction->t_tid); | ||
672 | tagp += tag_bytes; | 694 | tagp += tag_bytes; |
673 | space_left -= tag_bytes; | 695 | space_left -= tag_bytes; |
674 | 696 | ||
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 9072f03d30b5..e9a3c4c85594 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c | |||
@@ -2097,10 +2097,16 @@ int jbd2_journal_blocks_per_page(struct inode *inode) | |||
2097 | */ | 2097 | */ |
2098 | size_t journal_tag_bytes(journal_t *journal) | 2098 | size_t journal_tag_bytes(journal_t *journal) |
2099 | { | 2099 | { |
2100 | journal_block_tag_t tag; | ||
2101 | size_t x = 0; | ||
2102 | |||
2103 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
2104 | x += sizeof(tag.t_checksum); | ||
2105 | |||
2100 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) | 2106 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) |
2101 | return JBD2_TAG_SIZE64; | 2107 | return x + JBD2_TAG_SIZE64; |
2102 | else | 2108 | else |
2103 | return JBD2_TAG_SIZE32; | 2109 | return x + JBD2_TAG_SIZE32; |
2104 | } | 2110 | } |
2105 | 2111 | ||
2106 | /* | 2112 | /* |
diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c index df4a20e7d854..0131e4362534 100644 --- a/fs/jbd2/recovery.c +++ b/fs/jbd2/recovery.c | |||
@@ -393,6 +393,23 @@ static int jbd2_commit_block_csum_verify(journal_t *j, void *buf) | |||
393 | return provided == calculated; | 393 | return provided == calculated; |
394 | } | 394 | } |
395 | 395 | ||
396 | static int jbd2_block_tag_csum_verify(journal_t *j, journal_block_tag_t *tag, | ||
397 | void *buf, __u32 sequence) | ||
398 | { | ||
399 | __u32 provided, calculated; | ||
400 | |||
401 | if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
402 | return 1; | ||
403 | |||
404 | sequence = cpu_to_be32(sequence); | ||
405 | calculated = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&sequence, | ||
406 | sizeof(sequence)); | ||
407 | calculated = jbd2_chksum(j, calculated, buf, j->j_blocksize); | ||
408 | provided = be32_to_cpu(tag->t_checksum); | ||
409 | |||
410 | return provided == cpu_to_be32(calculated); | ||
411 | } | ||
412 | |||
396 | static int do_one_pass(journal_t *journal, | 413 | static int do_one_pass(journal_t *journal, |
397 | struct recovery_info *info, enum passtype pass) | 414 | struct recovery_info *info, enum passtype pass) |
398 | { | 415 | { |
@@ -569,6 +586,19 @@ static int do_one_pass(journal_t *journal, | |||
569 | goto skip_write; | 586 | goto skip_write; |
570 | } | 587 | } |
571 | 588 | ||
589 | /* Look for block corruption */ | ||
590 | if (!jbd2_block_tag_csum_verify( | ||
591 | journal, tag, obh->b_data, | ||
592 | be32_to_cpu(tmp->h_sequence))) { | ||
593 | brelse(obh); | ||
594 | success = -EIO; | ||
595 | printk(KERN_ERR "JBD: Invalid " | ||
596 | "checksum recovering " | ||
597 | "block %llu in log\n", | ||
598 | blocknr); | ||
599 | continue; | ||
600 | } | ||
601 | |||
572 | /* Find a buffer for the new | 602 | /* Find a buffer for the new |
573 | * data being restored */ | 603 | * data being restored */ |
574 | nbh = __getblk(journal->j_fs_dev, | 604 | nbh = __getblk(journal->j_fs_dev, |