bcachefs: Fix btree node scan when unknown btree IDs are present
authorKent Overstreet <kent.overstreet@linux.dev>
Mon, 25 Nov 2024 03:57:01 +0000 (22:57 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sat, 21 Dec 2024 06:36:19 +0000 (01:36 -0500)
btree_root entries for unknown btree IDs are created during recovery,
before reading those btree roots.

But btree_node_scan may find btree nodes with unknown btree IDs when we
haven't seen roots for those btrees.

Reported-by: syzbot+1f202d4da221ec6ebf8e@syzkaller.appspotmail.com
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/btree_cache.c
fs/bcachefs/btree_cache.h

index 36dfa6a48aa6236eed4d07e36cca8ef60fff586e..1f06e24e53fced858c73ab06f40ecbbab0001409 100644 (file)
@@ -1406,9 +1406,14 @@ void bch2_btree_id_level_to_text(struct printbuf *out, enum btree_id btree, unsi
 void bch2_btree_pos_to_text(struct printbuf *out, struct bch_fs *c, const struct btree *b)
 {
        bch2_btree_id_to_text(out, b->c.btree_id);
-       prt_printf(out, " level %u/%u\n  ",
-                  b->c.level,
-                  bch2_btree_id_root(c, b->c.btree_id)->level);
+       prt_printf(out, " level %u/", b->c.level);
+       struct btree_root *r = bch2_btree_id_root(c, b->c.btree_id);
+       if (r)
+               prt_printf(out, "%u", r->level);
+       else
+               prt_printf(out, "(unknown)");
+       prt_printf(out, "\n  ");
+
        bch2_bkey_val_to_text(out, c, bkey_i_to_s_c(&b->key));
 }
 
index 6cfacacb6769367ec5840d52a92e2726ddad7813..dcc34fe4996d5d118c66391d5a6236df814bdc08 100644 (file)
@@ -128,14 +128,19 @@ static inline struct btree_root *bch2_btree_id_root(struct bch_fs *c, unsigned i
        } else {
                unsigned idx = id - BTREE_ID_NR;
 
-               EBUG_ON(idx >= c->btree_roots_extra.nr);
+               /* This can happen when we're called from btree_node_scan */
+               if (idx >= c->btree_roots_extra.nr)
+                       return NULL;
+
                return &c->btree_roots_extra.data[idx];
        }
 }
 
 static inline struct btree *btree_node_root(struct bch_fs *c, struct btree *b)
 {
-       return bch2_btree_id_root(c, b->c.btree_id)->b;
+       struct btree_root *r = bch2_btree_id_root(c, b->c.btree_id);
+
+       return r ? r->b : NULL;
 }
 
 const char *bch2_btree_id_str(enum btree_id);  /* avoid */