mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-11-01 17:08:10 +00:00
bcachefs: Seralize btree_update operations at btree_update_nodes_written()
Prep work for journalling updates to interior nodes - enforcing ordering will greatly simplify those changes. Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com> Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
548b3d209f
commit
ac7c51b218
4 changed files with 29 additions and 6 deletions
|
@ -610,6 +610,7 @@ struct bch_fs {
|
||||||
|
|
||||||
mempool_t btree_interior_update_pool;
|
mempool_t btree_interior_update_pool;
|
||||||
struct list_head btree_interior_update_list;
|
struct list_head btree_interior_update_list;
|
||||||
|
struct list_head btree_interior_updates_unwritten;
|
||||||
struct mutex btree_interior_update_lock;
|
struct mutex btree_interior_update_lock;
|
||||||
struct closure_waitlist btree_interior_update_wait;
|
struct closure_waitlist btree_interior_update_wait;
|
||||||
|
|
||||||
|
|
|
@ -666,9 +666,15 @@ static void btree_update_nodes_written(struct closure *cl)
|
||||||
* to child nodes that weren't written yet: now, the child nodes have
|
* to child nodes that weren't written yet: now, the child nodes have
|
||||||
* been written so we can write out the update to the interior node.
|
* been written so we can write out the update to the interior node.
|
||||||
*/
|
*/
|
||||||
retry:
|
|
||||||
mutex_lock(&c->btree_interior_update_lock);
|
mutex_lock(&c->btree_interior_update_lock);
|
||||||
as->nodes_written = true;
|
as->nodes_written = true;
|
||||||
|
retry:
|
||||||
|
as = list_first_entry_or_null(&c->btree_interior_updates_unwritten,
|
||||||
|
struct btree_update, unwritten_list);
|
||||||
|
if (!as || !as->nodes_written) {
|
||||||
|
mutex_unlock(&c->btree_interior_update_lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (as->mode) {
|
switch (as->mode) {
|
||||||
case BTREE_INTERIOR_NO_UPDATE:
|
case BTREE_INTERIOR_NO_UPDATE:
|
||||||
|
@ -681,11 +687,12 @@ static void btree_update_nodes_written(struct closure *cl)
|
||||||
mutex_unlock(&c->btree_interior_update_lock);
|
mutex_unlock(&c->btree_interior_update_lock);
|
||||||
btree_node_lock_type(c, b, SIX_LOCK_read);
|
btree_node_lock_type(c, b, SIX_LOCK_read);
|
||||||
six_unlock_read(&b->c.lock);
|
six_unlock_read(&b->c.lock);
|
||||||
|
mutex_lock(&c->btree_interior_update_lock);
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
BUG_ON(!btree_node_dirty(b));
|
BUG_ON(!btree_node_dirty(b));
|
||||||
closure_wait(&btree_current_write(b)->wait, cl);
|
closure_wait(&btree_current_write(b)->wait, &as->cl);
|
||||||
|
|
||||||
list_del(&as->write_blocked_list);
|
list_del(&as->write_blocked_list);
|
||||||
|
|
||||||
|
@ -694,6 +701,8 @@ static void btree_update_nodes_written(struct closure *cl)
|
||||||
* nodes to be writeable:
|
* nodes to be writeable:
|
||||||
*/
|
*/
|
||||||
closure_wake_up(&c->btree_interior_update_wait);
|
closure_wake_up(&c->btree_interior_update_wait);
|
||||||
|
|
||||||
|
list_del(&as->unwritten_list);
|
||||||
mutex_unlock(&c->btree_interior_update_lock);
|
mutex_unlock(&c->btree_interior_update_lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -702,6 +711,7 @@ static void btree_update_nodes_written(struct closure *cl)
|
||||||
*/
|
*/
|
||||||
bch2_btree_node_write_cond(c, b, true);
|
bch2_btree_node_write_cond(c, b, true);
|
||||||
six_unlock_read(&b->c.lock);
|
six_unlock_read(&b->c.lock);
|
||||||
|
continue_at(&as->cl, btree_update_nodes_reachable, system_wq);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BTREE_INTERIOR_UPDATING_AS:
|
case BTREE_INTERIOR_UPDATING_AS:
|
||||||
|
@ -716,8 +726,12 @@ static void btree_update_nodes_written(struct closure *cl)
|
||||||
/*
|
/*
|
||||||
* and then we have to wait on that btree_update to finish:
|
* and then we have to wait on that btree_update to finish:
|
||||||
*/
|
*/
|
||||||
closure_wait(&as->parent_as->wait, cl);
|
closure_wait(&as->parent_as->wait, &as->cl);
|
||||||
|
|
||||||
|
list_del(&as->unwritten_list);
|
||||||
mutex_unlock(&c->btree_interior_update_lock);
|
mutex_unlock(&c->btree_interior_update_lock);
|
||||||
|
|
||||||
|
continue_at(&as->cl, btree_update_nodes_reachable, system_wq);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BTREE_INTERIOR_UPDATING_ROOT:
|
case BTREE_INTERIOR_UPDATING_ROOT:
|
||||||
|
@ -728,6 +742,7 @@ static void btree_update_nodes_written(struct closure *cl)
|
||||||
mutex_unlock(&c->btree_interior_update_lock);
|
mutex_unlock(&c->btree_interior_update_lock);
|
||||||
btree_node_lock_type(c, b, SIX_LOCK_read);
|
btree_node_lock_type(c, b, SIX_LOCK_read);
|
||||||
six_unlock_read(&b->c.lock);
|
six_unlock_read(&b->c.lock);
|
||||||
|
mutex_lock(&c->btree_interior_update_lock);
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -744,6 +759,8 @@ static void btree_update_nodes_written(struct closure *cl)
|
||||||
* can reuse the old nodes it'll have to do a journal commit:
|
* can reuse the old nodes it'll have to do a journal commit:
|
||||||
*/
|
*/
|
||||||
six_unlock_read(&b->c.lock);
|
six_unlock_read(&b->c.lock);
|
||||||
|
|
||||||
|
list_del(&as->unwritten_list);
|
||||||
mutex_unlock(&c->btree_interior_update_lock);
|
mutex_unlock(&c->btree_interior_update_lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -762,11 +779,12 @@ static void btree_update_nodes_written(struct closure *cl)
|
||||||
|
|
||||||
as->journal_seq = bch2_journal_last_unwritten_seq(&c->journal);
|
as->journal_seq = bch2_journal_last_unwritten_seq(&c->journal);
|
||||||
|
|
||||||
btree_update_wait_on_journal(cl);
|
btree_update_wait_on_journal(&as->cl);
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue_at(cl, btree_update_nodes_reachable, system_wq);
|
mutex_lock(&c->btree_interior_update_lock);
|
||||||
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -778,6 +796,7 @@ static void btree_update_updated_node(struct btree_update *as, struct btree *b)
|
||||||
struct bch_fs *c = as->c;
|
struct bch_fs *c = as->c;
|
||||||
|
|
||||||
mutex_lock(&c->btree_interior_update_lock);
|
mutex_lock(&c->btree_interior_update_lock);
|
||||||
|
list_add_tail(&as->unwritten_list, &c->btree_interior_updates_unwritten);
|
||||||
|
|
||||||
BUG_ON(as->mode != BTREE_INTERIOR_NO_UPDATE);
|
BUG_ON(as->mode != BTREE_INTERIOR_NO_UPDATE);
|
||||||
BUG_ON(!btree_node_dirty(b));
|
BUG_ON(!btree_node_dirty(b));
|
||||||
|
@ -858,6 +877,7 @@ static void btree_update_updated_root(struct btree_update *as)
|
||||||
struct btree_root *r = &c->btree_roots[as->btree_id];
|
struct btree_root *r = &c->btree_roots[as->btree_id];
|
||||||
|
|
||||||
mutex_lock(&c->btree_interior_update_lock);
|
mutex_lock(&c->btree_interior_update_lock);
|
||||||
|
list_add_tail(&as->unwritten_list, &c->btree_interior_updates_unwritten);
|
||||||
|
|
||||||
BUG_ON(as->mode != BTREE_INTERIOR_NO_UPDATE);
|
BUG_ON(as->mode != BTREE_INTERIOR_NO_UPDATE);
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,7 @@ struct btree_update {
|
||||||
struct bch_fs *c;
|
struct bch_fs *c;
|
||||||
|
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
|
struct list_head unwritten_list;
|
||||||
|
|
||||||
/* What kind of update are we doing? */
|
/* What kind of update are we doing? */
|
||||||
enum {
|
enum {
|
||||||
|
|
|
@ -642,6 +642,7 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts)
|
||||||
INIT_LIST_HEAD(&c->list);
|
INIT_LIST_HEAD(&c->list);
|
||||||
|
|
||||||
INIT_LIST_HEAD(&c->btree_interior_update_list);
|
INIT_LIST_HEAD(&c->btree_interior_update_list);
|
||||||
|
INIT_LIST_HEAD(&c->btree_interior_updates_unwritten);
|
||||||
mutex_init(&c->btree_reserve_cache_lock);
|
mutex_init(&c->btree_reserve_cache_lock);
|
||||||
mutex_init(&c->btree_interior_update_lock);
|
mutex_init(&c->btree_interior_update_lock);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue