diff options
author | Darrick J. Wong <djwong@us.ibm.com> | 2012-05-27 08:10:22 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2012-05-27 08:10:22 -0400 |
commit | 3caa487f53f65fd1e3950a6b6ae1709e6c43b334 (patch) | |
tree | 02ee3f18422d9ffed974eb1019e98b2ee1ade01c /fs/jbd2/recovery.c | |
parent | 42a7106de636ebf9c0b93d25b4230e14f5f2682e (diff) |
jbd2: checksum descriptor blocks
Calculate and verify a checksum of each descriptor block.
Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/jbd2/recovery.c')
-rw-r--r-- | fs/jbd2/recovery.c | 37 |
1 files changed, 36 insertions, 1 deletions
diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c index 728ecd0705d9..066ee603db50 100644 --- a/fs/jbd2/recovery.c +++ b/fs/jbd2/recovery.c | |||
@@ -174,6 +174,25 @@ static int jread(struct buffer_head **bhp, journal_t *journal, | |||
174 | return 0; | 174 | return 0; |
175 | } | 175 | } |
176 | 176 | ||
177 | static int jbd2_descr_block_csum_verify(journal_t *j, | ||
178 | void *buf) | ||
179 | { | ||
180 | struct jbd2_journal_block_tail *tail; | ||
181 | __u32 provided, calculated; | ||
182 | |||
183 | if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
184 | return 1; | ||
185 | |||
186 | tail = (struct jbd2_journal_block_tail *)(buf + j->j_blocksize - | ||
187 | sizeof(struct jbd2_journal_block_tail)); | ||
188 | provided = tail->t_checksum; | ||
189 | tail->t_checksum = 0; | ||
190 | calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize); | ||
191 | tail->t_checksum = provided; | ||
192 | |||
193 | provided = be32_to_cpu(provided); | ||
194 | return provided == calculated; | ||
195 | } | ||
177 | 196 | ||
178 | /* | 197 | /* |
179 | * Count the number of in-use tags in a journal descriptor block. | 198 | * 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 | int nr = 0, size = journal->j_blocksize; | 205 | int nr = 0, size = journal->j_blocksize; |
187 | int tag_bytes = journal_tag_bytes(journal); | 206 | int tag_bytes = journal_tag_bytes(journal); |
188 | 207 | ||
208 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
209 | size -= sizeof(struct jbd2_journal_block_tail); | ||
210 | |||
189 | tagp = &bh->b_data[sizeof(journal_header_t)]; | 211 | tagp = &bh->b_data[sizeof(journal_header_t)]; |
190 | 212 | ||
191 | while ((tagp - bh->b_data + tag_bytes) <= size) { | 213 | while ((tagp - bh->b_data + tag_bytes) <= size) { |
@@ -366,6 +388,7 @@ static int do_one_pass(journal_t *journal, | |||
366 | int blocktype; | 388 | int blocktype; |
367 | int tag_bytes = journal_tag_bytes(journal); | 389 | int tag_bytes = journal_tag_bytes(journal); |
368 | __u32 crc32_sum = ~0; /* Transactional Checksums */ | 390 | __u32 crc32_sum = ~0; /* Transactional Checksums */ |
391 | int descr_csum_size = 0; | ||
369 | 392 | ||
370 | /* | 393 | /* |
371 | * First thing is to establish what we expect to find in the log | 394 | * 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 | 474 | ||
452 | switch(blocktype) { | 475 | switch(blocktype) { |
453 | case JBD2_DESCRIPTOR_BLOCK: | 476 | case JBD2_DESCRIPTOR_BLOCK: |
477 | /* Verify checksum first */ | ||
478 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, | ||
479 | JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
480 | descr_csum_size = | ||
481 | sizeof(struct jbd2_journal_block_tail); | ||
482 | if (descr_csum_size > 0 && | ||
483 | !jbd2_descr_block_csum_verify(journal, | ||
484 | bh->b_data)) { | ||
485 | err = -EIO; | ||
486 | goto failed; | ||
487 | } | ||
488 | |||
454 | /* If it is a valid descriptor block, replay it | 489 | /* If it is a valid descriptor block, replay it |
455 | * in pass REPLAY; if journal_checksums enabled, then | 490 | * in pass REPLAY; if journal_checksums enabled, then |
456 | * calculate checksums in PASS_SCAN, otherwise, | 491 | * calculate checksums in PASS_SCAN, otherwise, |
@@ -481,7 +516,7 @@ static int do_one_pass(journal_t *journal, | |||
481 | 516 | ||
482 | tagp = &bh->b_data[sizeof(journal_header_t)]; | 517 | tagp = &bh->b_data[sizeof(journal_header_t)]; |
483 | while ((tagp - bh->b_data + tag_bytes) | 518 | while ((tagp - bh->b_data + tag_bytes) |
484 | <= journal->j_blocksize) { | 519 | <= journal->j_blocksize - descr_csum_size) { |
485 | unsigned long io_block; | 520 | unsigned long io_block; |
486 | 521 | ||
487 | tag = (journal_block_tag_t *) tagp; | 522 | tag = (journal_block_tag_t *) tagp; |