bcachefs: Also log overwrites in journal
authorKent Overstreet <kent.overstreet@gmail.com>
Sun, 5 Jun 2022 19:32:57 +0000 (15:32 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:09:33 +0000 (17:09 -0400)
Lately we've been doing a lot of debugging by looking at the journal to
see what was changed, and by what code path. This patch adds a new
journal entry type for recording overwrites, so that we don't have to
search backwards through the journal to see what was being overwritten
in order to work out what the triggers were supposed to be doing.

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

index d77a45041ff0751eb83a1efda13108416b0bcb8c..079ad93ab34e9b39641d6893272d733ebea4b5f6 100644 (file)
@@ -1796,7 +1796,8 @@ static inline __u64 __bset_magic(struct bch_sb *sb)
        x(data_usage,           6)              \
        x(clock,                7)              \
        x(dev_usage,            8)              \
-       x(log,                  9)
+       x(log,                  9)              \
+       x(overwrite,            10)
 
 enum {
 #define x(f, nr)       BCH_JSET_ENTRY_##f      = nr,
index df2b21245d00160fb37a3fa99f8e1541396f2e03..eac601d6a397f318393c1aa4a840adc76f4bf9e7 100644 (file)
@@ -384,41 +384,6 @@ btree_key_can_insert_cached(struct btree_trans *trans,
        return -EINTR;
 }
 
-static inline void do_btree_insert_one(struct btree_trans *trans,
-                                      struct btree_insert_entry *i)
-{
-       struct bch_fs *c = trans->c;
-       struct journal *j = &c->journal;
-
-       EBUG_ON(trans->journal_res.ref !=
-               !(trans->flags & BTREE_INSERT_JOURNAL_REPLAY));
-
-       i->k->k.needs_whiteout = false;
-
-       if (!i->cached)
-               btree_insert_key_leaf(trans, i);
-       else if (!i->key_cache_already_flushed)
-               bch2_btree_insert_key_cached(trans, i->path, i->k);
-       else {
-               bch2_btree_key_cache_drop(trans, i->path);
-               return;
-       }
-
-       if (likely(!(trans->flags & BTREE_INSERT_JOURNAL_REPLAY)) &&
-           !(i->flags & BTREE_UPDATE_NOJOURNAL)) {
-               struct jset_entry *entry;
-
-               entry = bch2_journal_add_entry(j, &trans->journal_res,
-                                      BCH_JSET_ENTRY_btree_keys,
-                                      i->btree_id, i->level,
-                                      i->k->k.u64s);
-               bkey_copy(&entry->start[0], i->k);
-
-               if (trans->journal_seq)
-                       *trans->journal_seq = trans->journal_res.seq;
-       }
-}
-
 /* Triggers: */
 
 static int run_one_mem_trigger(struct btree_trans *trans,
@@ -729,8 +694,47 @@ bch2_trans_commit_write_locked(struct btree_trans *trans,
                        return ret;
        }
 
-       trans_for_each_update(trans, i)
-               do_btree_insert_one(trans, i);
+       if (likely(!(trans->flags & BTREE_INSERT_JOURNAL_REPLAY))) {
+               trans_for_each_update(trans, i) {
+                       struct journal *j = &c->journal;
+                       struct jset_entry *entry;
+
+                       if (i->key_cache_already_flushed)
+                               continue;
+
+                       if (i->flags & BTREE_UPDATE_NOJOURNAL)
+                               continue;
+
+                       if (trans->journal_transaction_names) {
+                               entry = bch2_journal_add_entry(j, &trans->journal_res,
+                                                      BCH_JSET_ENTRY_overwrite,
+                                                      i->btree_id, i->level,
+                                                      i->old_k.u64s);
+                               bkey_reassemble(&entry->start[0],
+                                               (struct bkey_s_c) { &i->old_k, i->old_v });
+                       }
+
+                       entry = bch2_journal_add_entry(j, &trans->journal_res,
+                                              BCH_JSET_ENTRY_btree_keys,
+                                              i->btree_id, i->level,
+                                              i->k->k.u64s);
+                       bkey_copy(&entry->start[0], i->k);
+               }
+
+               if (trans->journal_seq)
+                       *trans->journal_seq = trans->journal_res.seq;
+       }
+
+       trans_for_each_update(trans, i) {
+               i->k->k.needs_whiteout = false;
+
+               if (!i->cached)
+                       btree_insert_key_leaf(trans, i);
+               else if (!i->key_cache_already_flushed)
+                       bch2_btree_insert_key_cached(trans, i->path, i->k);
+               else
+                       bch2_btree_key_cache_drop(trans, i->path);
+       }
 
        return ret;
 }
@@ -1134,13 +1138,23 @@ int __bch2_trans_commit(struct btree_trans *trans)
 
                BUG_ON(!btree_node_intent_locked(i->path, i->level));
 
+               if (i->key_cache_already_flushed)
+                       continue;
+
+               /* we're going to journal the key being updated: */
                u64s = jset_u64s(i->k->k.u64s);
                if (i->cached &&
                    likely(!(trans->flags & BTREE_INSERT_JOURNAL_REPLAY)))
                        trans->journal_preres_u64s += u64s;
 
-               if (!(i->flags & BTREE_UPDATE_NOJOURNAL))
-                       trans->journal_u64s += u64s;
+               if (i->flags & BTREE_UPDATE_NOJOURNAL)
+                       continue;
+
+               trans->journal_u64s += u64s;
+
+               /* and we're also going to log the overwrite: */
+               if (trans->journal_transaction_names)
+                       trans->journal_u64s += jset_u64s(i->old_k.u64s);
        }
 
        if (trans->extra_journal_res) {
index 351d5d9d822513e3f8578b5fab5a198b5a205194..163b18340fa18d67ba9a958282353861455475ac 100644 (file)
@@ -212,7 +212,7 @@ static void journal_entry_null_range(void *start, void *end)
 static int journal_validate_key(struct bch_fs *c, const char *where,
                                struct jset_entry *entry,
                                unsigned level, enum btree_id btree_id,
-                               struct bkey_i *k, const char *type,
+                               struct bkey_i *k,
                                unsigned version, int big_endian, int write)
 {
        void *next = vstruct_next(entry);
@@ -220,8 +220,8 @@ static int journal_validate_key(struct bch_fs *c, const char *where,
        int ret = 0;
 
        if (journal_entry_err_on(!k->k.u64s, c,
-                       "invalid %s in %s entry offset %zi/%u: k->u64s 0",
-                       type, where,
+                       "invalid key in %s at %s offset %zi/%u: k->u64s 0",
+                       bch2_jset_entry_types[entry->type], where,
                        (u64 *) k - entry->_data,
                        le16_to_cpu(entry->u64s))) {
                entry->u64s = cpu_to_le16((u64 *) k - entry->_data);
@@ -231,8 +231,8 @@ static int journal_validate_key(struct bch_fs *c, const char *where,
 
        if (journal_entry_err_on((void *) bkey_next(k) >
                                (void *) vstruct_next(entry), c,
-                       "invalid %s in %s entry offset %zi/%u: extends past end of journal entry",
-                       type, where,
+                       "invalid key in %s at %s offset %zi/%u: extends past end of journal entry",
+                       bch2_jset_entry_types[entry->type], where,
                        (u64 *) k - entry->_data,
                        le16_to_cpu(entry->u64s))) {
                entry->u64s = cpu_to_le16((u64 *) k - entry->_data);
@@ -241,8 +241,8 @@ static int journal_validate_key(struct bch_fs *c, const char *where,
        }
 
        if (journal_entry_err_on(k->k.format != KEY_FORMAT_CURRENT, c,
-                       "invalid %s in %s entry offset %zi/%u: bad format %u",
-                       type, where,
+                       "invalid key in %s at %s offset %zi/%u: bad format %u",
+                       bch2_jset_entry_types[entry->type], where,
                        (u64 *) k - entry->_data,
                        le16_to_cpu(entry->u64s),
                        k->k.format)) {
@@ -259,8 +259,8 @@ static int journal_validate_key(struct bch_fs *c, const char *where,
        if (bch2_bkey_invalid(c, bkey_i_to_s_c(k),
                              __btree_node_type(level, btree_id), write, &buf)) {
                printbuf_reset(&buf);
-               pr_buf(&buf, "invalid %s in %s entry offset %zi/%u:",
-                      type, where,
+               pr_buf(&buf, "invalid key in %s at %s offset %zi/%u:",
+                      bch2_jset_entry_types[entry->type], where,
                       (u64 *) k - entry->_data,
                       le16_to_cpu(entry->u64s));
                pr_newline(&buf);
@@ -300,7 +300,7 @@ static int journal_entry_btree_keys_validate(struct bch_fs *c,
                int ret = journal_validate_key(c, where, entry,
                                               entry->level,
                                               entry->btree_id,
-                                              k, "key", version, big_endian, write);
+                                              k, version, big_endian, write);
                if (ret == FSCK_DELETED_KEY)
                        continue;
 
@@ -350,7 +350,7 @@ static int journal_entry_btree_root_validate(struct bch_fs *c,
        }
 
        return journal_validate_key(c, where, entry, 1, entry->btree_id, k,
-                                   "btree root", version, big_endian, write);
+                                   version, big_endian, write);
 fsck_err:
        return ret;
 }
@@ -612,6 +612,19 @@ static void journal_entry_log_to_text(struct printbuf *out, struct bch_fs *c,
        pr_buf(out, "%.*s", bytes, l->d);
 }
 
+static int journal_entry_overwrite_validate(struct bch_fs *c, const char *where,
+                                     struct jset_entry *entry,
+                                     unsigned version, int big_endian, int write)
+{
+       return journal_entry_btree_keys_validate(c, where, entry, version, big_endian, write);
+}
+
+static void journal_entry_overwrite_to_text(struct printbuf *out, struct bch_fs *c,
+                                           struct jset_entry *entry)
+{
+       journal_entry_btree_keys_to_text(out, c, entry);
+}
+
 struct jset_entry_ops {
        int (*validate)(struct bch_fs *, const char *,
                        struct jset_entry *, unsigned, int, int);