summaryrefslogtreecommitdiff
path: root/libbcachefs/btree_update.c
diff options
context:
space:
mode:
Diffstat (limited to 'libbcachefs/btree_update.c')
-rw-r--r--libbcachefs/btree_update.c95
1 files changed, 48 insertions, 47 deletions
diff --git a/libbcachefs/btree_update.c b/libbcachefs/btree_update.c
index cdbc0de4..196b7423 100644
--- a/libbcachefs/btree_update.c
+++ b/libbcachefs/btree_update.c
@@ -161,15 +161,14 @@ static void __btree_node_free(struct bch_fs *c, struct btree *b,
{
trace_btree_node_free(c, b);
+ BUG_ON(btree_node_dirty(b));
BUG_ON(b == btree_node_root(c, b));
BUG_ON(b->ob);
BUG_ON(!list_empty(&b->write_blocked));
- six_lock_write(&b->lock);
+ clear_btree_node_noevict(b);
- if (btree_node_dirty(b))
- bch2_btree_complete_write(c, b, btree_current_write(b));
- clear_btree_node_dirty(b);
+ six_lock_write(&b->lock);
bch2_btree_node_hash_remove(c, b);
@@ -192,6 +191,8 @@ void bch2_btree_node_free_never_inserted(struct bch_fs *c, struct btree *b)
b->ob = NULL;
+ clear_btree_node_dirty(b);
+
__btree_node_free(c, b, NULL);
bch2_open_bucket_put(c, ob);
@@ -890,7 +891,8 @@ bch2_btree_interior_update_alloc(struct bch_fs *c)
static void btree_interior_update_free(struct closure *cl)
{
- struct btree_interior_update *as = container_of(cl, struct btree_interior_update, cl);
+ struct btree_interior_update *as =
+ container_of(cl, struct btree_interior_update, cl);
mempool_free(as, &as->c->btree_interior_update_pool);
}
@@ -910,9 +912,6 @@ static void btree_interior_update_nodes_reachable(struct closure *cl)
bch2_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);
@@ -1039,6 +1038,15 @@ static void btree_interior_update_updated_btree(struct bch_fs *c,
system_freezable_wq);
}
+static void btree_interior_update_reparent(struct btree_interior_update *as,
+ struct btree_interior_update *child)
+{
+ child->b = NULL;
+ child->mode = BTREE_INTERIOR_UPDATING_AS;
+ child->parent_as = as;
+ closure_get(&as->cl);
+}
+
static void btree_interior_update_updated_root(struct bch_fs *c,
struct btree_interior_update *as,
enum btree_id btree_id)
@@ -1053,14 +1061,8 @@ static void btree_interior_update_updated_root(struct bch_fs *c,
* Old root might not be persistent yet - if so, redirect its
* btree_interior_update operation to point to us:
*/
- if (r->as) {
- BUG_ON(r->as->mode != BTREE_INTERIOR_UPDATING_ROOT);
-
- r->as->b = NULL;
- r->as->mode = BTREE_INTERIOR_UPDATING_AS;
- r->as->parent_as = as;
- closure_get(&as->cl);
- }
+ if (r->as)
+ btree_interior_update_reparent(as, r->as);
as->mode = BTREE_INTERIOR_UPDATING_ROOT;
as->b = r->b;
@@ -1068,8 +1070,6 @@ static void btree_interior_update_updated_root(struct bch_fs *c,
mutex_unlock(&c->btree_interior_update_lock);
- bch2_journal_wait_on_seq(&c->journal, as->journal_seq, &as->cl);
-
continue_at(&as->cl, btree_interior_update_nodes_written,
system_freezable_wq);
}
@@ -1092,8 +1092,10 @@ void bch2_btree_interior_update_will_free_node(struct bch_fs *c,
struct btree_interior_update *as,
struct btree *b)
{
+ struct closure *cl, *cl_n;
struct btree_interior_update *p, *n;
struct pending_btree_node_free *d;
+ struct btree_write *w;
struct bset_tree *t;
/*
@@ -1107,23 +1109,18 @@ void bch2_btree_interior_update_will_free_node(struct bch_fs *c,
for_each_bset(b, t)
as->journal_seq = max(as->journal_seq, bset(b, t)->journal_seq);
- /*
- * Does this node have unwritten data that has a pin on the journal?
- *
- * If so, transfer that pin to the btree_interior_update operation -
- * note that if we're freeing multiple nodes, we only need to keep the
- * oldest pin of any of the nodes we're freeing. We'll release the pin
- * when the new nodes are persistent and reachable on disk:
- */
- bch2_journal_pin_add_if_older(&c->journal,
- &b->writes[0].journal,
- &as->journal, interior_update_flush);
- bch2_journal_pin_add_if_older(&c->journal,
- &b->writes[1].journal,
- &as->journal, interior_update_flush);
-
mutex_lock(&c->btree_interior_update_lock);
+ /* Add this node to the list of nodes being freed: */
+ BUG_ON(as->nr_pending >= ARRAY_SIZE(as->pending));
+
+ 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);
+
/*
* Does this node have any btree_interior_update operations preventing
* it from being written?
@@ -1133,24 +1130,28 @@ void bch2_btree_interior_update_will_free_node(struct bch_fs *c,
* operations complete
*/
list_for_each_entry_safe(p, n, &b->write_blocked, write_blocked_list) {
- BUG_ON(p->mode != BTREE_INTERIOR_UPDATING_NODE);
-
- p->mode = BTREE_INTERIOR_UPDATING_AS;
list_del(&p->write_blocked_list);
- p->b = NULL;
- p->parent_as = as;
- closure_get(&as->cl);
+ btree_interior_update_reparent(as, p);
}
- /* Add this node to the list of nodes being freed: */
- BUG_ON(as->nr_pending >= ARRAY_SIZE(as->pending));
+ clear_btree_node_dirty(b);
+ w = btree_current_write(b);
+
+ llist_for_each_entry_safe(cl, cl_n, llist_del_all(&w->wait.list), list)
+ llist_add(&cl->list, &as->wait.list);
+
+ /*
+ * Does this node have unwritten data that has a pin on the journal?
+ *
+ * If so, transfer that pin to the btree_interior_update operation -
+ * note that if we're freeing multiple nodes, we only need to keep the
+ * oldest pin of any of the nodes we're freeing. We'll release the pin
+ * when the new nodes are persistent and reachable on disk:
+ */
+ bch2_journal_pin_add_if_older(&c->journal, &w->journal,
+ &as->journal, interior_update_flush);
+ bch2_journal_pin_drop(&c->journal, &w->journal);
- 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_unlock(&c->btree_interior_update_lock);
}