bcachefs: bch2_check_fix_ptrs() can now repair btree roots
authorKent Overstreet <kent.overstreet@linux.dev>
Wed, 28 May 2025 00:51:00 +0000 (20:51 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Fri, 30 May 2025 05:21:13 +0000 (01:21 -0400)
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>
fs/bcachefs/btree_trans_commit.c
fs/bcachefs/buckets.c

index 1c03c965d836b0fae971835fb3ec90cd0af10fd8..f2d1edc9163cb4c585c3d5df13df2ec771a6fdbf 100644 (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)) {
index b9e92bd55e1c2d2084800e897cbffc12b048a240..1adf6792ef97060013fc842358a838c12938a6a6 100644 (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 @@ found:
                        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);