summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/md/bcache/bset.c169
-rw-r--r--drivers/md/bcache/bset.h45
-rw-r--r--drivers/md/bcache/btree_update.c1
-rw-r--r--drivers/md/bcache/debug.c5
4 files changed, 122 insertions, 98 deletions
diff --git a/drivers/md/bcache/bset.c b/drivers/md/bcache/bset.c
index 04e3151933ba..ff5ea3c62974 100644
--- a/drivers/md/bcache/bset.c
+++ b/drivers/md/bcache/bset.c
@@ -324,93 +324,84 @@ static inline size_t btree_keys_cachelines(struct btree_keys *b)
return btree_keys_bytes(b) / BSET_CACHELINE;
}
-/* Space required for the auxiliary search trees */
-static inline size_t bset_tree_bytes(struct btree_keys *b)
+static inline size_t btree_aux_data_bytes(struct btree_keys *b)
{
- return btree_keys_cachelines(b) * sizeof(struct bkey_float);
+ return btree_keys_cachelines(b) * sizeof(struct bkey_float) * 2;
}
-/* Space required for the prev pointers */
-static inline size_t bset_prev_bytes(struct btree_keys *b)
+static void bset_aux_tree_verify(struct btree_keys *b)
{
- return btree_keys_cachelines(b) * sizeof(u8);
-}
+#ifdef CONFIG_BCACHE_DEBUG
+ struct bset_tree *t;
+ void *prev;
-/* Memory allocation */
+ for_each_bset(b, t) {
+ if (!t->tree)
+ continue;
-void bch_btree_keys_free(struct btree_keys *b)
-{
- struct bset_tree *t = b->set;
+ BUG_ON(t != b->set && (!t[-1].tree || !t[-1].prev));
- vfree(b->unpack_fn);
+ prev = t == b->set
+ ? b->aux_data + b->unpack_fn_len
+ : t[-1].prev + t[-1].size;
- if (bset_prev_bytes(b) < PAGE_SIZE)
- kfree(t->prev);
- else
- free_pages((unsigned long) t->prev,
- get_order(bset_prev_bytes(b)));
+ BUG_ON((void *) t->tree < (void *) prev);
- if (bset_tree_bytes(b) < PAGE_SIZE)
- kfree(t->tree);
- else
- free_pages((unsigned long) t->tree,
- get_order(bset_tree_bytes(b)));
+ switch (bset_aux_tree_type(t)) {
+ case BSET_NO_AUX_TREE:
+ BUG_ON((void *) t->prev != (void *) t->tree);
+ break;
+ case BSET_RO_AUX_TREE:
+ BUG_ON((void *) t->prev < (void *) (t->tree + t->size));
+ break;
+ case BSET_RW_AUX_TREE:
+ BUG_ON((void *) t->prev != (void *) t->tree);
+ BUG_ON(t != bset_tree_last(b));
+ break;
+ }
- t->prev = NULL;
- t->tree = NULL;
+ BUG_ON((void *) (t->prev + t->size) >
+ b->aux_data + btree_aux_data_bytes(b));
+ }
+#endif
}
-EXPORT_SYMBOL(bch_btree_keys_free);
-
-int bch_btree_keys_alloc(struct btree_keys *b, unsigned page_order, gfp_t gfp)
-{
- struct bset_tree *t = b->set;
-
- BUG_ON(t->tree || t->prev);
-
- b->page_order = page_order;
- t->tree = bset_tree_bytes(b) < PAGE_SIZE
- ? kmalloc(bset_tree_bytes(b), gfp)
- : (void *) __get_free_pages(gfp, get_order(bset_tree_bytes(b)));
- if (!t->tree)
- goto err;
+/* Memory allocation */
- t->prev = bset_prev_bytes(b) < PAGE_SIZE
- ? kmalloc(bset_prev_bytes(b), gfp)
- : (void *) __get_free_pages(gfp, get_order(bset_prev_bytes(b)));
- if (!t->prev)
- goto err;
+void bch_btree_keys_free(struct btree_keys *b)
+{
+ vfree(b->aux_data);
+ b->aux_data = NULL;
+}
- b->unpack_fn = vmalloc_exec(200);
- if (!b->unpack_fn)
- goto err;
+int bch_btree_keys_alloc(struct btree_keys *b, unsigned page_order, gfp_t gfp)
+{
+ b->page_order = page_order;
+ b->aux_data = __vmalloc(btree_aux_data_bytes(b), gfp,
+ PAGE_KERNEL_EXEC);
+ if (!b->aux_data)
+ return -ENOMEM;
return 0;
-err:
- bch_btree_keys_free(b);
- return -ENOMEM;
}
-EXPORT_SYMBOL(bch_btree_keys_alloc);
void bch_btree_keys_init(struct btree_keys *b, bool *expensive_debug_checks)
{
- struct bkey_format_state s;
unsigned i;
- bch_bkey_format_init(&s);
- b->format = bch_bkey_format_done(&s);
-
b->nsets = 0;
memset(&b->nr, 0, sizeof(b->nr));
#ifdef CONFIG_BCACHE_DEBUG
b->expensive_debug_checks = expensive_debug_checks;
#endif
- for (i = 0; i < MAX_BSETS; i++)
+ for (i = 0; i < MAX_BSETS; i++) {
+ b->set[i].tree = NULL;
+ b->set[i].prev = NULL;
b->set[i].data = NULL;
+ }
bch_bset_set_no_aux_tree(b, b->set);
}
-EXPORT_SYMBOL(bch_btree_keys_init);
/* Binary tree stuff for auxiliary search trees */
@@ -755,10 +746,25 @@ static void make_bfloat(const struct btree_keys *b,
}
}
-/* Only valid for the last bset: */
-static unsigned bset_tree_capacity(struct btree_keys *b, struct bset_tree *t)
+/* bytes remaining - only valid for last bset: */
+static unsigned __bset_tree_capacity(struct btree_keys *b, struct bset_tree *t)
+{
+ bset_aux_tree_verify(b);
+
+ return b->aux_data + btree_aux_data_bytes(b) - (void *) t->tree;
+}
+
+static unsigned bset_ro_tree_capacity(struct btree_keys *b, struct bset_tree *t)
{
- return b->set->tree + btree_keys_cachelines(b) - t->tree;
+ return __bset_tree_capacity(b, t) /
+ (sizeof(struct bkey_float) + sizeof(u8));
+}
+
+static unsigned bset_rw_tree_capacity(struct btree_keys *b, struct bset_tree *t)
+{
+ EBUG_ON((void *) t->prev != (void *) t->tree);
+
+ return __bset_tree_capacity(b, t) / sizeof(u8);
}
static void bch_bset_lookup_table_add_entries(struct btree_keys *b,
@@ -767,13 +773,13 @@ static void bch_bset_lookup_table_add_entries(struct btree_keys *b,
struct bkey_packed *k;
BUG_ON(!bset_has_rw_aux_tree(t));
- BUG_ON(t->size > bset_tree_capacity(b, t));
+ BUG_ON(t->size > bset_rw_tree_capacity(b, t));
for (k = table_to_bkey(t, t->size - 1);
k != bset_bkey_last(t->data);
k = bkey_next(k))
while (bkey_to_cacheline(t, k) >= t->size) {
- if (t->size == bset_tree_capacity(b, t))
+ if (t->size == bset_rw_tree_capacity(b, t))
return;
t->prev[t->size] = bkey_to_cacheline_offset(t, t->size, k);
@@ -796,13 +802,17 @@ static void __build_ro_aux_tree(struct btree_keys *b, struct bset_tree *t)
unsigned j, cacheline = 1;
t->size = min(bkey_to_cacheline(t, bset_bkey_last(t->data)),
- bset_tree_capacity(b, t));
+ bset_ro_tree_capacity(b, t));
retry:
if (t->size < 2) {
- bch_bset_set_no_aux_tree(b, t);
+ t->size = 0;
+ t->extra = BSET_NO_AUX_TREE_VAL;
+ t->prev = (void *) (t->tree + t->size);
return;
}
+ t->prev = (void *) (t->tree + t->size);
+
t->extra = (t->size - rounddown_pow_of_two(t->size - 1)) << 1;
/* First we figure out where the first key in each cacheline is */
@@ -839,21 +849,25 @@ retry:
static void bset_alloc_tree(struct btree_keys *b, struct bset_tree *t)
{
struct bset_tree *i;
+ size_t used;
for (i = b->set; i != t; i++)
BUG_ON(bset_has_rw_aux_tree(i));
- if (t != b->set) {
- unsigned j = round_up(t[-1].size,
- 64 / sizeof(struct bkey_float));
+ bch_bset_set_no_aux_tree(b, t);
- t->tree = t[-1].tree + j;
- t->prev = t[-1].prev + j;
+ used = t == b->set
+ ? b->unpack_fn_len
+ : (void *) (t[-1].prev + t[-1].size) - b->aux_data;
- BUG_ON(t->tree > b->set->tree + btree_keys_cachelines(b));
- }
+ /* round up to next cacheline: */
+ used = round_up(used, 64);
+ BUG_ON(used > btree_aux_data_bytes(b));
- bch_bset_set_no_aux_tree(b, t);
+ t->tree = b->aux_data + used;
+ t->prev = b->aux_data + used;
+
+ bset_aux_tree_verify(b);
}
void bch_bset_build_aux_tree(struct btree_keys *b, struct bset_tree *t,
@@ -866,16 +880,15 @@ void bch_bset_build_aux_tree(struct btree_keys *b, struct bset_tree *t,
bset_alloc_tree(b, t);
- if (!bset_tree_capacity(b, t)) {
- bch_bset_set_no_aux_tree(b, t);
+ if (!__bset_tree_capacity(b, t))
return;
- }
if (writeable)
__build_rw_aux_tree(b, t);
else
__build_ro_aux_tree(b, t);
+ bset_aux_tree_verify(b);
}
void bch_bset_init_first(struct btree_keys *b, struct bset *i)
@@ -1048,7 +1061,7 @@ static void bch_bset_fix_lookup_table(struct btree_keys *b,
while (t->size > 1 &&
table_to_bkey(t, t->size - 1) >= bset_bkey_last(t->data))
t->size--;
- return;
+ goto verify;
}
/* Find first entry in the lookup table strictly greater than where: */
@@ -1080,7 +1093,7 @@ static void bch_bset_fix_lookup_table(struct btree_keys *b,
k = bkey_next(cacheline_to_bkey(t, j, new_offset));
if (k == bset_bkey_last(t->data)) {
t->size = j;
- return;
+ goto verify;
}
new_offset = __bkey_to_cacheline_offset(t, j, k);
@@ -1091,6 +1104,8 @@ static void bch_bset_fix_lookup_table(struct btree_keys *b,
}
bch_bset_lookup_table_add_entries(b, t);
+verify:
+ bset_aux_tree_verify(b);
}
static void bch_bset_verify_lookup_table(struct btree_keys *b,
@@ -1445,6 +1460,8 @@ void bch_btree_node_iter_init(struct btree_node_iter *iter,
BUG_ON(b->nsets > MAX_BSETS);
+ bset_aux_tree_verify(b);
+
switch (bkey_pack_pos_lossy(&p, search, b)) {
case BKEY_PACK_POS_EXACT:
packed_search = &p;
diff --git a/drivers/md/bcache/bset.h b/drivers/md/bcache/bset.h
index a73dedbc740b..b27ff4710419 100644
--- a/drivers/md/bcache/bset.h
+++ b/drivers/md/bcache/bset.h
@@ -229,10 +229,12 @@ struct btree_keys {
u8 nsets;
u8 page_order;
u8 nr_key_bits;
+ u8 unpack_fn_len;
struct btree_nr_keys nr;
struct bkey_format format;
+ void *aux_data;
/*
* Sets of sorted keys - the real btree node - plus a binary search tree
@@ -245,22 +247,8 @@ struct btree_keys {
#ifdef CONFIG_BCACHE_DEBUG
bool *expensive_debug_checks;
#endif
-
- compiled_unpack_fn unpack_fn;
};
-static inline void btree_node_set_format(struct btree_keys *b,
- struct bkey_format f)
-{
- int len;
-
- b->format = f;
- b->nr_key_bits = bkey_format_key_bits(&f);
-
- len = bch_compile_bkey_format(&b->format, b->unpack_fn);
- BUG_ON(len < 0 || len > 200);
-}
-
static inline struct bkey
bkey_unpack_key_format_checked(const struct btree_keys *b,
const struct bkey_packed *src)
@@ -268,12 +256,15 @@ bkey_unpack_key_format_checked(const struct btree_keys *b,
struct bkey dst;
#ifdef HAVE_BCACHE_COMPILED_UNPACK
- b->unpack_fn(&dst, src);
+ {
+ compiled_unpack_fn unpack_fn = b->aux_data;
+ unpack_fn(&dst, src);
- if (IS_ENABLED(CONFIG_BCACHE_DEBUG)) {
- struct bkey dst2 = __bkey_unpack_key(&b->format, src);
+ if (IS_ENABLED(CONFIG_BCACHE_DEBUG)) {
+ struct bkey dst2 = __bkey_unpack_key(&b->format, src);
- BUG_ON(memcmp(&dst, &dst2, sizeof(dst)));
+ BUG_ON(memcmp(&dst, &dst2, sizeof(dst)));
+ }
}
#else
dst = __bkey_unpack_key(&b->format, src);
@@ -351,10 +342,28 @@ static inline void bch_bset_set_no_aux_tree(struct btree_keys *b,
for (; t < b->set + ARRAY_SIZE(b->set); t++) {
t->size = 0;
t->extra = BSET_NO_AUX_TREE_VAL;
+ t->tree = NULL;
+ t->prev = NULL;
}
}
+static inline void btree_node_set_format(struct btree_keys *b,
+ struct bkey_format f)
+{
+ int len;
+
+ b->format = f;
+ b->nr_key_bits = bkey_format_key_bits(&f);
+
+ len = bch_compile_bkey_format(&b->format, b->aux_data);
+ BUG_ON(len < 0 || len > U8_MAX);
+
+ b->unpack_fn_len = len;
+
+ bch_bset_set_no_aux_tree(b, b->set);
+}
+
#define __set_bytes(_i, _u64s) (sizeof(*(_i)) + (_u64s) * sizeof(u64))
#define set_bytes(_i) __set_bytes(_i, (_i)->u64s)
diff --git a/drivers/md/bcache/btree_update.c b/drivers/md/bcache/btree_update.c
index c53e938515fb..944afe9558ac 100644
--- a/drivers/md/bcache/btree_update.c
+++ b/drivers/md/bcache/btree_update.c
@@ -469,6 +469,7 @@ static struct btree *__btree_root_alloc(struct cache_set *c, unsigned level,
b->key.k.p = POS_MAX;
btree_node_set_format(&b->keys, b->data->format);
+ bch_btree_build_aux_trees(b);
six_unlock_write(&b->lock);
diff --git a/drivers/md/bcache/debug.c b/drivers/md/bcache/debug.c
index fba0edb44965..18f8aaf26010 100644
--- a/drivers/md/bcache/debug.c
+++ b/drivers/md/bcache/debug.c
@@ -300,9 +300,6 @@ static int print_btree_node(struct dump_iter *i, struct btree *b)
{
const struct bkey_format *f = &b->keys.format;
struct bset_stats stats;
- u8 unpack_fn[200];
- int unpack_fn_len =
- bch_compile_bkey_format(&b->keys.format, unpack_fn);
memset(&stats, 0, sizeof(stats));
@@ -331,7 +328,7 @@ static int print_btree_node(struct dump_iter *i, struct btree *b)
f->bits_per_field[2],
f->bits_per_field[3],
f->bits_per_field[4],
- unpack_fn_len,
+ b->keys.unpack_fn_len,
b->keys.nr.live_u64s * sizeof(u64),
btree_bytes(i->c) - sizeof(struct btree_node),
b->keys.nr.live_u64s * 100 / btree_max_u64s(i->c),