Commit 3caa487f authored by Darrick J. Wong's avatar Darrick J. Wong Committed by Theodore Ts'o

jbd2: checksum descriptor blocks

Calculate and verify a checksum of each descriptor block.
Signed-off-by: default avatarDarrick J. Wong <djwong@us.ibm.com>
Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
parent 42a7106d
...@@ -301,6 +301,24 @@ static void write_tag_block(int tag_bytes, journal_block_tag_t *tag, ...@@ -301,6 +301,24 @@ static void write_tag_block(int tag_bytes, journal_block_tag_t *tag,
tag->t_blocknr_high = cpu_to_be32((block >> 31) >> 1); tag->t_blocknr_high = cpu_to_be32((block >> 31) >> 1);
} }
static void jbd2_descr_block_csum_set(journal_t *j,
struct journal_head *descriptor)
{
struct jbd2_journal_block_tail *tail;
__u32 csum;
if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2))
return;
tail = (struct jbd2_journal_block_tail *)
(jh2bh(descriptor)->b_data + j->j_blocksize -
sizeof(struct jbd2_journal_block_tail));
tail->t_checksum = 0;
csum = jbd2_chksum(j, j->j_csum_seed, jh2bh(descriptor)->b_data,
j->j_blocksize);
tail->t_checksum = cpu_to_be32(csum);
}
/* /*
* jbd2_journal_commit_transaction * jbd2_journal_commit_transaction
* *
...@@ -334,6 +352,10 @@ void jbd2_journal_commit_transaction(journal_t *journal) ...@@ -334,6 +352,10 @@ void jbd2_journal_commit_transaction(journal_t *journal)
unsigned long first_block; unsigned long first_block;
tid_t first_tid; tid_t first_tid;
int update_tail; int update_tail;
int csum_size = 0;
if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2))
csum_size = sizeof(struct jbd2_journal_block_tail);
/* /*
* First job: lock down the current transaction and wait for * First job: lock down the current transaction and wait for
...@@ -643,7 +665,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) ...@@ -643,7 +665,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
if (bufs == journal->j_wbufsize || if (bufs == journal->j_wbufsize ||
commit_transaction->t_buffers == NULL || commit_transaction->t_buffers == NULL ||
space_left < tag_bytes + 16) { space_left < tag_bytes + 16 + csum_size) {
jbd_debug(4, "JBD2: Submit %d IOs\n", bufs); jbd_debug(4, "JBD2: Submit %d IOs\n", bufs);
...@@ -653,6 +675,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) ...@@ -653,6 +675,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
tag->t_flags |= cpu_to_be16(JBD2_FLAG_LAST_TAG); tag->t_flags |= cpu_to_be16(JBD2_FLAG_LAST_TAG);
jbd2_descr_block_csum_set(journal, descriptor);
start_journal_io: start_journal_io:
for (i = 0; i < bufs; i++) { for (i = 0; i < bufs; i++) {
struct buffer_head *bh = wbuf[i]; struct buffer_head *bh = wbuf[i];
......
...@@ -174,6 +174,25 @@ static int jread(struct buffer_head **bhp, journal_t *journal, ...@@ -174,6 +174,25 @@ static int jread(struct buffer_head **bhp, journal_t *journal,
return 0; return 0;
} }
static int jbd2_descr_block_csum_verify(journal_t *j,
void *buf)
{
struct jbd2_journal_block_tail *tail;
__u32 provided, calculated;
if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2))
return 1;
tail = (struct jbd2_journal_block_tail *)(buf + j->j_blocksize -
sizeof(struct jbd2_journal_block_tail));
provided = tail->t_checksum;
tail->t_checksum = 0;
calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize);
tail->t_checksum = provided;
provided = be32_to_cpu(provided);
return provided == calculated;
}
/* /*
* Count the number of in-use tags in a journal descriptor block. * Count the number of in-use tags in a journal descriptor block.
...@@ -186,6 +205,9 @@ static int count_tags(journal_t *journal, struct buffer_head *bh) ...@@ -186,6 +205,9 @@ static int count_tags(journal_t *journal, struct buffer_head *bh)
int nr = 0, size = journal->j_blocksize; int nr = 0, size = journal->j_blocksize;
int tag_bytes = journal_tag_bytes(journal); int tag_bytes = journal_tag_bytes(journal);
if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2))
size -= sizeof(struct jbd2_journal_block_tail);
tagp = &bh->b_data[sizeof(journal_header_t)]; tagp = &bh->b_data[sizeof(journal_header_t)];
while ((tagp - bh->b_data + tag_bytes) <= size) { while ((tagp - bh->b_data + tag_bytes) <= size) {
...@@ -366,6 +388,7 @@ static int do_one_pass(journal_t *journal, ...@@ -366,6 +388,7 @@ static int do_one_pass(journal_t *journal,
int blocktype; int blocktype;
int tag_bytes = journal_tag_bytes(journal); int tag_bytes = journal_tag_bytes(journal);
__u32 crc32_sum = ~0; /* Transactional Checksums */ __u32 crc32_sum = ~0; /* Transactional Checksums */
int descr_csum_size = 0;
/* /*
* First thing is to establish what we expect to find in the log * First thing is to establish what we expect to find in the log
...@@ -451,6 +474,18 @@ static int do_one_pass(journal_t *journal, ...@@ -451,6 +474,18 @@ static int do_one_pass(journal_t *journal,
switch(blocktype) { switch(blocktype) {
case JBD2_DESCRIPTOR_BLOCK: case JBD2_DESCRIPTOR_BLOCK:
/* Verify checksum first */
if (JBD2_HAS_INCOMPAT_FEATURE(journal,
JBD2_FEATURE_INCOMPAT_CSUM_V2))
descr_csum_size =
sizeof(struct jbd2_journal_block_tail);
if (descr_csum_size > 0 &&
!jbd2_descr_block_csum_verify(journal,
bh->b_data)) {
err = -EIO;
goto failed;
}
/* If it is a valid descriptor block, replay it /* If it is a valid descriptor block, replay it
* in pass REPLAY; if journal_checksums enabled, then * in pass REPLAY; if journal_checksums enabled, then
* calculate checksums in PASS_SCAN, otherwise, * calculate checksums in PASS_SCAN, otherwise,
...@@ -481,7 +516,7 @@ static int do_one_pass(journal_t *journal, ...@@ -481,7 +516,7 @@ static int do_one_pass(journal_t *journal,
tagp = &bh->b_data[sizeof(journal_header_t)]; tagp = &bh->b_data[sizeof(journal_header_t)];
while ((tagp - bh->b_data + tag_bytes) while ((tagp - bh->b_data + tag_bytes)
<= journal->j_blocksize) { <= journal->j_blocksize - descr_csum_size) {
unsigned long io_block; unsigned long io_block;
tag = (journal_block_tag_t *) tagp; tag = (journal_block_tag_t *) tagp;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment