Skip to content

Commit

Permalink
jbd2: checksum data blocks that are stored in the journal
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Darrick J. Wong authored and Theodore Ts'o committed May 27, 2012
1 parent 1f56c58 commit c390087
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 2 deletions.
22 changes: 22 additions & 0 deletions fs/jbd2/commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,26 @@ static void jbd2_descr_block_csum_set(journal_t *j,
tail->t_checksum = cpu_to_be32(csum);
}

static void jbd2_block_tag_csum_set(journal_t *j, journal_block_tag_t *tag,
struct buffer_head *bh, __u32 sequence)
{
struct page *page = bh->b_page;
__u8 *addr;
__u32 csum;

if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2))
return;

sequence = cpu_to_be32(sequence);
addr = kmap_atomic(page, KM_USER0);
csum = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&sequence,
sizeof(sequence));
csum = jbd2_chksum(j, csum, addr + offset_in_page(bh->b_data),
bh->b_size);
kunmap_atomic(addr, KM_USER0);

tag->t_checksum = cpu_to_be32(csum);
}
/*
* jbd2_journal_commit_transaction
*
Expand Down Expand Up @@ -669,6 +689,8 @@ void jbd2_journal_commit_transaction(journal_t *journal)
tag = (journal_block_tag_t *) tagp;
write_tag_block(tag_bytes, tag, jh2bh(jh)->b_blocknr);
tag->t_flags = cpu_to_be16(tag_flag);
jbd2_block_tag_csum_set(journal, tag, jh2bh(new_jh),
commit_transaction->t_tid);
tagp += tag_bytes;
space_left -= tag_bytes;

Expand Down
10 changes: 8 additions & 2 deletions fs/jbd2/journal.c
Original file line number Diff line number Diff line change
Expand Up @@ -2097,10 +2097,16 @@ int jbd2_journal_blocks_per_page(struct inode *inode)
*/
size_t journal_tag_bytes(journal_t *journal)
{
journal_block_tag_t tag;
size_t x = 0;

if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2))
x += sizeof(tag.t_checksum);

if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT))
return JBD2_TAG_SIZE64;
return x + JBD2_TAG_SIZE64;
else
return JBD2_TAG_SIZE32;
return x + JBD2_TAG_SIZE32;
}

/*
Expand Down
30 changes: 30 additions & 0 deletions fs/jbd2/recovery.c
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,23 @@ 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 (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2))
return 1;

sequence = cpu_to_be32(sequence);
calculated = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&sequence,
sizeof(sequence));
calculated = jbd2_chksum(j, calculated, buf, j->j_blocksize);
provided = be32_to_cpu(tag->t_checksum);

return provided == cpu_to_be32(calculated);
}

static int do_one_pass(journal_t *journal,
struct recovery_info *info, enum passtype pass)
{
Expand Down Expand Up @@ -569,6 +586,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 %llu in log\n",
blocknr);
continue;
}

/* Find a buffer for the new
* data being restored */
nbh = __getblk(journal->j_fs_dev,
Expand Down

0 comments on commit c390087

Please sign in to comment.