summaryrefslogtreecommitdiff
path: root/libbcachefs/btree_update_interior.c
diff options
context:
space:
mode:
Diffstat (limited to 'libbcachefs/btree_update_interior.c')
-rw-r--r--libbcachefs/btree_update_interior.c82
1 files changed, 55 insertions, 27 deletions
diff --git a/libbcachefs/btree_update_interior.c b/libbcachefs/btree_update_interior.c
index a0f37c4c..e92a6a3a 100644
--- a/libbcachefs/btree_update_interior.c
+++ b/libbcachefs/btree_update_interior.c
@@ -270,6 +270,17 @@ void bch2_btree_node_free_never_inserted(struct bch_fs *c, struct btree *b)
void bch2_btree_node_free_inmem(struct bch_fs *c, struct btree *b,
struct btree_iter *iter)
{
+ /*
+ * Is this a node that isn't reachable on disk yet?
+ *
+ * Nodes that aren't reachable yet have writes blocked until they're
+ * reachable - now that we've cancelled any pending writes and moved
+ * things waiting on that write to wait on this update, we can drop this
+ * node from the list of nodes that the other update is making
+ * reachable, prior to freeing it:
+ */
+ btree_update_drop_new_node(c, b);
+
bch2_btree_iter_node_drop_linked(iter, b);
__btree_node_free(c, b, iter);
@@ -503,8 +514,7 @@ static struct btree_reserve *bch2_btree_reserve_get(struct bch_fs *c,
struct btree *b;
struct disk_reservation disk_res = { 0, 0 };
unsigned sectors = nr_nodes * c->opts.btree_node_size;
- int ret, disk_res_flags = BCH_DISK_RESERVATION_GC_LOCK_HELD|
- BCH_DISK_RESERVATION_METADATA;
+ int ret, disk_res_flags = BCH_DISK_RESERVATION_GC_LOCK_HELD;
if (flags & BTREE_INSERT_NOFAIL)
disk_res_flags |= BCH_DISK_RESERVATION_NOFAIL;
@@ -517,7 +527,9 @@ static struct btree_reserve *bch2_btree_reserve_get(struct bch_fs *c,
if (ret)
return ERR_PTR(ret);
- if (bch2_disk_reservation_get(c, &disk_res, sectors, disk_res_flags))
+ if (bch2_disk_reservation_get(c, &disk_res, sectors,
+ c->opts.metadata_replicas,
+ disk_res_flags))
return ERR_PTR(-ENOSPC);
BUG_ON(nr_nodes > BTREE_RESERVE_MAX);
@@ -597,12 +609,17 @@ static void btree_update_nodes_reachable(struct closure *cl)
while (as->nr_new_nodes) {
struct btree *b = as->new_nodes[--as->nr_new_nodes];
- BUG_ON(b->will_make_reachable != as);
- b->will_make_reachable = NULL;
+ BUG_ON(b->will_make_reachable &&
+ (struct btree_update *) b->will_make_reachable != as);
+ b->will_make_reachable = 0;
mutex_unlock(&c->btree_interior_update_lock);
+ /*
+ * b->will_make_reachable prevented it from being written, so
+ * write it now if it needs to be written:
+ */
six_lock_read(&b->lock);
- bch2_btree_node_write_dirty(c, b, NULL, btree_node_need_write(b));
+ bch2_btree_node_write_cond(c, b, btree_node_need_write(b));
six_unlock_read(&b->lock);
mutex_lock(&c->btree_interior_update_lock);
}
@@ -651,8 +668,11 @@ retry:
list_del(&as->write_blocked_list);
mutex_unlock(&c->btree_interior_update_lock);
- bch2_btree_node_write_dirty(c, b, NULL,
- btree_node_need_write(b));
+ /*
+ * b->write_blocked prevented it from being written, so
+ * write it now if it needs to be written:
+ */
+ bch2_btree_node_write_cond(c, b, btree_node_need_write(b));
six_unlock_read(&b->lock);
break;
@@ -851,17 +871,25 @@ static void btree_node_will_make_reachable(struct btree_update *as,
BUG_ON(b->will_make_reachable);
as->new_nodes[as->nr_new_nodes++] = b;
- b->will_make_reachable = as;
+ b->will_make_reachable = 1UL|(unsigned long) as;
+
+ closure_get(&as->cl);
mutex_unlock(&c->btree_interior_update_lock);
}
-static void __btree_interior_update_drop_new_node(struct btree *b)
+static void btree_update_drop_new_node(struct bch_fs *c, struct btree *b)
{
- struct btree_update *as = b->will_make_reachable;
+ struct btree_update *as;
+ unsigned long v;
unsigned i;
- BUG_ON(!as);
+ if (!b->will_make_reachable)
+ return;
+
+ mutex_lock(&c->btree_interior_update_lock);
+ v = xchg(&b->will_make_reachable, 0);
+ as = (struct btree_update *) (v & ~1UL);
for (i = 0; i < as->nr_new_nodes; i++)
if (as->new_nodes[i] == b)
goto found;
@@ -869,14 +897,10 @@ static void __btree_interior_update_drop_new_node(struct btree *b)
BUG();
found:
array_remove_item(as->new_nodes, as->nr_new_nodes, i);
- b->will_make_reachable = NULL;
-}
-
-static void btree_update_drop_new_node(struct bch_fs *c, struct btree *b)
-{
- mutex_lock(&c->btree_interior_update_lock);
- __btree_interior_update_drop_new_node(b);
mutex_unlock(&c->btree_interior_update_lock);
+
+ if (v & 1)
+ closure_put(&as->cl);
}
static void btree_interior_update_add_node_reference(struct btree_update *as,
@@ -952,6 +976,12 @@ void bch2_btree_interior_update_will_free_node(struct btree_update *as,
clear_btree_node_need_write(b);
w = btree_current_write(b);
+ /*
+ * Does this node have any btree_update operations waiting on this node
+ * to be written?
+ *
+ * If so, wake them up when this btree_update operation is reachable:
+ */
llist_for_each_entry_safe(cl, cl_n, llist_del_all(&w->wait.list), list)
llist_add(&cl->list, &as->wait.list);
@@ -972,9 +1002,6 @@ void bch2_btree_interior_update_will_free_node(struct btree_update *as,
&as->journal, interior_update_flush);
bch2_journal_pin_drop(&c->journal, &w->journal);
- if (b->will_make_reachable)
- __btree_interior_update_drop_new_node(b);
-
mutex_unlock(&c->btree_interior_update_lock);
}
@@ -1338,7 +1365,7 @@ static void btree_split(struct btree_update *as, struct btree *b,
six_unlock_write(&n2->lock);
six_unlock_write(&n1->lock);
- bch2_btree_node_write(c, n2, &as->cl, SIX_LOCK_intent);
+ bch2_btree_node_write(c, n2, SIX_LOCK_intent);
/*
* Note that on recursive parent_keys == keys, so we
@@ -1356,7 +1383,8 @@ static void btree_split(struct btree_update *as, struct btree *b,
n3->sib_u64s[1] = U16_MAX;
btree_split_insert_keys(as, n3, iter, &as->parent_keys);
- bch2_btree_node_write(c, n3, &as->cl, SIX_LOCK_intent);
+
+ bch2_btree_node_write(c, n3, SIX_LOCK_intent);
}
} else {
trace_btree_compact(c, b);
@@ -1367,7 +1395,7 @@ static void btree_split(struct btree_update *as, struct btree *b,
bch2_keylist_add(&as->parent_keys, &n1->key);
}
- bch2_btree_node_write(c, n1, &as->cl, SIX_LOCK_intent);
+ bch2_btree_node_write(c, n1, SIX_LOCK_intent);
/* New nodes all written, now make them visible: */
@@ -1668,7 +1696,7 @@ retry:
bch2_keylist_add(&as->parent_keys, &delete);
bch2_keylist_add(&as->parent_keys, &n->key);
- bch2_btree_node_write(c, n, &as->cl, SIX_LOCK_intent);
+ bch2_btree_node_write(c, n, SIX_LOCK_intent);
bch2_btree_insert_node(as, parent, iter, &as->parent_keys);
@@ -1726,7 +1754,7 @@ static int __btree_node_rewrite(struct bch_fs *c, struct btree_iter *iter,
trace_btree_gc_rewrite_node(c, b);
- bch2_btree_node_write(c, n, &as->cl, SIX_LOCK_intent);
+ bch2_btree_node_write(c, n, SIX_LOCK_intent);
if (parent) {
bch2_btree_insert_node(as, parent, iter,