bcachefs: bch2_check_fix_ptrs() can now repair btree roots

This is straightforward enough: check_fix_ptrs() currently only runs
before we go RW, so updating the btree root pointer in c->btree_roots
suffices - it'll be written out in the first journal write we do.

For that, do_bch2_trans_commit_to_journal_replay() now handles
JSET_ENTRY_btree_root entries.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
Kent Overstreet 2025-05-27 20:51:00 -04:00
parent a7c9add482
commit 66b7c51ceb
2 changed files with 54 additions and 22 deletions

View File

@ -966,14 +966,27 @@ do_bch2_trans_commit_to_journal_replay(struct btree_trans *trans)
for (struct jset_entry *i = btree_trans_journal_entries_start(trans);
i != btree_trans_journal_entries_top(trans);
i = vstruct_next(i))
i = vstruct_next(i)) {
if (i->type == BCH_JSET_ENTRY_btree_keys ||
i->type == BCH_JSET_ENTRY_write_buffer_keys) {
int ret = bch2_journal_key_insert(c, i->btree_id, i->level, i->start);
if (ret)
return ret;
jset_entry_for_each_key(i, k) {
int ret = bch2_journal_key_insert(c, i->btree_id, i->level, k);
if (ret)
return ret;
}
}
if (i->type == BCH_JSET_ENTRY_btree_root) {
guard(mutex)(&c->btree_root_lock);
struct btree_root *r = bch2_btree_id_root(c, i->btree_id);
bkey_copy(&r->key, i->start);
r->level = i->level;
r->alive = true;
}
}
for (struct bkey_i *i = btree_trans_subbuf_base(trans, &trans->accounting);
i != btree_trans_subbuf_top(trans, &trans->accounting);
i = bkey_next(i)) {

View File

@ -270,6 +270,9 @@ int bch2_check_fix_ptrs(struct btree_trans *trans,
struct printbuf buf = PRINTBUF;
int ret = 0;
/* We don't yet do btree key updates correctly for when we're RW */
BUG_ON(test_bit(BCH_FS_rw, &c->flags));
bkey_for_each_ptr_decode(k.k, ptrs_c, p, entry_c) {
ret = bch2_check_fix_ptr(trans, k, p, entry_c, &do_update);
if (ret)
@ -277,12 +280,6 @@ int bch2_check_fix_ptrs(struct btree_trans *trans,
}
if (do_update) {
if (flags & BTREE_TRIGGER_is_root) {
bch_err(c, "cannot update btree roots yet");
ret = -EINVAL;
goto err;
}
struct bkey_i *new = bch2_bkey_make_mut_noupdate(trans, k);
ret = PTR_ERR_OR_ZERO(new);
if (ret)
@ -370,19 +367,41 @@ int bch2_check_fix_ptrs(struct btree_trans *trans,
bch_info(c, "new key %s", buf.buf);
}
struct btree_iter iter;
bch2_trans_node_iter_init(trans, &iter, btree, new->k.p, 0, level,
BTREE_ITER_intent|BTREE_ITER_all_snapshots);
ret = bch2_btree_iter_traverse(trans, &iter) ?:
bch2_trans_update(trans, &iter, new,
BTREE_UPDATE_internal_snapshot_node|
BTREE_TRIGGER_norun);
bch2_trans_iter_exit(trans, &iter);
if (ret)
goto err;
if (!(flags & BTREE_TRIGGER_is_root)) {
struct btree_iter iter;
bch2_trans_node_iter_init(trans, &iter, btree, new->k.p, 0, level,
BTREE_ITER_intent|BTREE_ITER_all_snapshots);
ret = bch2_btree_iter_traverse(trans, &iter) ?:
bch2_trans_update(trans, &iter, new,
BTREE_UPDATE_internal_snapshot_node|
BTREE_TRIGGER_norun);
bch2_trans_iter_exit(trans, &iter);
if (ret)
goto err;
if (level)
bch2_btree_node_update_key_early(trans, btree, level - 1, k, new);
if (level)
bch2_btree_node_update_key_early(trans, btree, level - 1, k, new);
} else {
struct jset_entry *e = bch2_trans_jset_entry_alloc(trans,
jset_u64s(new->k.u64s));
ret = PTR_ERR_OR_ZERO(e);
if (ret)
goto err;
journal_entry_set(e,
BCH_JSET_ENTRY_btree_root,
btree, level - 1,
new, new->k.u64s);
/*
* no locking, we're single threaded and not rw yet, see
* the big assertino above that we repeat here:
*/
BUG_ON(test_bit(BCH_FS_rw, &c->flags));
struct btree *b = bch2_btree_id_root(c, btree)->b;
bkey_copy(&b->key, new);
}
}
err:
printbuf_exit(&buf);