aboutsummaryrefslogtreecommitdiffstats
path: root/fs/jbd2
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@us.ibm.com>2012-05-27 08:12:12 -0400
committerTheodore Ts'o <tytso@mit.edu>2012-05-27 08:12:12 -0400
commitc390087591dcbecd244c31d979ccdad49ae83364 (patch)
treec3ccbd028cb7970070114a8b0f45adfbebb113cb /fs/jbd2
parent1f56c5890e3e815c6f4eabfc87a8a81f439b6f3d (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.c22
-rw-r--r--fs/jbd2/journal.c10
-rw-r--r--fs/jbd2/recovery.c30
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
341static 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 */
2098size_t journal_tag_bytes(journal_t *journal) 2098size_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
396static 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
396static int do_one_pass(journal_t *journal, 413static 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,