bcachefs: Don't BUG_ON() btree topology error
authorKent Overstreet <kent.overstreet@gmail.com>
Fri, 23 Apr 2021 20:05:49 +0000 (16:05 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:09:01 +0000 (17:09 -0400)
This replaces an assertion in the btree merge path with a
bch2_inconsistent_error() - fsck will fix it.

Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/btree_cache.c
fs/bcachefs/btree_update_interior.c

index cc703c2602cf274e09f7b281f3809e6bc3f1442b..5a5eb99baefa11d98a8ac4891eb01825c73bb65f 100644 (file)
@@ -686,6 +686,41 @@ static int lock_node_check_fn(struct six_lock *lock, void *p)
        return b->hash_val == btree_ptr_hash_val(k) ? 0 : -1;
 }
 
+static noinline void btree_bad_header(struct bch_fs *c, struct btree *b)
+{
+       char buf1[100], buf2[100], buf3[100], buf4[100];
+
+       if (!test_bit(BCH_FS_INITIAL_GC_DONE, &c->flags))
+               return;
+
+       bch2_bpos_to_text(&PBUF(buf1), b->key.k.type == KEY_TYPE_btree_ptr_v2
+               ? bkey_i_to_btree_ptr_v2(&b->key)->v.min_key
+               : POS_MIN);
+       bch2_bpos_to_text(&PBUF(buf2), b->data->min_key);
+
+       bch2_bpos_to_text(&PBUF(buf3), b->key.k.p);
+       bch2_bpos_to_text(&PBUF(buf4), b->data->max_key);
+       bch2_fs_inconsistent(c, "btree node header doesn't match ptr\n"
+                            "btree: ptr %u header %llu\n"
+                            "level: ptr %u header %llu\n"
+                            "min ptr %s node header %s\n"
+                            "max ptr %s node header %s",
+                            b->c.btree_id,     BTREE_NODE_ID(b->data),
+                            b->c.level,        BTREE_NODE_LEVEL(b->data),
+                            buf1, buf2, buf3, buf4);
+}
+
+static inline void btree_check_header(struct bch_fs *c, struct btree *b)
+{
+       if (b->c.btree_id != BTREE_NODE_ID(b->data) ||
+           b->c.level != BTREE_NODE_LEVEL(b->data) ||
+           bpos_cmp(b->data->max_key, b->key.k.p) ||
+           (b->key.k.type == KEY_TYPE_btree_ptr_v2 &&
+            bpos_cmp(b->data->min_key,
+                     bkey_i_to_btree_ptr_v2(&b->key)->v.min_key)))
+               btree_bad_header(c, b);
+}
+
 /**
  * bch_btree_node_get - find a btree node in the cache and lock it, reading it
  * in from disk if necessary.
@@ -803,10 +838,7 @@ lock_node:
 
        EBUG_ON(b->c.btree_id != iter->btree_id);
        EBUG_ON(BTREE_NODE_LEVEL(b->data) != level);
-       EBUG_ON(bpos_cmp(b->data->max_key, k->k.p));
-       EBUG_ON(b->key.k.type == KEY_TYPE_btree_ptr_v2 &&
-               bpos_cmp(b->data->min_key,
-                        bkey_i_to_btree_ptr_v2(&b->key)->v.min_key));
+       btree_check_header(c, b);
 
        return b;
 }
@@ -886,10 +918,7 @@ lock_node:
 
        EBUG_ON(b->c.btree_id != btree_id);
        EBUG_ON(BTREE_NODE_LEVEL(b->data) != level);
-       EBUG_ON(bpos_cmp(b->data->max_key, k->k.p));
-       EBUG_ON(b->key.k.type == KEY_TYPE_btree_ptr_v2 &&
-               bpos_cmp(b->data->min_key,
-                        bkey_i_to_btree_ptr_v2(&b->key)->v.min_key));
+       btree_check_header(c, b);
 out:
        bch2_btree_cache_cannibalize_unlock(c);
        return b;
index dabd1a3e3aa3af0157032af29797955113cd34a7..986b396ba177c06e16ab442448c343ec78d460b1 100644 (file)
@@ -1606,7 +1606,19 @@ retry:
                next = m;
        }
 
-       BUG_ON(bkey_cmp(bpos_successor(prev->data->max_key), next->data->min_key));
+       if (bkey_cmp(bpos_successor(prev->data->max_key), next->data->min_key)) {
+               char buf1[100], buf2[100];
+
+               bch2_bpos_to_text(&PBUF(buf1), prev->data->max_key);
+               bch2_bpos_to_text(&PBUF(buf2), next->data->min_key);
+               bch2_fs_inconsistent(c,
+                                    "btree topology error in btree merge:\n"
+                                    "prev ends at   %s\n"
+                                    "next starts at %s\n",
+                                    buf1, buf2);
+               ret = -EIO;
+               goto err;
+       }
 
        bch2_bkey_format_init(&new_s);
        bch2_bkey_format_add_pos(&new_s, prev->data->min_key);