summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2016-08-27 02:37:58 -0800
committerKent Overstreet <kent.overstreet@gmail.com>2016-08-27 02:37:58 -0800
commit0a9ad028970ba45acb365a559bfbd81c86918ec8 (patch)
tree468ba38777ddda0f2b296584197075a80dda701d
parent17b8d5efc11585f3eb87238237df78f61fefc4fe (diff)
bcache: rename async_split -> btree_interior_update
& refactoring
-rw-r--r--drivers/md/bcache/bcache.h9
-rw-r--r--drivers/md/bcache/btree_gc.c13
-rw-r--r--drivers/md/bcache/btree_types.h14
-rw-r--r--drivers/md/bcache/btree_update.c198
-rw-r--r--drivers/md/bcache/btree_update.h65
-rw-r--r--drivers/md/bcache/super.c13
6 files changed, 165 insertions, 147 deletions
diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h
index fca21a796c17..137c0d7a2e50 100644
--- a/drivers/md/bcache/bcache.h
+++ b/drivers/md/bcache/bcache.h
@@ -613,12 +613,9 @@ struct cache_set {
unsigned btree_reserve_cache_nr;
struct mutex btree_reserve_cache_lock;
- mempool_t btree_async_split_pool;
-
- struct list_head btree_node_pending_free;
- struct mutex btree_node_pending_free_lock;
-
- struct mutex async_split_lock;
+ mempool_t btree_interior_update_pool;
+ struct list_head btree_interior_update_list;
+ struct mutex btree_interior_update_lock;
struct workqueue_struct *wq;
diff --git a/drivers/md/bcache/btree_gc.c b/drivers/md/bcache/btree_gc.c
index 5dfa8e766717..486c47372458 100644
--- a/drivers/md/bcache/btree_gc.c
+++ b/drivers/md/bcache/btree_gc.c
@@ -280,12 +280,13 @@ static void bch_mark_metadata(struct cache_set *c)
static void bch_mark_pending_btree_node_frees(struct cache_set *c)
{
struct bucket_stats_cache_set stats = { 0 };
+ struct btree_interior_update *as;
struct pending_btree_node_free *d;
- mutex_lock(&c->btree_node_pending_free_lock);
+ mutex_lock(&c->btree_interior_update_lock);
gc_pos_set(c, gc_phase(GC_PHASE_PENDING_DELETE));
- list_for_each_entry(d, &c->btree_node_pending_free, list)
+ for_each_pending_btree_node_free(c, as, d)
if (d->index_update_done)
__bch_gc_mark_key(c, bkey_i_to_s_c(&d->key),
c->sb.btree_node_size, true,
@@ -295,7 +296,7 @@ static void bch_mark_pending_btree_node_frees(struct cache_set *c)
* cache_set_stats:
*/
- mutex_unlock(&c->btree_node_pending_free_lock);
+ mutex_unlock(&c->btree_interior_update_lock);
}
static void bch_mark_scan_keylists(struct cache_set *c)
@@ -450,7 +451,7 @@ static void bch_coalesce_nodes(struct btree *old_nodes[GC_MERGE_NODES],
unsigned i, nr_old_nodes, nr_new_nodes, u64s = 0;
unsigned blocks = btree_blocks(c) * 2 / 3;
struct btree *new_nodes[GC_MERGE_NODES];
- struct async_split *as;
+ struct btree_interior_update *as;
struct btree_reserve *res;
struct keylist keylist;
struct bkey_format_state format_state;
@@ -499,10 +500,10 @@ static void bch_coalesce_nodes(struct btree *old_nodes[GC_MERGE_NODES],
goto out;
}
- as = __bch_async_split_alloc(old_nodes, nr_old_nodes, iter);
+ as = __bch_btree_interior_update_alloc(old_nodes, nr_old_nodes, iter);
for (i = 0; i < nr_old_nodes; i++)
- bch_async_split_will_free_node(as, old_nodes[i]);
+ bch_btree_interior_update_will_free_node(as, old_nodes[i]);
/* Repack everything with @new_format and sort down to one bset */
for (i = 0; i < nr_old_nodes; i++)
diff --git a/drivers/md/bcache/btree_types.h b/drivers/md/bcache/btree_types.h
index 4734c0da89c8..5bce26ba3f95 100644
--- a/drivers/md/bcache/btree_types.h
+++ b/drivers/md/bcache/btree_types.h
@@ -14,7 +14,7 @@
struct cache_set;
struct open_bucket;
-struct async_split;
+struct btree_interior_update;
struct btree_write {
unsigned index;
@@ -25,7 +25,7 @@ struct btree_write {
struct btree_root {
struct btree *b;
- struct async_split *as;
+ struct btree_interior_update *as;
/* On disk root - see async splits: */
__BKEY_PADDED(key, BKEY_BTREE_PTR_VAL_U64s_MAX);
@@ -56,7 +56,8 @@ struct btree {
* node to point to them: we update the parent in memory immediately,
* but then we must wait until the children have been written out before
* the update to the parent can be written - this is a list of the
- * async_splits that are blocking this node from being written:
+ * btree_interior_updates that are blocking this node from being
+ * written:
*/
struct list_head write_blocked;
@@ -67,13 +68,6 @@ struct btree {
struct open_bucket *ob;
- /*
- * When a node is going to be freed while write_blocked nonzero, we have
- * to preserve the write ordering - this then points to the async_split
- * that's waiting on writes before making the new node visible:
- */
- struct async_split *as;
-
/* lru list */
struct list_head list;
diff --git a/drivers/md/bcache/btree_update.c b/drivers/md/bcache/btree_update.c
index 251d2f6e7d65..3fc2fcb6bd65 100644
--- a/drivers/md/bcache/btree_update.c
+++ b/drivers/md/bcache/btree_update.c
@@ -18,7 +18,7 @@
#include <linux/sort.h>
#include <trace/events/bcache.h>
-static void async_split_updated_root(struct async_split *,
+static void btree_interior_update_updated_root(struct btree_interior_update *,
struct btree *);
/* Calculate ideal packed bkey format for new btree nodes: */
@@ -74,38 +74,42 @@ bool bch_btree_node_format_fits(struct btree *b, struct bkey_format *new_f)
* @b is going to be freed, allocate a pending_btree_node_free in @as:
*/
void bch_btree_node_free_start(struct cache_set *c,
- struct async_split *as,
+ struct btree_interior_update *as,
struct btree *b)
{
struct pending_btree_node_free *d;
BUG_ON(as->nr_pending >= ARRAY_SIZE(as->pending));
- d = &as->pending[as->nr_pending++];
- d->index_update_done = false;
+ mutex_lock(&c->btree_interior_update_lock);
+
+ d = &as->pending[as->nr_pending++];
+ d->index_update_done = false;
+ d->seq = b->data->keys.seq;
+ d->btree_id = b->btree_id;
+ d->level = b->level;
bkey_copy(&d->key, &b->key);
- mutex_lock(&c->btree_node_pending_free_lock);
- list_add(&d->list, &c->btree_node_pending_free);
- mutex_unlock(&c->btree_node_pending_free_lock);
+ mutex_unlock(&c->btree_interior_update_lock);
}
/*
* We're doing the index update that makes @b unreachable, update stuff to
* reflect that:
*
- * Must be called _before_ async_split_updated_root() or
- * async_split_updated_btree:
+ * Must be called _before_ btree_interior_update_updated_root() or
+ * btree_interior_update_updated_btree:
*/
static void bch_btree_node_free_index(struct cache_set *c, struct btree *b,
enum btree_id id, struct bkey_s_c k,
struct bucket_stats_cache_set *stats)
{
+ struct btree_interior_update *as;
struct pending_btree_node_free *d;
- mutex_lock(&c->btree_node_pending_free_lock);
+ mutex_lock(&c->btree_interior_update_lock);
- list_for_each_entry(d, &c->btree_node_pending_free, list)
+ for_each_pending_btree_node_free(c, as, d)
if (!bkey_cmp(k.k->p, d->key.k.p) &&
bkey_val_bytes(k.k) == bkey_val_bytes(&d->key.k) &&
!memcmp(k.v, &d->key.v, bkey_val_bytes(k.k)))
@@ -157,7 +161,7 @@ found:
*/
}
- mutex_unlock(&c->btree_node_pending_free_lock);
+ mutex_unlock(&c->btree_interior_update_lock);
}
static void __btree_node_free(struct cache_set *c, struct btree *b,
@@ -223,9 +227,6 @@ static void bch_btree_node_free_ondisk(struct cache_set *c,
BUG_ON(!pending->index_update_done);
- mutex_lock(&c->btree_node_pending_free_lock);
- list_del(&pending->list);
-
bch_mark_key(c, bkey_i_to_s_c(&pending->key),
-c->sb.btree_node_size, true,
gc_phase(GC_PHASE_PENDING_DELETE),
@@ -234,8 +235,6 @@ static void bch_btree_node_free_ondisk(struct cache_set *c,
* Don't apply stats - pending deletes aren't tracked in
* cache_set_stats:
*/
-
- mutex_unlock(&c->btree_node_pending_free_lock);
}
void btree_open_bucket_put(struct cache_set *c, struct btree *b)
@@ -369,6 +368,7 @@ static void bch_btree_set_root_inmem(struct cache_set *c, struct btree *b,
mutex_lock(&c->btree_root_lock);
btree_node_root(b) = b;
+ mutex_unlock(&c->btree_root_lock);
if (btree_reserve) {
/*
@@ -390,7 +390,6 @@ static void bch_btree_set_root_inmem(struct cache_set *c, struct btree *b,
bch_cache_set_stats_apply(c, &stats, &btree_reserve->disk_res,
gc_pos_btree_root(b->btree_id));
}
- mutex_unlock(&c->btree_root_lock);
bch_recalc_btree_reserve(c);
}
@@ -435,7 +434,7 @@ void bch_btree_set_root_initial(struct cache_set *c, struct btree *b,
* journal write.
*/
static void bch_btree_set_root(struct btree_iter *iter, struct btree *b,
- struct async_split *as,
+ struct btree_interior_update *as,
struct btree_reserve *btree_reserve)
{
struct cache_set *c = iter->c;
@@ -454,7 +453,7 @@ static void bch_btree_set_root(struct btree_iter *iter, struct btree *b,
bch_btree_set_root_inmem(c, b, btree_reserve);
- async_split_updated_root(as, b);
+ btree_interior_update_updated_root(as, b);
/*
* Unlock old root after new root is visible:
@@ -782,20 +781,20 @@ relock:
/* Asynchronous interior node update machinery */
-struct async_split *__bch_async_split_alloc(struct btree *nodes[],
- unsigned nr_nodes,
- struct btree_iter *iter)
+struct btree_interior_update *
+__bch_btree_interior_update_alloc(struct btree *nodes[], unsigned nr_nodes,
+ struct btree_iter *iter)
{
struct cache_set *c = iter->c;
- struct async_split *as;
+ struct btree_interior_update *as;
struct journal_entry_pin_list *pin_list = NULL;
unsigned i, pin_idx = UINT_MAX;
- as = mempool_alloc(&c->btree_async_split_pool, GFP_NOIO);
+ as = mempool_alloc(&c->btree_interior_update_pool, GFP_NOIO);
memset(as, 0, sizeof(*as));
closure_init(&as->cl, &c->cl);
as->c = c;
- as->mode = ASYNC_SPLIT_NO_UPDATE;
+ as->mode = BTREE_INTERIOR_NO_UPDATE;
bch_keylist_init(&as->parent_keys, as->inline_keys,
ARRAY_SIZE(as->inline_keys));
@@ -848,24 +847,30 @@ struct async_split *__bch_async_split_alloc(struct btree *nodes[],
six_unlock_write(&nodes[i]->lock);
}
+ mutex_lock(&c->btree_interior_update_lock);
+ list_add(&as->list, &c->btree_interior_update_list);
+ mutex_unlock(&c->btree_interior_update_lock);
+
return as;
}
-struct async_split *bch_async_split_alloc(struct btree *b, struct btree_iter *iter)
+struct btree_interior_update *
+bch_btree_interior_update_alloc(struct btree *b, struct btree_iter *iter)
{
- return __bch_async_split_alloc(&b, 1, iter);
+ return __bch_btree_interior_update_alloc(&b, 1, iter);
}
-static void async_split_free(struct closure *cl)
+static void btree_interior_update_free(struct closure *cl)
{
- struct async_split *as = container_of(cl, struct async_split, cl);
+ struct btree_interior_update *as = container_of(cl, struct btree_interior_update, cl);
- mempool_free(as, &as->c->btree_async_split_pool);
+ mempool_free(as, &as->c->btree_interior_update_pool);
}
-static void async_split_pointers_written(struct closure *cl)
+static void btree_interior_update_pointers_written(struct closure *cl)
{
- struct async_split *as = container_of(cl, struct async_split, cl);
+ struct btree_interior_update *as =
+ container_of(cl, struct btree_interior_update, cl);
struct cache_set *c = as->c;
unsigned i;
@@ -873,15 +878,25 @@ static void async_split_pointers_written(struct closure *cl)
journal_pin_drop(&c->journal, &as->journal);
+ mutex_lock(&c->btree_interior_update_lock);
+
for (i = 0; i < as->nr_pending; i++)
bch_btree_node_free_ondisk(c, &as->pending[i]);
+ as->nr_pending = 0;
+
+ mutex_unlock(&c->btree_interior_update_lock);
+
+ mutex_lock(&c->btree_interior_update_lock);
+ list_del(&as->list);
+ mutex_unlock(&c->btree_interior_update_lock);
- closure_return_with_destructor(cl, async_split_free);
+ closure_return_with_destructor(cl, btree_interior_update_free);
}
-static void async_split_nodes_written(struct closure *cl)
+static void btree_interior_update_nodes_written(struct closure *cl)
{
- struct async_split *as = container_of(cl, struct async_split, cl);
+ struct btree_interior_update *as =
+ container_of(cl, struct btree_interior_update, cl);
struct cache_set *c = as->c;
struct btree *b;
@@ -892,16 +907,16 @@ static void async_split_nodes_written(struct closure *cl)
*/
retry:
- mutex_lock(&c->async_split_lock);
+ mutex_lock(&c->btree_interior_update_lock);
switch (as->mode) {
- case ASYNC_SPLIT_NO_UPDATE:
+ case BTREE_INTERIOR_NO_UPDATE:
BUG();
- case ASYNC_SPLIT_UPDATING_BTREE:
+ case BTREE_INTERIOR_UPDATING_NODE:
/* The usual case: */
b = READ_ONCE(as->b);
if (!six_trylock_read(&b->lock)) {
- mutex_unlock(&c->async_split_lock);
+ mutex_unlock(&c->btree_interior_update_lock);
six_lock_read(&b->lock);
six_unlock_read(&b->lock);
goto retry;
@@ -910,34 +925,34 @@ retry:
BUG_ON(!btree_node_dirty(b));
closure_wait(&btree_current_write(b)->wait, cl);
- list_del(&as->list);
+ list_del(&as->write_blocked_list);
if (list_empty(&b->write_blocked))
__bch_btree_node_write(b, NULL, -1);
six_unlock_read(&b->lock);
break;
- case ASYNC_SPLIT_UPDATING_AS:
+ case BTREE_INTERIOR_UPDATING_AS:
/*
* The btree node we originally updated has been freed and is
* being rewritten - so we need to write anything here, we just
- * need to signal to that async_split that it's ok to make the
+ * need to signal to that btree_interior_update that it's ok to make the
* new replacement node visible:
*/
closure_put(&as->parent_as->cl);
/*
- * and then we have to wait on that async_split to finish:
+ * and then we have to wait on that btree_interior_update to finish:
*/
closure_wait(&as->parent_as->wait, cl);
break;
- case ASYNC_SPLIT_UPDATING_ROOT:
+ case BTREE_INTERIOR_UPDATING_ROOT:
/* b is the new btree root: */
b = READ_ONCE(as->b);
if (!six_trylock_read(&b->lock)) {
- mutex_unlock(&c->async_split_lock);
+ mutex_unlock(&c->btree_interior_update_lock);
six_lock_read(&b->lock);
six_unlock_read(&b->lock);
goto retry;
@@ -950,94 +965,95 @@ retry:
/*
* We don't have to wait anything anything here (before
- * async_split_pointers_written frees the old nodes ondisk) -
- * we've ensured that the very next journal write will have the
- * pointer to the new root, and before the allocator can reuse
- * the old nodes it'll have to do a journal commit:
+ * btree_interior_update_pointers_written frees the old nodes
+ * ondisk) - we've ensured that the very next journal write will
+ * have the pointer to the new root, and before the allocator
+ * can reuse the old nodes it'll have to do a journal commit:
*/
six_unlock_read(&b->lock);
}
- mutex_unlock(&c->async_split_lock);
+ mutex_unlock(&c->btree_interior_update_lock);
- continue_at(cl, async_split_pointers_written, system_wq);
+ continue_at(cl, btree_interior_update_pointers_written, system_wq);
}
/*
* We're updating @b with pointers to nodes that haven't finished writing yet:
* block @b from being written until @as completes
*/
-static void async_split_updated_btree(struct async_split *as,
- struct btree *b)
+static void btree_interior_update_updated_btree(struct btree_interior_update *as,
+ struct btree *b)
{
- mutex_lock(&as->c->async_split_lock);
+ mutex_lock(&as->c->btree_interior_update_lock);
- BUG_ON(as->mode != ASYNC_SPLIT_NO_UPDATE);
+ BUG_ON(as->mode != BTREE_INTERIOR_NO_UPDATE);
BUG_ON(!btree_node_dirty(b));
- as->mode = ASYNC_SPLIT_UPDATING_BTREE;
+ as->mode = BTREE_INTERIOR_UPDATING_NODE;
as->b = b;
- list_add(&as->list, &b->write_blocked);
+ list_add(&as->write_blocked_list, &b->write_blocked);
- mutex_unlock(&as->c->async_split_lock);
+ mutex_unlock(&as->c->btree_interior_update_lock);
- continue_at(&as->cl, async_split_nodes_written, system_freezable_wq);
+ continue_at(&as->cl, btree_interior_update_nodes_written, system_freezable_wq);
}
-static void async_split_updated_root(struct async_split *as,
- struct btree *b)
+static void btree_interior_update_updated_root(struct btree_interior_update *as,
+ struct btree *b)
{
struct btree_root *r = &as->c->btree_roots[b->btree_id];
/*
- * XXX: if there's an outstanding async_split updating the root, we
- * have to do the dance with the old one
+ * XXX: if there's an outstanding btree_interior_update updating the
+ * root, we have to do the dance with the old one
*/
- mutex_lock(&as->c->async_split_lock);
+ mutex_lock(&as->c->btree_interior_update_lock);
if (r->as) {
- BUG_ON(r->as->mode != ASYNC_SPLIT_UPDATING_ROOT);
+ BUG_ON(r->as->mode != BTREE_INTERIOR_UPDATING_ROOT);
r->as->b = NULL;
- r->as->mode = ASYNC_SPLIT_UPDATING_AS;
+ r->as->mode = BTREE_INTERIOR_UPDATING_AS;
r->as->parent_as = as;
closure_get(&as->cl);
}
- BUG_ON(as->mode != ASYNC_SPLIT_NO_UPDATE);
- as->mode = ASYNC_SPLIT_UPDATING_ROOT;
+ BUG_ON(as->mode != BTREE_INTERIOR_NO_UPDATE);
+ as->mode = BTREE_INTERIOR_UPDATING_ROOT;
as->b = b;
r->as = as;
- mutex_unlock(&as->c->async_split_lock);
+ mutex_unlock(&as->c->btree_interior_update_lock);
- continue_at(&as->cl, async_split_nodes_written, system_freezable_wq);
+ continue_at(&as->cl, btree_interior_update_nodes_written, system_freezable_wq);
}
/*
* @b is being split/rewritten: it may have pointers to not-yet-written btree
- * nodes and thus outstanding async_splits - redirect @b's async_splits to point
- * to this async_split:
+ * nodes and thus outstanding btree_interior_updates - redirect @b's
+ * btree_interior_updates to point to this btree_interior_update:
*/
-void bch_async_split_will_free_node(struct async_split *as, struct btree *b)
+void bch_btree_interior_update_will_free_node(struct btree_interior_update *as, struct btree *b)
{
- mutex_lock(&as->c->async_split_lock);
+ mutex_lock(&as->c->btree_interior_update_lock);
while (!list_empty(&b->write_blocked)) {
- struct async_split *p =
+ struct btree_interior_update *p =
list_first_entry(&b->write_blocked,
- struct async_split, list);
+ struct btree_interior_update,
+ write_blocked_list);
- BUG_ON(p->mode != ASYNC_SPLIT_UPDATING_BTREE);
+ BUG_ON(p->mode != BTREE_INTERIOR_UPDATING_NODE);
- p->mode = ASYNC_SPLIT_UPDATING_AS;
- list_del(&p->list);
+ p->mode = BTREE_INTERIOR_UPDATING_AS;
+ list_del(&p->write_blocked_list);
p->b = NULL;
p->parent_as = as;
closure_get(&as->cl);
}
- mutex_unlock(&as->c->async_split_lock);
+ mutex_unlock(&as->c->btree_interior_update_lock);
}
static void btree_node_interior_verify(struct btree *b)
@@ -1085,7 +1101,7 @@ static enum btree_insert_ret
bch_btree_insert_keys_interior(struct btree *b,
struct btree_iter *iter,
struct keylist *insert_keys,
- struct async_split *as,
+ struct btree_interior_update *as,
struct btree_reserve *res)
{
struct btree_node_iter node_iter;
@@ -1126,7 +1142,7 @@ bch_btree_insert_keys_interior(struct btree *b,
bch_keylist_dequeue(insert_keys);
}
- async_split_updated_btree(as, b);
+ btree_interior_update_updated_btree(as, b);
btree_node_unlock_write(b, iter);
@@ -1253,7 +1269,7 @@ static void btree_split_insert_keys(struct btree_iter *iter, struct btree *b,
static void btree_split(struct btree *b, struct btree_iter *iter,
struct keylist *insert_keys,
struct btree_reserve *reserve,
- struct async_split *as)
+ struct btree_interior_update *as)
{
struct cache_set *c = iter->c;
struct btree *parent = iter->nodes[b->level + 1];
@@ -1265,7 +1281,7 @@ static void btree_split(struct btree *b, struct btree_iter *iter,
BUG_ON(!parent && (b != btree_node_root(b)));
BUG_ON(!btree_node_intent_locked(iter, btree_node_root(b)->level));
- bch_async_split_will_free_node(as, b);
+ bch_btree_interior_update_will_free_node(as, b);
n1 = btree_node_alloc_replacement(c, b, reserve);
@@ -1412,7 +1428,7 @@ void bch_btree_insert_node(struct btree *b,
struct btree_iter *iter,
struct keylist *insert_keys,
struct btree_reserve *reserve,
- struct async_split *as)
+ struct btree_interior_update *as)
{
BUG_ON(!b->level);
BUG_ON(!reserve || !as);
@@ -1436,7 +1452,7 @@ static int bch_btree_split_leaf(struct btree_iter *iter, unsigned flags,
struct cache_set *c = iter->c;
struct btree *b = iter->nodes[0];
struct btree_reserve *reserve;
- struct async_split *as;
+ struct btree_interior_update *as;
int ret = 0;
/* Hack, because gc and splitting nodes doesn't mix yet: */
@@ -1463,7 +1479,7 @@ static int bch_btree_split_leaf(struct btree_iter *iter, unsigned flags,
goto out_get_locks;
}
- as = bch_async_split_alloc(b, iter);
+ as = bch_btree_interior_update_alloc(b, iter);
btree_split(b, iter, NULL, reserve, as);
bch_btree_reserve_put(c, reserve);
@@ -1928,7 +1944,7 @@ int bch_btree_node_rewrite(struct btree_iter *iter, struct btree *b,
struct cache_set *c = iter->c;
struct btree *n, *parent = iter->nodes[b->level + 1];
struct btree_reserve *reserve;
- struct async_split *as;
+ struct btree_interior_update *as;
iter->locks_want = U8_MAX;
if (!bch_btree_iter_upgrade(iter))
@@ -1940,9 +1956,9 @@ int bch_btree_node_rewrite(struct btree_iter *iter, struct btree *b,
return PTR_ERR(reserve);
}
- as = bch_async_split_alloc(b, iter);
+ as = bch_btree_interior_update_alloc(b, iter);
- bch_async_split_will_free_node(as, b);
+ bch_btree_interior_update_will_free_node(as, b);
n = btree_node_alloc_replacement(c, b, reserve);
six_unlock_write(&n->lock);
diff --git a/drivers/md/bcache/btree_update.h b/drivers/md/bcache/btree_update.h
index f5250dee951d..55b74b61c04b 100644
--- a/drivers/md/bcache/btree_update.h
+++ b/drivers/md/bcache/btree_update.h
@@ -14,13 +14,9 @@ struct btree;
struct btree_reserve {
struct disk_reservation disk_res;
unsigned nr;
- struct btree *b[];
+ struct btree *b[BTREE_RESERVE_MAX];
};
-#define BTREE_RESERVE_SIZE \
- (sizeof(struct btree_reserve) + \
- sizeof(struct btree *) * BTREE_RESERVE_MAX)
-
void __bch_btree_calc_format(struct bkey_format_state *, struct btree *);
bool bch_btree_node_format_fits(struct btree *, struct bkey_format *);
@@ -32,9 +28,11 @@ bool bch_btree_node_format_fits(struct btree *, struct bkey_format *);
* node(s) visible and frees the old hasn't completed yet)
*/
struct pending_btree_node_free {
- struct list_head list;
bool index_update_done;
+ __le64 seq;
+ enum btree_id btree_id;
+ unsigned level;
__BKEY_PADDED(key, BKEY_BTREE_PTR_VAL_U64s_MAX);
};
@@ -56,40 +54,49 @@ struct pending_btree_node_free {
* until then, the old nodes are still reachable on disk.
*
*/
-struct async_split {
+struct btree_interior_update {
struct closure cl;
-
struct cache_set *c;
+ struct list_head list;
+
+ /* What kind of update are we doing? */
enum {
- ASYNC_SPLIT_NO_UPDATE,
- ASYNC_SPLIT_UPDATING_BTREE,
- ASYNC_SPLIT_UPDATING_ROOT,
- ASYNC_SPLIT_UPDATING_AS,
+ BTREE_INTERIOR_NO_UPDATE,
+ BTREE_INTERIOR_UPDATING_NODE,
+ BTREE_INTERIOR_UPDATING_ROOT,
+ BTREE_INTERIOR_UPDATING_AS,
} mode;
/*
- * ASYNC_SPLIT_UPDATING_BTREE:
- * @b - node we're blocking from being written
- * @list - corresponds to @b->write_blocked
+ * BTREE_INTERIOR_UPDATING_NODE:
+ * The update that made the new nodes visible was a regular update to an
+ * existing interior node - @b. We can't write out the update to @b
+ * until the new nodes we created are finished writing, so we block @b
+ * from writing by putting this btree_interior update on the
+ * @b->write_blocked list with @write_blocked_list:
*/
struct btree *b;
- struct list_head list;
+ struct list_head write_blocked_list;
/*
- * ASYNC_SPLIT_UPDATING_AS: btree node we updated was freed, so now
- * we're now blocking another async_split
- * @parent_as - async_split that's waiting on our nodes to finish
+ * BTREE_INTERIOR_UPDATING_AS: btree node we updated was freed, so now
+ * we're now blocking another btree_interior_update
+ * @parent_as - btree_interior_update that's waiting on our nodes to finish
* writing, before it can make new nodes visible on disk
- * @wait - list of child async_splits that are waiting on this
- * async_split to make all the new nodes visible before they can free
+ * @wait - list of child btree_interior_updates that are waiting on this
+ * btree_interior_update to make all the new nodes visible before they can free
* their old btree nodes
*/
- struct async_split *parent_as;
+ struct btree_interior_update *parent_as;
struct closure_waitlist wait;
struct journal_entry_pin journal;
+ /*
+ * Nodes being freed:
+ * Protected by c->btree_node_pending_free_lock
+ */
struct pending_btree_node_free pending[BTREE_MAX_DEPTH + GC_MERGE_NODES];
unsigned nr_pending;
@@ -103,7 +110,11 @@ struct async_split {
u64 inline_keys[BKEY_BTREE_PTR_U64s_MAX * 3];
};
-void bch_btree_node_free_start(struct cache_set *, struct async_split *,
+#define for_each_pending_btree_node_free(c, as, p) \
+ list_for_each_entry(as, &c->btree_interior_update_list, list) \
+ for (p = as->pending; p < as->pending + as->nr_pending; p++)
+
+void bch_btree_node_free_start(struct cache_set *, struct btree_interior_update *,
struct btree *);
void bch_btree_node_free_inmem(struct btree_iter *, struct btree *);
@@ -118,11 +129,11 @@ struct btree *__btree_node_alloc_replacement(struct cache_set *,
struct btree *btree_node_alloc_replacement(struct cache_set *, struct btree *,
struct btree_reserve *);
-struct async_split *__bch_async_split_alloc(struct btree *[], unsigned,
+struct btree_interior_update *__bch_btree_interior_update_alloc(struct btree *[], unsigned,
struct btree_iter *);
-struct async_split *bch_async_split_alloc(struct btree *, struct btree_iter *);
+struct btree_interior_update *bch_btree_interior_update_alloc(struct btree *, struct btree_iter *);
-void bch_async_split_will_free_node(struct async_split *, struct btree *);
+void bch_btree_interior_update_will_free_node(struct btree_interior_update *, struct btree *);
void bch_btree_set_root_initial(struct cache_set *, struct btree *,
struct btree_reserve *);
@@ -185,7 +196,7 @@ static inline bool bch_btree_node_insert_fits(struct cache_set *c,
void bch_btree_insert_node(struct btree *, struct btree_iter *,
struct keylist *, struct btree_reserve *,
- struct async_split *as);
+ struct btree_interior_update *as);
/* Normal update interface: */
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index 09451a155b35..27d984c1d37a 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -892,7 +892,7 @@ static void cache_set_free(struct cache_set *c)
bioset_exit(&c->bio_read_split);
bioset_exit(&c->bio_read);
bioset_exit(&c->btree_read_bio);
- mempool_exit(&c->btree_async_split_pool);
+ mempool_exit(&c->btree_interior_update_pool);
mempool_exit(&c->btree_reserve_pool);
mempool_exit(&c->fill_iter);
mempool_exit(&c->search);
@@ -1079,10 +1079,9 @@ static struct cache_set *bch_cache_set_alloc(struct cache_sb *sb,
INIT_LIST_HEAD(&c->btree_cache_freeable);
INIT_LIST_HEAD(&c->btree_cache_freed);
- INIT_LIST_HEAD(&c->btree_node_pending_free);
- mutex_init(&c->btree_node_pending_free_lock);
+ INIT_LIST_HEAD(&c->btree_interior_update_list);
mutex_init(&c->btree_reserve_cache_lock);
- mutex_init(&c->async_split_lock);
+ mutex_init(&c->btree_interior_update_lock);
mutex_init(&c->bio_bounce_pages_lock);
INIT_WORK(&c->bio_submit_work, bch_bio_submit_work);
@@ -1138,9 +1137,9 @@ static struct cache_set *bch_cache_set_alloc(struct cache_sb *sb,
percpu_ref_init(&c->writes, bch_writes_disabled, 0, GFP_KERNEL) ||
mempool_init_slab_pool(&c->search, 1, bch_search_cache) ||
mempool_init_kmalloc_pool(&c->btree_reserve_pool, 1,
- BTREE_RESERVE_SIZE) ||
- mempool_init_kmalloc_pool(&c->btree_async_split_pool, 1,
- sizeof(struct async_split)) ||
+ sizeof(struct btree_reserve)) ||
+ mempool_init_kmalloc_pool(&c->btree_interior_update_pool, 1,
+ sizeof(struct btree_interior_update)) ||
mempool_init_kmalloc_pool(&c->fill_iter, 1, iter_size) ||
bioset_init(&c->btree_read_bio, 1, offsetof(struct bbio, bio)) ||
bioset_init(&c->bio_read, 1, offsetof(struct bch_read_bio, bio)) ||