bcachefs: Fix btree for nonexistent tree depth
authorKent Overstreet <kent.overstreet@linux.dev>
Thu, 3 Jul 2025 19:53:51 +0000 (15:53 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Fri, 4 Jul 2025 19:47:13 +0000 (15:47 -0400)
The fix for when we should increase tree depth in journal replay was
entirely bogus.

We should only increase the tree depth in journal replay when recovery
from btree node scan, and then only for keys found by btree node scan.

This needs additional work - we should be shooting down existing
interior node pointers when recovery from scan, they shouldn't be
showing up here.

Fixes: b47a82ff4772 ("bcachefs: Only run 'increase_depth' for keys from btree node csan")
Cc: Alan Huang <mmpgouride@gmail.com>
Reported-by: syzbot+8deb6ff4415db67a9f18@syzkaller.appspotmail.com
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/recovery.c

index d0b7e3a36a5420032a5d1fd3c7e6e845d2a63ec5..c94debb12d2feeb869f917fbe98969b841e8c25a 100644 (file)
@@ -273,24 +273,35 @@ static int bch2_journal_replay_key(struct btree_trans *trans,
                goto out;
 
        struct btree_path *path = btree_iter_path(trans, &iter);
-       if (unlikely(!btree_path_node(path, k->level) &&
-                    !k->allocated)) {
+       if (unlikely(!btree_path_node(path, k->level))) {
                struct bch_fs *c = trans->c;
 
+               CLASS(printbuf, buf)();
+               prt_str(&buf, "btree=");
+               bch2_btree_id_to_text(&buf, k->btree_id);
+               prt_printf(&buf, " level=%u ", k->level);
+               bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(k->k));
+
                if (!(c->recovery.passes_complete & (BIT_ULL(BCH_RECOVERY_PASS_scan_for_btree_nodes)|
                                                     BIT_ULL(BCH_RECOVERY_PASS_check_topology)))) {
-                       bch_err(c, "have key in journal replay for btree depth that does not exist, confused");
+                       bch_err(c, "have key in journal replay for btree depth that does not exist, confused\n%s",
+                               buf.buf);
                        ret = -EINVAL;
                }
-#if 0
+
+               if (!k->allocated) {
+                       bch_notice(c, "dropping key in journal replay for depth that does not exist because we're recovering from scan\n%s",
+                                  buf.buf);
+                       k->overwritten = true;
+                       goto out;
+               }
+
                bch2_trans_iter_exit(trans, &iter);
                bch2_trans_node_iter_init(trans, &iter, k->btree_id, k->k->k.p,
                                          BTREE_MAX_DEPTH, 0, iter_flags);
                ret =   bch2_btree_iter_traverse(trans, &iter) ?:
                        bch2_btree_increase_depth(trans, iter.path, 0) ?:
                        -BCH_ERR_transaction_restart_nested;
-#endif
-               k->overwritten = true;
                goto out;
        }