]> www.infradead.org Git - linux.git/commitdiff
bcachefs: Plumb bkey_validate_context to journal_entry_validate
authorKent Overstreet <kent.overstreet@linux.dev>
Sun, 8 Dec 2024 02:36:15 +0000 (21:36 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sat, 21 Dec 2024 06:36:22 +0000 (01:36 -0500)
This lets us print the exact location in the journal if it was found in
the journal, or correctly print if it was found in the superblock.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/bkey_types.h
fs/bcachefs/btree_trans_commit.c
fs/bcachefs/error.c
fs/bcachefs/extents.c
fs/bcachefs/journal_io.c
fs/bcachefs/journal_io.h
fs/bcachefs/sb-clean.c

index 2af6279b02a9ad8f3a0e28e6b05f21790d1c79ed..b4f328f9853c6073463fc4c34cc5299c91e83683 100644 (file)
@@ -213,16 +213,16 @@ BCH_BKEY_TYPES();
 enum bch_validate_flags {
        BCH_VALIDATE_write              = BIT(0),
        BCH_VALIDATE_commit             = BIT(1),
-       BCH_VALIDATE_journal            = BIT(2),
-       BCH_VALIDATE_silent             = BIT(3),
+       BCH_VALIDATE_silent             = BIT(2),
 };
 
 #define BKEY_VALIDATE_CONTEXTS()       \
        x(unknown)                      \
-       x(commit)                       \
+       x(superblock)                   \
        x(journal)                      \
        x(btree_root)                   \
-       x(btree_node)
+       x(btree_node)                   \
+       x(commit)
 
 struct bkey_validate_context {
        enum {
@@ -230,10 +230,12 @@ struct bkey_validate_context {
        BKEY_VALIDATE_CONTEXTS()
 #undef x
        }                       from:8;
+       enum bch_validate_flags flags:8;
        u8                      level;
        enum btree_id           btree;
        bool                    root:1;
-       enum bch_validate_flags flags:8;
+       unsigned                journal_offset;
+       u64                     journal_seq;
 };
 
 #endif /* _BCACHEFS_BKEY_TYPES_H */
index 78d72c26083d9aa58b226630997e1e592b04d22e..9011cc3f719013374710795c4328200c7b6bb1c8 100644 (file)
@@ -719,38 +719,17 @@ bch2_trans_commit_write_locked(struct btree_trans *trans, unsigned flags,
                        goto fatal_err;
        }
 
-       trans_for_each_update(trans, i) {
-               enum bch_validate_flags invalid_flags = 0;
-
-               if (!(flags & BCH_TRANS_COMMIT_no_journal_res))
-                       invalid_flags |= BCH_VALIDATE_write|BCH_VALIDATE_commit;
-
-               ret = bch2_bkey_validate(c, bkey_i_to_s_c(i->k),
-                                        (struct bkey_validate_context) {
-                                               .from   = BKEY_VALIDATE_commit,
-                                               .level  = i->level,
-                                               .btree  = i->btree_id,
-                                               .flags  = invalid_flags,
-                                        });
-               if (unlikely(ret)){
-                       bch2_trans_inconsistent(trans, "invalid bkey on insert from %s -> %ps\n",
-                                               trans->fn, (void *) i->ip_allocated);
-                       goto fatal_err;
-               }
-               btree_insert_entry_checks(trans, i);
-       }
+       struct bkey_validate_context validate_context = { .from = BKEY_VALIDATE_commit };
+
+       if (!(flags & BCH_TRANS_COMMIT_no_journal_res))
+               validate_context.flags = BCH_VALIDATE_write|BCH_VALIDATE_commit;
 
        for (struct jset_entry *i = trans->journal_entries;
             i != (void *) ((u64 *) trans->journal_entries + trans->journal_entries_u64s);
             i = vstruct_next(i)) {
-               enum bch_validate_flags invalid_flags = 0;
-
-               if (!(flags & BCH_TRANS_COMMIT_no_journal_res))
-                       invalid_flags |= BCH_VALIDATE_write|BCH_VALIDATE_commit;
-
                ret = bch2_journal_entry_validate(c, NULL, i,
                                                  bcachefs_metadata_version_current,
-                                                 CPU_BIG_ENDIAN, invalid_flags);
+                                                 CPU_BIG_ENDIAN, validate_context);
                if (unlikely(ret)) {
                        bch2_trans_inconsistent(trans, "invalid journal entry on insert from %s\n",
                                                trans->fn);
@@ -758,6 +737,19 @@ bch2_trans_commit_write_locked(struct btree_trans *trans, unsigned flags,
                }
        }
 
+       trans_for_each_update(trans, i) {
+               validate_context.level  = i->level;
+               validate_context.btree  = i->btree_id;
+
+               ret = bch2_bkey_validate(c, bkey_i_to_s_c(i->k), validate_context);
+               if (unlikely(ret)){
+                       bch2_trans_inconsistent(trans, "invalid bkey on insert from %s -> %ps\n",
+                                               trans->fn, (void *) i->ip_allocated);
+                       goto fatal_err;
+               }
+               btree_insert_entry_checks(trans, i);
+       }
+
        if (likely(!(flags & BCH_TRANS_COMMIT_no_journal_res))) {
                struct journal *j = &c->journal;
                struct jset_entry *entry;
index 9e34374960f3adb34fab3d33f2e7fe568d512259..038da6a61f6b553e3fdd2c45381d3947f889e9b1 100644 (file)
@@ -486,9 +486,14 @@ int __bch2_bkey_fsck_err(struct bch_fs *c,
                fsck_flags |= fsck_flags_extra[err];
 
        struct printbuf buf = PRINTBUF;
-
-       prt_printf(&buf, "invalid bkey in %s btree=",
+       prt_printf(&buf, "invalid bkey in %s",
                   bch2_bkey_validate_contexts[from.from]);
+
+       if (from.from == BKEY_VALIDATE_journal)
+               prt_printf(&buf, " journal seq=%llu offset=%u",
+                          from.journal_seq, from.journal_offset);
+
+       prt_str(&buf, " btree=");
        bch2_btree_id_to_text(&buf, from.btree);
        prt_printf(&buf, " level=%u: ", from.level);
 
index 2fc9ace5533c332030638769d1e848bb951711e9..05d5f71a7ca9f6423f8f12162ae568ca2c150037 100644 (file)
@@ -1238,6 +1238,12 @@ static int extent_ptr_validate(struct bch_fs *c,
 {
        int ret = 0;
 
+       struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k);
+       bkey_for_each_ptr(ptrs, ptr2)
+               bkey_fsck_err_on(ptr != ptr2 && ptr->dev == ptr2->dev,
+                                c, ptr_to_duplicate_device,
+                                "multiple pointers to same device (%u)", ptr->dev);
+
        /* bad pointers are repaired by check_fix_ptrs(): */
        rcu_read_lock();
        struct bch_dev *ca = bch2_dev_rcu_noerror(c, ptr->dev);
@@ -1252,13 +1258,6 @@ static int extent_ptr_validate(struct bch_fs *c,
        unsigned bucket_size    = ca->mi.bucket_size;
        rcu_read_unlock();
 
-       struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k);
-       bkey_for_each_ptr(ptrs, ptr2)
-               bkey_fsck_err_on(ptr != ptr2 && ptr->dev == ptr2->dev,
-                                c, ptr_to_duplicate_device,
-                                "multiple pointers to same device (%u)", ptr->dev);
-
-
        bkey_fsck_err_on(bucket >= nbuckets,
                         c, ptr_after_last_bucket,
                         "pointer past last bucket (%llu > %llu)", bucket, nbuckets);
index 2f4daa8bd498b0f04b436e3adcd62452c11242b6..7f2efe85a805292da39fcf06724c9d4aea27551c 100644 (file)
@@ -301,7 +301,7 @@ static void journal_entry_err_msg(struct printbuf *out,
        journal_entry_err_msg(&_buf, version, jset, entry);             \
        prt_printf(&_buf, msg, ##__VA_ARGS__);                          \
                                                                        \
-       switch (flags & BCH_VALIDATE_write) {                           \
+       switch (from.flags & BCH_VALIDATE_write) {                      \
        case READ:                                                      \
                mustfix_fsck_err(c, _err, "%s", _buf.buf);              \
                break;                                                  \
@@ -390,15 +390,12 @@ static int journal_entry_btree_keys_validate(struct bch_fs *c,
                                struct jset *jset,
                                struct jset_entry *entry,
                                unsigned version, int big_endian,
-                               enum bch_validate_flags flags)
+                               struct bkey_validate_context from)
 {
        struct bkey_i *k = entry->start;
-       struct bkey_validate_context from = {
-               .from   = BKEY_VALIDATE_journal,
-               .level  = entry->level,
-               .btree  = entry->btree_id,
-               .flags  = flags|BCH_VALIDATE_journal,
-       };
+
+       from.level      = entry->level;
+       from.btree      = entry->btree_id;
 
        while (k != vstruct_last(entry)) {
                int ret = journal_validate_key(c, jset, entry, k, from, version, big_endian);
@@ -435,11 +432,15 @@ static int journal_entry_btree_root_validate(struct bch_fs *c,
                                struct jset *jset,
                                struct jset_entry *entry,
                                unsigned version, int big_endian,
-                               enum bch_validate_flags flags)
+                               struct bkey_validate_context from)
 {
        struct bkey_i *k = entry->start;
        int ret = 0;
 
+       from.root       = true;
+       from.level      = entry->level + 1;
+       from.btree      = entry->btree_id;
+
        if (journal_entry_err_on(!entry->u64s ||
                                 le16_to_cpu(entry->u64s) != k->k.u64s,
                                 c, version, jset, entry,
@@ -456,13 +457,6 @@ static int journal_entry_btree_root_validate(struct bch_fs *c,
                return 0;
        }
 
-       struct bkey_validate_context from = {
-               .from   = BKEY_VALIDATE_journal,
-               .level  = entry->level + 1,
-               .btree  = entry->btree_id,
-               .root   = true,
-               .flags  = flags,
-       };
        ret = journal_validate_key(c, jset, entry, k, from, version, big_endian);
        if (ret == FSCK_DELETED_KEY)
                ret = 0;
@@ -480,7 +474,7 @@ static int journal_entry_prio_ptrs_validate(struct bch_fs *c,
                                struct jset *jset,
                                struct jset_entry *entry,
                                unsigned version, int big_endian,
-                               enum bch_validate_flags flags)
+                               struct bkey_validate_context from)
 {
        /* obsolete, don't care: */
        return 0;
@@ -495,7 +489,7 @@ static int journal_entry_blacklist_validate(struct bch_fs *c,
                                struct jset *jset,
                                struct jset_entry *entry,
                                unsigned version, int big_endian,
-                               enum bch_validate_flags flags)
+                               struct bkey_validate_context from)
 {
        int ret = 0;
 
@@ -522,7 +516,7 @@ static int journal_entry_blacklist_v2_validate(struct bch_fs *c,
                                struct jset *jset,
                                struct jset_entry *entry,
                                unsigned version, int big_endian,
-                               enum bch_validate_flags flags)
+                               struct bkey_validate_context from)
 {
        struct jset_entry_blacklist_v2 *bl_entry;
        int ret = 0;
@@ -564,7 +558,7 @@ static int journal_entry_usage_validate(struct bch_fs *c,
                                struct jset *jset,
                                struct jset_entry *entry,
                                unsigned version, int big_endian,
-                               enum bch_validate_flags flags)
+                               struct bkey_validate_context from)
 {
        struct jset_entry_usage *u =
                container_of(entry, struct jset_entry_usage, entry);
@@ -598,7 +592,7 @@ static int journal_entry_data_usage_validate(struct bch_fs *c,
                                struct jset *jset,
                                struct jset_entry *entry,
                                unsigned version, int big_endian,
-                               enum bch_validate_flags flags)
+                               struct bkey_validate_context from)
 {
        struct jset_entry_data_usage *u =
                container_of(entry, struct jset_entry_data_usage, entry);
@@ -642,7 +636,7 @@ static int journal_entry_clock_validate(struct bch_fs *c,
                                struct jset *jset,
                                struct jset_entry *entry,
                                unsigned version, int big_endian,
-                               enum bch_validate_flags flags)
+                               struct bkey_validate_context from)
 {
        struct jset_entry_clock *clock =
                container_of(entry, struct jset_entry_clock, entry);
@@ -682,7 +676,7 @@ static int journal_entry_dev_usage_validate(struct bch_fs *c,
                                struct jset *jset,
                                struct jset_entry *entry,
                                unsigned version, int big_endian,
-                               enum bch_validate_flags flags)
+                               struct bkey_validate_context from)
 {
        struct jset_entry_dev_usage *u =
                container_of(entry, struct jset_entry_dev_usage, entry);
@@ -739,7 +733,7 @@ static int journal_entry_log_validate(struct bch_fs *c,
                                struct jset *jset,
                                struct jset_entry *entry,
                                unsigned version, int big_endian,
-                               enum bch_validate_flags flags)
+                               struct bkey_validate_context from)
 {
        return 0;
 }
@@ -756,10 +750,11 @@ static int journal_entry_overwrite_validate(struct bch_fs *c,
                                struct jset *jset,
                                struct jset_entry *entry,
                                unsigned version, int big_endian,
-                               enum bch_validate_flags flags)
+                               struct bkey_validate_context from)
 {
+       from.flags = 0;
        return journal_entry_btree_keys_validate(c, jset, entry,
-                               version, big_endian, READ);
+                               version, big_endian, from);
 }
 
 static void journal_entry_overwrite_to_text(struct printbuf *out, struct bch_fs *c,
@@ -772,10 +767,10 @@ static int journal_entry_write_buffer_keys_validate(struct bch_fs *c,
                                struct jset *jset,
                                struct jset_entry *entry,
                                unsigned version, int big_endian,
-                               enum bch_validate_flags flags)
+                               struct bkey_validate_context from)
 {
        return journal_entry_btree_keys_validate(c, jset, entry,
-                               version, big_endian, READ);
+                               version, big_endian, from);
 }
 
 static void journal_entry_write_buffer_keys_to_text(struct printbuf *out, struct bch_fs *c,
@@ -788,7 +783,7 @@ static int journal_entry_datetime_validate(struct bch_fs *c,
                                struct jset *jset,
                                struct jset_entry *entry,
                                unsigned version, int big_endian,
-                               enum bch_validate_flags flags)
+                               struct bkey_validate_context from)
 {
        unsigned bytes = vstruct_bytes(entry);
        unsigned expected = 16;
@@ -818,7 +813,7 @@ static void journal_entry_datetime_to_text(struct printbuf *out, struct bch_fs *
 struct jset_entry_ops {
        int (*validate)(struct bch_fs *, struct jset *,
                        struct jset_entry *, unsigned, int,
-                       enum bch_validate_flags);
+                       struct bkey_validate_context);
        void (*to_text)(struct printbuf *, struct bch_fs *, struct jset_entry *);
 };
 
@@ -836,11 +831,11 @@ int bch2_journal_entry_validate(struct bch_fs *c,
                                struct jset *jset,
                                struct jset_entry *entry,
                                unsigned version, int big_endian,
-                               enum bch_validate_flags flags)
+                               struct bkey_validate_context from)
 {
        return entry->type < BCH_JSET_ENTRY_NR
                ? bch2_jset_entry_ops[entry->type].validate(c, jset, entry,
-                               version, big_endian, flags)
+                               version, big_endian, from)
                : 0;
 }
 
@@ -858,10 +853,18 @@ void bch2_journal_entry_to_text(struct printbuf *out, struct bch_fs *c,
 static int jset_validate_entries(struct bch_fs *c, struct jset *jset,
                                 enum bch_validate_flags flags)
 {
+       struct bkey_validate_context from = {
+               .flags          = flags,
+               .from           = BKEY_VALIDATE_journal,
+               .journal_seq    = le64_to_cpu(jset->seq),
+       };
+
        unsigned version = le32_to_cpu(jset->version);
        int ret = 0;
 
        vstruct_for_each(jset, entry) {
+               from.journal_offset = (u64 *) entry - jset->_data;
+
                if (journal_entry_err_on(vstruct_next(entry) > vstruct_last(jset),
                                c, version, jset, entry,
                                journal_entry_past_jset_end,
@@ -870,8 +873,8 @@ static int jset_validate_entries(struct bch_fs *c, struct jset *jset,
                        break;
                }
 
-               ret = bch2_journal_entry_validate(c, jset, entry,
-                                       version, JSET_BIG_ENDIAN(jset), flags);
+               ret = bch2_journal_entry_validate(c, jset, entry, version,
+                                                 JSET_BIG_ENDIAN(jset), from);
                if (ret)
                        break;
        }
@@ -884,13 +887,17 @@ static int jset_validate(struct bch_fs *c,
                         struct jset *jset, u64 sector,
                         enum bch_validate_flags flags)
 {
-       unsigned version;
+       struct bkey_validate_context from = {
+               .flags          = flags,
+               .from           = BKEY_VALIDATE_journal,
+               .journal_seq    = le64_to_cpu(jset->seq),
+       };
        int ret = 0;
 
        if (le64_to_cpu(jset->magic) != jset_magic(c))
                return JOURNAL_ENTRY_NONE;
 
-       version = le32_to_cpu(jset->version);
+       unsigned version = le32_to_cpu(jset->version);
        if (journal_entry_err_on(!bch2_version_compatible(version),
                        c, version, jset, NULL,
                        jset_unsupported_version,
@@ -935,15 +942,16 @@ static int jset_validate_early(struct bch_fs *c,
                         unsigned bucket_sectors_left,
                         unsigned sectors_read)
 {
-       size_t bytes = vstruct_bytes(jset);
-       unsigned version;
-       enum bch_validate_flags flags = BCH_VALIDATE_journal;
+       struct bkey_validate_context from = {
+               .from           = BKEY_VALIDATE_journal,
+               .journal_seq    = le64_to_cpu(jset->seq),
+       };
        int ret = 0;
 
        if (le64_to_cpu(jset->magic) != jset_magic(c))
                return JOURNAL_ENTRY_NONE;
 
-       version = le32_to_cpu(jset->version);
+       unsigned version = le32_to_cpu(jset->version);
        if (journal_entry_err_on(!bch2_version_compatible(version),
                        c, version, jset, NULL,
                        jset_unsupported_version,
@@ -956,6 +964,7 @@ static int jset_validate_early(struct bch_fs *c,
                return -EINVAL;
        }
 
+       size_t bytes = vstruct_bytes(jset);
        if (bytes > (sectors_read << 9) &&
            sectors_read < bucket_sectors_left)
                return JOURNAL_ENTRY_REREAD;
@@ -1240,8 +1249,6 @@ int bch2_journal_read(struct bch_fs *c,
         * those entries will be blacklisted:
         */
        genradix_for_each_reverse(&c->journal_entries, radix_iter, _i) {
-               enum bch_validate_flags flags = BCH_VALIDATE_journal;
-
                i = *_i;
 
                if (journal_replay_ignore(i))
@@ -1261,6 +1268,10 @@ int bch2_journal_read(struct bch_fs *c,
                        continue;
                }
 
+               struct bkey_validate_context from = {
+                       .from           = BKEY_VALIDATE_journal,
+                       .journal_seq    = le64_to_cpu(i->j.seq),
+               };
                if (journal_entry_err_on(le64_to_cpu(i->j.last_seq) > le64_to_cpu(i->j.seq),
                                         c, le32_to_cpu(i->j.version), &i->j, NULL,
                                         jset_last_seq_newer_than_seq,
index 2ca9cde30ea8da0fdabbc2fa084be8df140ba3fa..12b39fcb4424bcbb950bf05ea404f28147c24c75 100644 (file)
@@ -63,7 +63,7 @@ static inline struct jset_entry *__jset_entry_type_next(struct jset *jset,
 
 int bch2_journal_entry_validate(struct bch_fs *, struct jset *,
                                struct jset_entry *, unsigned, int,
-                               enum bch_validate_flags);
+                               struct bkey_validate_context);
 void bch2_journal_entry_to_text(struct printbuf *, struct bch_fs *,
                                struct jset_entry *);
 
index 0052752818045b0c7ed6f02956f912010461fb2a..59c8770e4a0e94b63bb0f931b33f188fc420ae57 100644 (file)
 int bch2_sb_clean_validate_late(struct bch_fs *c, struct bch_sb_field_clean *clean,
                                int write)
 {
+       struct bkey_validate_context from = {
+               .flags          = write,
+               .from           = BKEY_VALIDATE_superblock,
+       };
        struct jset_entry *entry;
        int ret;
 
@@ -40,7 +44,7 @@ int bch2_sb_clean_validate_late(struct bch_fs *c, struct bch_sb_field_clean *cle
                ret = bch2_journal_entry_validate(c, NULL, entry,
                                                  le16_to_cpu(c->disk_sb.sb->version),
                                                  BCH_SB_BIG_ENDIAN(c->disk_sb.sb),
-                                                 write);
+                                                 from);
                if (ret)
                        return ret;
        }