]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bcachefs: Fix journal entry repair code
authorKent Overstreet <kent.overstreet@gmail.com>
Mon, 16 Nov 2020 17:22:30 +0000 (12:22 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:08:47 +0000 (17:08 -0400)
When we detect bad keys in the journal that have to be dropped, the flow
control was wrong - we ended up not checking the next key in that entry.
Oops.

Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/journal_io.c

index a6fb4fb207a28fae2f9ef02119bf92c71c100f31..354d57a3cd59503803c479ba4ffb876988c830f3 100644 (file)
@@ -160,6 +160,8 @@ static void journal_entry_null_range(void *start, void *end)
 #define journal_entry_err_on(cond, c, msg, ...)                                \
        ((cond) ? journal_entry_err(c, msg, ##__VA_ARGS__) : false)
 
+#define FSCK_DELETED_KEY       5
+
 static int journal_validate_key(struct bch_fs *c, struct jset *jset,
                                struct jset_entry *entry,
                                unsigned level, enum btree_id btree_id,
@@ -172,33 +174,42 @@ static int journal_validate_key(struct bch_fs *c, struct jset *jset,
        int ret = 0;
 
        if (journal_entry_err_on(!k->k.u64s, c,
-                       "invalid %s in journal entry %llu offset %zi: k->u64s 0",
+                       "invalid %s in jset %llu offset %zi/%u entry offset %zi/%u: k->u64s 0",
                        type, le64_to_cpu(jset->seq),
-                       (u64 *) entry - jset->_data)) {
+                       (u64 *) entry - jset->_data,
+                       le32_to_cpu(jset->u64s),
+                       (u64 *) k - entry->_data,
+                       le16_to_cpu(entry->u64s))) {
                entry->u64s = cpu_to_le16((u64 *) k - entry->_data);
                journal_entry_null_range(vstruct_next(entry), next);
-               return 0;
+               return FSCK_DELETED_KEY;
        }
 
        if (journal_entry_err_on((void *) bkey_next(k) >
                                (void *) vstruct_next(entry), c,
-                       "invalid %s in journal entry %llu offset %zi: extends past end of journal entry",
+                       "invalid %s in jset %llu offset %zi/%u entry offset %zi/%u: extends past end of journal entry",
                        type, le64_to_cpu(jset->seq),
-                       (u64 *) entry - jset->_data)) {
+                       (u64 *) entry - jset->_data,
+                       le32_to_cpu(jset->u64s),
+                       (u64 *) k - entry->_data,
+                       le16_to_cpu(entry->u64s))) {
                entry->u64s = cpu_to_le16((u64 *) k - entry->_data);
                journal_entry_null_range(vstruct_next(entry), next);
-               return 0;
+               return FSCK_DELETED_KEY;
        }
 
        if (journal_entry_err_on(k->k.format != KEY_FORMAT_CURRENT, c,
-                       "invalid %s in journal entry %llu offset %zi: bad format %u",
+                       "invalid %s in jset %llu offset %zi/%u entry offset %zi/%u: bad format %u",
                        type, le64_to_cpu(jset->seq),
                        (u64 *) entry - jset->_data,
+                       le32_to_cpu(jset->u64s),
+                       (u64 *) k - entry->_data,
+                       le16_to_cpu(entry->u64s),
                        k->k.format)) {
-               le16_add_cpu(&entry->u64s, -k->k.u64s);
+               le16_add_cpu(&entry->u64s, -((u16) k->k.u64s));
                memmove(k, bkey_next(k), next - (void *) bkey_next(k));
                journal_entry_null_range(vstruct_next(entry), next);
-               return 0;
+               return FSCK_DELETED_KEY;
        }
 
        if (!write)
@@ -212,15 +223,18 @@ static int journal_validate_key(struct bch_fs *c, struct jset *jset,
                char buf[160];
 
                bch2_bkey_val_to_text(&PBUF(buf), c, bkey_i_to_s_c(k));
-               mustfix_fsck_err(c, "invalid %s in journal entry %llu offset %zi: %s\n%s",
+               mustfix_fsck_err(c, "invalid %s in jset %llu offset %zi/%u entry offset %zi/%u: %s\n%s",
                                 type, le64_to_cpu(jset->seq),
                                 (u64 *) entry - jset->_data,
+                                le32_to_cpu(jset->u64s),
+                                (u64 *) k - entry->_data,
+                                le16_to_cpu(entry->u64s),
                                 invalid, buf);
 
-               le16_add_cpu(&entry->u64s, -k->k.u64s);
+               le16_add_cpu(&entry->u64s, -((u16) k->k.u64s));
                memmove(k, bkey_next(k), next - (void *) bkey_next(k));
                journal_entry_null_range(vstruct_next(entry), next);
-               return 0;
+               return FSCK_DELETED_KEY;
        }
 
        if (write)
@@ -236,15 +250,17 @@ static int journal_entry_validate_btree_keys(struct bch_fs *c,
                                             struct jset_entry *entry,
                                             int write)
 {
-       struct bkey_i *k;
+       struct bkey_i *k = entry->start;
 
-       vstruct_for_each(entry, k) {
+       while (k != vstruct_last(entry)) {
                int ret = journal_validate_key(c, jset, entry,
                                               entry->level,
                                               entry->btree_id,
                                               k, "key", write);
-               if (ret)
-                       return ret;
+               if (ret == FSCK_DELETED_KEY)
+                       continue;
+
+               k = bkey_next(k);
        }
 
        return 0;