|
@@ -174,6 +174,25 @@ static int jread(struct buffer_head **bhp, journal_t *journal,
|
|
|
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.
|
|
@@ -186,6 +205,9 @@ static int count_tags(journal_t *journal, struct buffer_head *bh)
|
|
|
int nr = 0, size = journal->j_blocksize;
|
|
|
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)];
|
|
|
|
|
|
while ((tagp - bh->b_data + tag_bytes) <= size) {
|
|
@@ -366,6 +388,7 @@ static int do_one_pass(journal_t *journal,
|
|
|
int blocktype;
|
|
|
int tag_bytes = journal_tag_bytes(journal);
|
|
|
__u32 crc32_sum = ~0; /* Transactional Checksums */
|
|
|
+ int descr_csum_size = 0;
|
|
|
|
|
|
/*
|
|
|
* 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,
|
|
|
|
|
|
switch(blocktype) {
|
|
|
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
|
|
|
* in pass REPLAY; if journal_checksums enabled, then
|
|
|
* calculate checksums in PASS_SCAN, otherwise,
|
|
@@ -481,7 +516,7 @@ static int do_one_pass(journal_t *journal,
|
|
|
|
|
|
tagp = &bh->b_data[sizeof(journal_header_t)];
|
|
|
while ((tagp - bh->b_data + tag_bytes)
|
|
|
- <= journal->j_blocksize) {
|
|
|
+ <= journal->j_blocksize - descr_csum_size) {
|
|
|
unsigned long io_block;
|
|
|
|
|
|
tag = (journal_block_tag_t *) tagp;
|