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 | |
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')
-rw-r--r-- | fs/jbd2/commit.c | 25 | ||||
-rw-r--r-- | fs/jbd2/recovery.c | 37 |
2 files changed, 60 insertions, 2 deletions
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 69d780310aea..5d505cfd21c2 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c | |||
@@ -301,6 +301,24 @@ static void write_tag_block(int tag_bytes, journal_block_tag_t *tag, | |||
301 | tag->t_blocknr_high = cpu_to_be32((block >> 31) >> 1); | 301 | tag->t_blocknr_high = cpu_to_be32((block >> 31) >> 1); |
302 | } | 302 | } |
303 | 303 | ||
304 | static void jbd2_descr_block_csum_set(journal_t *j, | ||
305 | struct journal_head *descriptor) | ||
306 | { | ||
307 | struct jbd2_journal_block_tail *tail; | ||
308 | __u32 csum; | ||
309 | |||
310 | if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
311 | return; | ||
312 | |||
313 | tail = (struct jbd2_journal_block_tail *) | ||
314 | (jh2bh(descriptor)->b_data + j->j_blocksize - | ||
315 | sizeof(struct jbd2_journal_block_tail)); | ||
316 | tail->t_checksum = 0; | ||
317 | csum = jbd2_chksum(j, j->j_csum_seed, jh2bh(descriptor)->b_data, | ||
318 | j->j_blocksize); | ||
319 | tail->t_checksum = cpu_to_be32(csum); | ||
320 | } | ||
321 | |||
304 | /* | 322 | /* |
305 | * jbd2_journal_commit_transaction | 323 | * jbd2_journal_commit_transaction |
306 | * | 324 | * |
@@ -334,6 +352,10 @@ void jbd2_journal_commit_transaction(journal_t *journal) | |||
334 | unsigned long first_block; | 352 | unsigned long first_block; |
335 | tid_t first_tid; | 353 | tid_t first_tid; |
336 | int update_tail; | 354 | int update_tail; |
355 | int csum_size = 0; | ||
356 | |||
357 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
358 | csum_size = sizeof(struct jbd2_journal_block_tail); | ||
337 | 359 | ||
338 | /* | 360 | /* |
339 | * First job: lock down the current transaction and wait for | 361 | * First job: lock down the current transaction and wait for |
@@ -643,7 +665,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) | |||
643 | 665 | ||
644 | if (bufs == journal->j_wbufsize || | 666 | if (bufs == journal->j_wbufsize || |
645 | commit_transaction->t_buffers == NULL || | 667 | commit_transaction->t_buffers == NULL || |
646 | space_left < tag_bytes + 16) { | 668 | space_left < tag_bytes + 16 + csum_size) { |
647 | 669 | ||
648 | jbd_debug(4, "JBD2: Submit %d IOs\n", bufs); | 670 | jbd_debug(4, "JBD2: Submit %d IOs\n", bufs); |
649 | 671 | ||
@@ -653,6 +675,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) | |||
653 | 675 | ||
654 | tag->t_flags |= cpu_to_be16(JBD2_FLAG_LAST_TAG); | 676 | tag->t_flags |= cpu_to_be16(JBD2_FLAG_LAST_TAG); |
655 | 677 | ||
678 | jbd2_descr_block_csum_set(journal, descriptor); | ||
656 | start_journal_io: | 679 | start_journal_io: |
657 | for (i = 0; i < bufs; i++) { | 680 | for (i = 0; i < bufs; i++) { |
658 | struct buffer_head *bh = wbuf[i]; | 681 | struct buffer_head *bh = wbuf[i]; |
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; |