Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 17e21a9f authored by Kent Overstreet's avatar Kent Overstreet
Browse files

bcache: Have btree_split() insert into parent directly



The flow control in btree_insert_node() was... fragile... before,
this'll use more stack (but since our btrees are never more than depth
1, that shouldn't matter) and it should be significantly clearer and
less fragile.

Signed-off-by: default avatarKent Overstreet <kmo@daterainc.com>
parent 65d22e91
Loading
Loading
Loading
Loading
+39 −46
Original line number Original line Diff line number Diff line
@@ -2025,15 +2025,16 @@ static bool bch_btree_insert_keys(struct btree *b, struct btree_op *op,


static int btree_split(struct btree *b, struct btree_op *op,
static int btree_split(struct btree *b, struct btree_op *op,
		       struct keylist *insert_keys,
		       struct keylist *insert_keys,
		       struct keylist *parent_keys,
		       struct bkey *replace_key)
		       struct bkey *replace_key)
{
{
	bool split;
	bool split;
	struct btree *n1, *n2 = NULL, *n3 = NULL;
	struct btree *n1, *n2 = NULL, *n3 = NULL;
	uint64_t start_time = local_clock();
	uint64_t start_time = local_clock();
	struct closure cl;
	struct closure cl;
	struct keylist parent_keys;


	closure_init_stack(&cl);
	closure_init_stack(&cl);
	bch_keylist_init(&parent_keys);


	n1 = btree_node_alloc_replacement(b, true);
	n1 = btree_node_alloc_replacement(b, true);
	if (IS_ERR(n1))
	if (IS_ERR(n1))
@@ -2078,7 +2079,7 @@ static int btree_split(struct btree *b, struct btree_op *op,


		bkey_copy_key(&n2->key, &b->key);
		bkey_copy_key(&n2->key, &b->key);


		bch_keylist_add(parent_keys, &n2->key);
		bch_keylist_add(&parent_keys, &n2->key);
		bch_btree_node_write(n2, &cl);
		bch_btree_node_write(n2, &cl);
		rw_unlock(true, n2);
		rw_unlock(true, n2);
	} else {
	} else {
@@ -2087,33 +2088,39 @@ static int btree_split(struct btree *b, struct btree_op *op,
		bch_btree_insert_keys(n1, op, insert_keys, replace_key);
		bch_btree_insert_keys(n1, op, insert_keys, replace_key);
	}
	}


	bch_keylist_add(parent_keys, &n1->key);
	bch_keylist_add(&parent_keys, &n1->key);
	bch_btree_node_write(n1, &cl);
	bch_btree_node_write(n1, &cl);


	if (n3) {
	if (n3) {
		/* Depth increases, make a new root */
		/* Depth increases, make a new root */

		bkey_copy_key(&n3->key, &MAX_KEY);
		bkey_copy_key(&n3->key, &MAX_KEY);
		bch_btree_insert_keys(n3, op, parent_keys, NULL);
		bch_btree_insert_keys(n3, op, &parent_keys, NULL);
		bch_btree_node_write(n3, &cl);
		bch_btree_node_write(n3, &cl);


		closure_sync(&cl);
		closure_sync(&cl);
		bch_btree_set_root(n3);
		bch_btree_set_root(n3);
		rw_unlock(true, n3);
		rw_unlock(true, n3);

		btree_node_free(b);
	} else if (!b->parent) {
	} else if (!b->parent) {
		/* Root filled up but didn't need to be split */
		/* Root filled up but didn't need to be split */

		bch_keylist_reset(parent_keys);
		closure_sync(&cl);
		closure_sync(&cl);
		bch_btree_set_root(n1);
		bch_btree_set_root(n1);

		btree_node_free(b);
	} else {
	} else {
		/* Split a non root node */
		closure_sync(&cl);
		closure_sync(&cl);
		make_btree_freeing_key(b, parent_keys->top);
		make_btree_freeing_key(b, parent_keys.top);
		bch_keylist_push(parent_keys);
		bch_keylist_push(&parent_keys);

		btree_node_free(b);

		bch_btree_insert_node(b->parent, op, &parent_keys, NULL, NULL);
		BUG_ON(!bch_keylist_empty(&parent_keys));
	}
	}


	rw_unlock(true, n1);
	rw_unlock(true, n1);
	btree_node_free(b);


	bch_time_stats_update(&b->c->btree_split_time, start_time);
	bch_time_stats_update(&b->c->btree_split_time, start_time);


@@ -2139,46 +2146,32 @@ static int bch_btree_insert_node(struct btree *b, struct btree_op *op,
				 atomic_t *journal_ref,
				 atomic_t *journal_ref,
				 struct bkey *replace_key)
				 struct bkey *replace_key)
{
{
	int ret = 0;
	struct keylist split_keys;

	bch_keylist_init(&split_keys);

	do {
	BUG_ON(b->level && replace_key);
	BUG_ON(b->level && replace_key);


	if (should_split(b)) {
	if (should_split(b)) {
		if (current->bio_list) {
		if (current->bio_list) {
			op->lock = b->c->root->level + 1;
			op->lock = b->c->root->level + 1;
				ret = -EAGAIN;
			return -EAGAIN;
		} else if (op->lock <= b->c->root->level) {
		} else if (op->lock <= b->c->root->level) {
			op->lock = b->c->root->level + 1;
			op->lock = b->c->root->level + 1;
				ret = -EINTR;
			return -EINTR;
		} else {
		} else {
				struct btree *parent = b->parent;
			/* Invalidated all iterators */

			return btree_split(b, op, insert_keys, replace_key) ?:
				ret = btree_split(b, op, insert_keys,
				-EINTR;
						  &split_keys, replace_key);
				insert_keys = &split_keys;
				replace_key = NULL;
				b = parent;
				if (!ret)
					ret = -EINTR;
		}
		}
	} else {
	} else {
		BUG_ON(write_block(b) != b->sets[b->nsets].data);
		BUG_ON(write_block(b) != b->sets[b->nsets].data);


			if (bch_btree_insert_keys(b, op, insert_keys,
		if (bch_btree_insert_keys(b, op, insert_keys, replace_key)) {
						  replace_key)) {
			if (!b->level)
			if (!b->level)
				bch_btree_leaf_dirty(b, journal_ref);
				bch_btree_leaf_dirty(b, journal_ref);
			else
			else
				bch_btree_node_write_sync(b);
				bch_btree_node_write_sync(b);
		}
		}
		}
	} while (!bch_keylist_empty(&split_keys));


	return ret;
		return 0;
	}
}
}


int bch_btree_insert_check_key(struct btree *b, struct btree_op *op,
int bch_btree_insert_check_key(struct btree *b, struct btree_op *op,