bcachefs: Improve journal entry validate code
authorKent Overstreet <kent.overstreet@gmail.com>
Fri, 13 Nov 2020 19:39:43 +0000 (14:39 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:08:47 +0000 (17:08 -0400)
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: Kent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/journal_io.c

index 80c833f..e976aa8 100644 (file)
@@ -431,46 +431,45 @@ static int jset_validate(struct bch_fs *c,
                        "%s sector %llu seq %llu: unknown journal entry version %u",
                        ca->name, sector, le64_to_cpu(jset->seq),
                        version)) {
-               /* XXX: note we might have missing journal entries */
-               return JOURNAL_ENTRY_BAD;
+               /* don't try to continue: */
+               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,
                        "%s sector %llu seq %llu: journal entry too big (%zu bytes)",
                        ca->name, sector, le64_to_cpu(jset->seq), bytes)) {
-               /* XXX: note we might have missing journal entries */
-               return JOURNAL_ENTRY_BAD;
+               ret = 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,
                        "%s sector %llu seq %llu: journal entry with unknown csum type %llu",
                        ca->name, sector, le64_to_cpu(jset->seq),
-                       JSET_CSUM_TYPE(jset)))
-               return JOURNAL_ENTRY_BAD;
+                       JSET_CSUM_TYPE(jset))) {
+               ret = JOURNAL_ENTRY_BAD;
+               goto bad_csum_type;
+       }
 
        csum = csum_vstruct(c, JSET_CSUM_TYPE(jset), journal_nonce(jset), jset);
        if (journal_entry_err_on(bch2_crc_cmp(csum, jset->csum), c,
                                 "%s sector %llu seq %llu: journal checksum bad",
-                                ca->name, sector, le64_to_cpu(jset->seq))) {
-               /* XXX: retry IO, when we start retrying checksum errors */
-               /* XXX: note we might have missing journal entries */
-               return JOURNAL_ENTRY_BAD;
-       }
+                                ca->name, sector, le64_to_cpu(jset->seq)))
+               ret = JOURNAL_ENTRY_BAD;
 
        bch2_encrypt(c, JSET_CSUM_TYPE(jset), journal_nonce(jset),
                     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,
                                 "invalid journal entry: last_seq > seq")) {
                jset->last_seq = jset->seq;
                return JOURNAL_ENTRY_BAD;
        }
-
-       return 0;
 fsck_err:
        return ret;
 }