]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - libbcachefs/btree_cache.c
Update bcachefs sources to 18686af684 bcachefs: Inode backpointers
[bcachefs-tools-debian] / libbcachefs / btree_cache.c
index bebf9fb01fe1ff1cc3301a33ab0005d951623d70..8a4667ba6b189e41d39aea23edec58ebf3ad33a1 100644 (file)
@@ -7,18 +7,12 @@
 #include "btree_iter.h"
 #include "btree_locking.h"
 #include "debug.h"
+#include "error.h"
 
 #include <linux/prefetch.h>
 #include <linux/sched/mm.h>
 #include <trace/events/bcachefs.h>
 
-const char * const bch2_btree_ids[] = {
-#define x(kwd, val, name) name,
-       BCH_BTREE_IDS()
-#undef x
-       NULL
-};
-
 void bch2_recalc_btree_reserve(struct bch_fs *c)
 {
        unsigned i, reserve = 16;
@@ -152,6 +146,11 @@ int bch2_btree_node_hash_insert(struct btree_cache *bc, struct btree *b,
        b->c.level      = level;
        b->c.btree_id   = id;
 
+       if (level)
+               six_lock_pcpu_alloc(&b->c.lock);
+       else
+               six_lock_pcpu_free_rcu(&b->c.lock);
+
        mutex_lock(&bc->lock);
        ret = __bch2_btree_node_hash_insert(bc, b);
        if (!ret)
@@ -392,6 +391,7 @@ void bch2_fs_btree_cache_exit(struct bch_fs *c)
        while (!list_empty(&bc->freed)) {
                b = list_first_entry(&bc->freed, struct btree, list);
                list_del(&b->list);
+               six_lock_pcpu_free(&b->c.lock);
                kfree(b);
        }
 
@@ -812,9 +812,12 @@ lock_node:
                return ERR_PTR(-EIO);
        }
 
-       EBUG_ON(b->c.btree_id != iter->btree_id ||
-               BTREE_NODE_LEVEL(b->data) != level ||
-               bkey_cmp(b->data->max_key, k->k.p));
+       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));
 
        return b;
 }
@@ -822,7 +825,8 @@ lock_node:
 struct btree *bch2_btree_node_get_noiter(struct bch_fs *c,
                                         const struct bkey_i *k,
                                         enum btree_id btree_id,
-                                        unsigned level)
+                                        unsigned level,
+                                        bool nofill)
 {
        struct btree_cache *bc = &c->btree_cache;
        struct btree *b;
@@ -837,6 +841,9 @@ struct btree *bch2_btree_node_get_noiter(struct bch_fs *c,
 retry:
        b = btree_cache_find(bc, k);
        if (unlikely(!b)) {
+               if (nofill)
+                       goto out;
+
                b = bch2_btree_node_fill(c, NULL, k, btree_id,
                                         level, SIX_LOCK_read, true);
 
@@ -844,8 +851,12 @@ retry:
                if (!b)
                        goto retry;
 
+               if (IS_ERR(b) &&
+                   !bch2_btree_cache_cannibalize_lock(c, NULL))
+                       goto retry;
+
                if (IS_ERR(b))
-                       return b;
+                       goto out;
        } else {
 lock_node:
                ret = six_lock_read(&b->c.lock, lock_node_check_fn, (void *) k);
@@ -880,13 +891,18 @@ lock_node:
 
        if (unlikely(btree_node_read_error(b))) {
                six_unlock_read(&b->c.lock);
-               return ERR_PTR(-EIO);
+               b = ERR_PTR(-EIO);
+               goto out;
        }
 
-       EBUG_ON(b->c.btree_id != btree_id ||
-               BTREE_NODE_LEVEL(b->data) != level ||
-               bkey_cmp(b->data->max_key, k->k.p));
-
+       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));
+out:
+       bch2_btree_cache_cannibalize_unlock(c);
        return b;
 }
 
@@ -995,8 +1011,22 @@ out:
                if (sib != btree_prev_sib)
                        swap(n1, n2);
 
-               BUG_ON(bkey_cmp(bkey_successor(n1->key.k.p),
-                               n2->data->min_key));
+               if (bpos_cmp(bpos_successor(n1->key.k.p),
+                            n2->data->min_key)) {
+                       char buf1[200], buf2[200];
+
+                       bch2_bkey_val_to_text(&PBUF(buf1), c, bkey_i_to_s_c(&n1->key));
+                       bch2_bkey_val_to_text(&PBUF(buf2), c, bkey_i_to_s_c(&n2->key));
+
+                       bch2_fs_inconsistent(c, "btree topology error at btree %s level %u:\n"
+                                            "prev: %s\n"
+                                            "next: %s\n",
+                                            bch2_btree_ids[iter->btree_id], level,
+                                            buf1, buf2);
+
+                       six_unlock_intent(&ret->c.lock);
+                       ret = NULL;
+               }
        }
 
        bch2_btree_trans_verify_locks(trans);
@@ -1033,15 +1063,14 @@ void bch2_btree_node_to_text(struct printbuf *out, struct bch_fs *c,
 
        bch2_btree_keys_stats(b, &stats);
 
-       pr_buf(out,
-              "l %u %llu:%llu - %llu:%llu:\n"
-              "    ptrs: ",
-              b->c.level,
-              b->data->min_key.inode,
-              b->data->min_key.offset,
-              b->data->max_key.inode,
-              b->data->max_key.offset);
+       pr_buf(out, "l %u ", b->c.level);
+       bch2_bpos_to_text(out, b->data->min_key);
+       pr_buf(out, " - ");
+       bch2_bpos_to_text(out, b->data->max_key);
+       pr_buf(out, ":\n"
+              "    ptrs: ");
        bch2_val_to_text(out, c, bkey_i_to_s_c(&b->key));
+
        pr_buf(out, "\n"
               "    format: u64s %u fields %u %u %u %u %u\n"
               "    unpack fn len: %u\n"