diff options
Diffstat (limited to 'libbcachefs/btree_update_interior.c')
-rw-r--r-- | libbcachefs/btree_update_interior.c | 82 |
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, |