#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;
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)
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);
}
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;
}
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;
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);
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);
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;
}
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);
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"