bcachefs: Also log overwrites in journal

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>
This commit is contained in:
Kent Overstreet 2022-06-05 15:32:57 -04:00 committed by Kent Overstreet
parent 43ddf44834
commit cb685ce72c
3 changed files with 79 additions and 51 deletions

View 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,

View 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) {

View 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);