Commit 35ef6df5 authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet

bcachefs: Improve journal entry validate code

Previously, the journal entry read code was changed so that if we got a
journal entry that failed validation, we'd try to use it, preferring to
use a good version from another device if available.

But this left a bug where if an earlier validation check (say, checksum)
failed, the later checks (for last_seq) wouldn't run and we'd end up
using a journal entry with a garbage last_seq field. This fixes that so
that the later validation checks run and if necessary change those
fields to something sensible.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent eb8e6e9c
...@@ -431,46 +431,45 @@ static int jset_validate(struct bch_fs *c, ...@@ -431,46 +431,45 @@ static int jset_validate(struct bch_fs *c,
"%s sector %llu seq %llu: unknown journal entry version %u", "%s sector %llu seq %llu: unknown journal entry version %u",
ca->name, sector, le64_to_cpu(jset->seq), ca->name, sector, le64_to_cpu(jset->seq),
version)) { version)) {
/* XXX: note we might have missing journal entries */ /* don't try to continue: */
return JOURNAL_ENTRY_BAD; return EINVAL;
} }
if (bytes > (sectors_read << 9) &&
sectors_read < bucket_sectors_left)
return JOURNAL_ENTRY_REREAD;
if (journal_entry_err_on(bytes > bucket_sectors_left << 9, c, if (journal_entry_err_on(bytes > bucket_sectors_left << 9, c,
"%s sector %llu seq %llu: journal entry too big (%zu bytes)", "%s sector %llu seq %llu: journal entry too big (%zu bytes)",
ca->name, sector, le64_to_cpu(jset->seq), bytes)) { ca->name, sector, le64_to_cpu(jset->seq), bytes)) {
/* XXX: note we might have missing journal entries */ ret = JOURNAL_ENTRY_BAD;
return JOURNAL_ENTRY_BAD; le32_add_cpu(&jset->u64s,
-((bytes - (bucket_sectors_left << 9)) / 8));
} }
if (bytes > sectors_read << 9)
return JOURNAL_ENTRY_REREAD;
if (fsck_err_on(!bch2_checksum_type_valid(c, JSET_CSUM_TYPE(jset)), c, if (fsck_err_on(!bch2_checksum_type_valid(c, JSET_CSUM_TYPE(jset)), c,
"%s sector %llu seq %llu: journal entry with unknown csum type %llu", "%s sector %llu seq %llu: journal entry with unknown csum type %llu",
ca->name, sector, le64_to_cpu(jset->seq), ca->name, sector, le64_to_cpu(jset->seq),
JSET_CSUM_TYPE(jset))) JSET_CSUM_TYPE(jset))) {
return JOURNAL_ENTRY_BAD; ret = JOURNAL_ENTRY_BAD;
goto bad_csum_type;
}
csum = csum_vstruct(c, JSET_CSUM_TYPE(jset), journal_nonce(jset), jset); csum = csum_vstruct(c, JSET_CSUM_TYPE(jset), journal_nonce(jset), jset);
if (journal_entry_err_on(bch2_crc_cmp(csum, jset->csum), c, if (journal_entry_err_on(bch2_crc_cmp(csum, jset->csum), c,
"%s sector %llu seq %llu: journal checksum bad", "%s sector %llu seq %llu: journal checksum bad",
ca->name, sector, le64_to_cpu(jset->seq))) { ca->name, sector, le64_to_cpu(jset->seq)))
/* XXX: retry IO, when we start retrying checksum errors */ ret = JOURNAL_ENTRY_BAD;
/* XXX: note we might have missing journal entries */
return JOURNAL_ENTRY_BAD;
}
bch2_encrypt(c, JSET_CSUM_TYPE(jset), journal_nonce(jset), bch2_encrypt(c, JSET_CSUM_TYPE(jset), journal_nonce(jset),
jset->encrypted_start, jset->encrypted_start,
vstruct_end(jset) - (void *) jset->encrypted_start); vstruct_end(jset) - (void *) jset->encrypted_start);
bad_csum_type:
if (journal_entry_err_on(le64_to_cpu(jset->last_seq) > le64_to_cpu(jset->seq), c, if (journal_entry_err_on(le64_to_cpu(jset->last_seq) > le64_to_cpu(jset->seq), c,
"invalid journal entry: last_seq > seq")) { "invalid journal entry: last_seq > seq")) {
jset->last_seq = jset->seq; jset->last_seq = jset->seq;
return JOURNAL_ENTRY_BAD; return JOURNAL_ENTRY_BAD;
} }
return 0;
fsck_err: fsck_err:
return ret; return ret;
} }
......
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