diff options
-rw-r--r-- | fs/jbd2/recovery.c | 22 | ||||
-rw-r--r-- | fs/jbd2/revoke.c | 27 |
2 files changed, 48 insertions, 1 deletions
diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c index 980f3d6b5f88..728ecd0705d9 100644 --- a/fs/jbd2/recovery.c +++ b/fs/jbd2/recovery.c | |||
@@ -706,6 +706,25 @@ static int do_one_pass(journal_t *journal, | |||
706 | return err; | 706 | return err; |
707 | } | 707 | } |
708 | 708 | ||
709 | static int jbd2_revoke_block_csum_verify(journal_t *j, | ||
710 | void *buf) | ||
711 | { | ||
712 | struct jbd2_journal_revoke_tail *tail; | ||
713 | __u32 provided, calculated; | ||
714 | |||
715 | if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
716 | return 1; | ||
717 | |||
718 | tail = (struct jbd2_journal_revoke_tail *)(buf + j->j_blocksize - | ||
719 | sizeof(struct jbd2_journal_revoke_tail)); | ||
720 | provided = tail->r_checksum; | ||
721 | tail->r_checksum = 0; | ||
722 | calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize); | ||
723 | tail->r_checksum = provided; | ||
724 | |||
725 | provided = be32_to_cpu(provided); | ||
726 | return provided == calculated; | ||
727 | } | ||
709 | 728 | ||
710 | /* Scan a revoke record, marking all blocks mentioned as revoked. */ | 729 | /* Scan a revoke record, marking all blocks mentioned as revoked. */ |
711 | 730 | ||
@@ -720,6 +739,9 @@ static int scan_revoke_records(journal_t *journal, struct buffer_head *bh, | |||
720 | offset = sizeof(jbd2_journal_revoke_header_t); | 739 | offset = sizeof(jbd2_journal_revoke_header_t); |
721 | max = be32_to_cpu(header->r_count); | 740 | max = be32_to_cpu(header->r_count); |
722 | 741 | ||
742 | if (!jbd2_revoke_block_csum_verify(journal, header)) | ||
743 | return -EINVAL; | ||
744 | |||
723 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) | 745 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) |
724 | record_len = 8; | 746 | record_len = 8; |
725 | 747 | ||
diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c index 6973705d6a3d..f30b80b4ce8b 100644 --- a/fs/jbd2/revoke.c +++ b/fs/jbd2/revoke.c | |||
@@ -578,6 +578,7 @@ static void write_one_revoke_record(journal_t *journal, | |||
578 | struct jbd2_revoke_record_s *record, | 578 | struct jbd2_revoke_record_s *record, |
579 | int write_op) | 579 | int write_op) |
580 | { | 580 | { |
581 | int csum_size = 0; | ||
581 | struct journal_head *descriptor; | 582 | struct journal_head *descriptor; |
582 | int offset; | 583 | int offset; |
583 | journal_header_t *header; | 584 | journal_header_t *header; |
@@ -592,9 +593,13 @@ static void write_one_revoke_record(journal_t *journal, | |||
592 | descriptor = *descriptorp; | 593 | descriptor = *descriptorp; |
593 | offset = *offsetp; | 594 | offset = *offsetp; |
594 | 595 | ||
596 | /* Do we need to leave space at the end for a checksum? */ | ||
597 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
598 | csum_size = sizeof(struct jbd2_journal_revoke_tail); | ||
599 | |||
595 | /* Make sure we have a descriptor with space left for the record */ | 600 | /* Make sure we have a descriptor with space left for the record */ |
596 | if (descriptor) { | 601 | if (descriptor) { |
597 | if (offset == journal->j_blocksize) { | 602 | if (offset >= journal->j_blocksize - csum_size) { |
598 | flush_descriptor(journal, descriptor, offset, write_op); | 603 | flush_descriptor(journal, descriptor, offset, write_op); |
599 | descriptor = NULL; | 604 | descriptor = NULL; |
600 | } | 605 | } |
@@ -631,6 +636,24 @@ static void write_one_revoke_record(journal_t *journal, | |||
631 | *offsetp = offset; | 636 | *offsetp = offset; |
632 | } | 637 | } |
633 | 638 | ||
639 | static void jbd2_revoke_csum_set(journal_t *j, | ||
640 | struct journal_head *descriptor) | ||
641 | { | ||
642 | struct jbd2_journal_revoke_tail *tail; | ||
643 | __u32 csum; | ||
644 | |||
645 | if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
646 | return; | ||
647 | |||
648 | tail = (struct jbd2_journal_revoke_tail *) | ||
649 | (jh2bh(descriptor)->b_data + j->j_blocksize - | ||
650 | sizeof(struct jbd2_journal_revoke_tail)); | ||
651 | tail->r_checksum = 0; | ||
652 | csum = jbd2_chksum(j, j->j_csum_seed, jh2bh(descriptor)->b_data, | ||
653 | j->j_blocksize); | ||
654 | tail->r_checksum = cpu_to_be32(csum); | ||
655 | } | ||
656 | |||
634 | /* | 657 | /* |
635 | * Flush a revoke descriptor out to the journal. If we are aborting, | 658 | * Flush a revoke descriptor out to the journal. If we are aborting, |
636 | * this is a noop; otherwise we are generating a buffer which needs to | 659 | * this is a noop; otherwise we are generating a buffer which needs to |
@@ -652,6 +675,8 @@ static void flush_descriptor(journal_t *journal, | |||
652 | 675 | ||
653 | header = (jbd2_journal_revoke_header_t *) jh2bh(descriptor)->b_data; | 676 | header = (jbd2_journal_revoke_header_t *) jh2bh(descriptor)->b_data; |
654 | header->r_count = cpu_to_be32(offset); | 677 | header->r_count = cpu_to_be32(offset); |
678 | jbd2_revoke_csum_set(journal, descriptor); | ||
679 | |||
655 | set_buffer_jwrite(bh); | 680 | set_buffer_jwrite(bh); |
656 | BUFFER_TRACE(bh, "write"); | 681 | BUFFER_TRACE(bh, "write"); |
657 | set_buffer_dirty(bh); | 682 | set_buffer_dirty(bh); |