Commit 0f9dda47 authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet

bcachefs: Fix a deadlock on starting an interior btree update

Not legal to block on a journal prereservation with btree locks held.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 1e3b1f9a
...@@ -935,7 +935,7 @@ static void bch2_coalesce_nodes(struct bch_fs *c, struct btree_iter *iter, ...@@ -935,7 +935,7 @@ static void bch2_coalesce_nodes(struct bch_fs *c, struct btree_iter *iter,
return; return;
} }
as = bch2_btree_update_start(c, iter->btree_id, as = bch2_btree_update_start(iter->trans, iter->btree_id,
btree_update_reserve_required(c, parent) + nr_old_nodes, btree_update_reserve_required(c, parent) + nr_old_nodes,
BTREE_INSERT_NOFAIL| BTREE_INSERT_NOFAIL|
BTREE_INSERT_USE_RESERVE, BTREE_INSERT_USE_RESERVE,
......
...@@ -949,14 +949,34 @@ void bch2_btree_update_done(struct btree_update *as) ...@@ -949,14 +949,34 @@ void bch2_btree_update_done(struct btree_update *as)
} }
struct btree_update * struct btree_update *
bch2_btree_update_start(struct bch_fs *c, enum btree_id id, bch2_btree_update_start(struct btree_trans *trans, enum btree_id id,
unsigned nr_nodes, unsigned flags, unsigned nr_nodes, unsigned flags,
struct closure *cl) struct closure *cl)
{ {
struct bch_fs *c = trans->c;
struct journal_preres journal_preres = { 0 };
struct btree_reserve *reserve; struct btree_reserve *reserve;
struct btree_update *as; struct btree_update *as;
int ret; int ret;
ret = bch2_journal_preres_get(&c->journal, &journal_preres,
BTREE_UPDATE_JOURNAL_RES,
JOURNAL_RES_GET_NONBLOCK);
if (ret == -EAGAIN) {
bch2_trans_unlock(trans);
ret = bch2_journal_preres_get(&c->journal, &journal_preres,
BTREE_UPDATE_JOURNAL_RES,
JOURNAL_RES_GET_NONBLOCK);
if (ret)
return ERR_PTR(ret);
if (!bch2_trans_relock(trans)) {
bch2_journal_preres_put(&c->journal, &journal_preres);
return ERR_PTR(-EINTR);
}
}
reserve = bch2_btree_reserve_get(c, nr_nodes, flags, cl); reserve = bch2_btree_reserve_get(c, nr_nodes, flags, cl);
if (IS_ERR(reserve)) if (IS_ERR(reserve))
return ERR_CAST(reserve); return ERR_CAST(reserve);
...@@ -969,18 +989,10 @@ bch2_btree_update_start(struct bch_fs *c, enum btree_id id, ...@@ -969,18 +989,10 @@ bch2_btree_update_start(struct bch_fs *c, enum btree_id id,
as->btree_id = id; as->btree_id = id;
as->reserve = reserve; as->reserve = reserve;
INIT_LIST_HEAD(&as->write_blocked_list); INIT_LIST_HEAD(&as->write_blocked_list);
as->journal_preres = journal_preres;
bch2_keylist_init(&as->parent_keys, as->inline_keys); bch2_keylist_init(&as->parent_keys, as->inline_keys);
ret = bch2_journal_preres_get(&c->journal, &as->journal_preres,
ARRAY_SIZE(as->journal_entries), 0);
if (ret) {
bch2_btree_reserve_put(c, reserve);
closure_debug_destroy(&as->cl);
mempool_free(as, &c->btree_interior_update_pool);
return ERR_PTR(ret);
}
mutex_lock(&c->btree_interior_update_lock); mutex_lock(&c->btree_interior_update_lock);
list_add_tail(&as->list, &c->btree_interior_update_list); list_add_tail(&as->list, &c->btree_interior_update_list);
mutex_unlock(&c->btree_interior_update_lock); mutex_unlock(&c->btree_interior_update_lock);
...@@ -1551,7 +1563,7 @@ int bch2_btree_split_leaf(struct bch_fs *c, struct btree_iter *iter, ...@@ -1551,7 +1563,7 @@ int bch2_btree_split_leaf(struct bch_fs *c, struct btree_iter *iter,
goto out; goto out;
} }
as = bch2_btree_update_start(c, iter->btree_id, as = bch2_btree_update_start(trans, iter->btree_id,
btree_update_reserve_required(c, b), flags, btree_update_reserve_required(c, b), flags,
!(flags & BTREE_INSERT_NOUNLOCK) ? &cl : NULL); !(flags & BTREE_INSERT_NOUNLOCK) ? &cl : NULL);
if (IS_ERR(as)) { if (IS_ERR(as)) {
...@@ -1663,7 +1675,7 @@ void __bch2_foreground_maybe_merge(struct bch_fs *c, ...@@ -1663,7 +1675,7 @@ void __bch2_foreground_maybe_merge(struct bch_fs *c,
goto err_unlock; goto err_unlock;
} }
as = bch2_btree_update_start(c, iter->btree_id, as = bch2_btree_update_start(trans, iter->btree_id,
btree_update_reserve_required(c, parent) + 1, btree_update_reserve_required(c, parent) + 1,
BTREE_INSERT_NOFAIL| BTREE_INSERT_NOFAIL|
BTREE_INSERT_USE_RESERVE, BTREE_INSERT_USE_RESERVE,
...@@ -1776,7 +1788,7 @@ static int __btree_node_rewrite(struct bch_fs *c, struct btree_iter *iter, ...@@ -1776,7 +1788,7 @@ static int __btree_node_rewrite(struct bch_fs *c, struct btree_iter *iter,
struct btree *n, *parent = btree_node_parent(iter, b); struct btree *n, *parent = btree_node_parent(iter, b);
struct btree_update *as; struct btree_update *as;
as = bch2_btree_update_start(c, iter->btree_id, as = bch2_btree_update_start(iter->trans, iter->btree_id,
(parent (parent
? btree_update_reserve_required(c, parent) ? btree_update_reserve_required(c, parent)
: 0) + 1, : 0) + 1,
...@@ -2043,7 +2055,7 @@ int bch2_btree_node_update_key(struct bch_fs *c, struct btree_iter *iter, ...@@ -2043,7 +2055,7 @@ int bch2_btree_node_update_key(struct bch_fs *c, struct btree_iter *iter,
new_hash = bch2_btree_node_mem_alloc(c); new_hash = bch2_btree_node_mem_alloc(c);
} }
as = bch2_btree_update_start(c, iter->btree_id, as = bch2_btree_update_start(iter->trans, iter->btree_id,
parent ? btree_update_reserve_required(c, parent) : 0, parent ? btree_update_reserve_required(c, parent) : 0,
BTREE_INSERT_NOFAIL| BTREE_INSERT_NOFAIL|
BTREE_INSERT_USE_RESERVE| BTREE_INSERT_USE_RESERVE|
......
...@@ -32,6 +32,9 @@ struct pending_btree_node_free { ...@@ -32,6 +32,9 @@ struct pending_btree_node_free {
__BKEY_PADDED(key, BKEY_BTREE_PTR_VAL_U64s_MAX); __BKEY_PADDED(key, BKEY_BTREE_PTR_VAL_U64s_MAX);
}; };
#define BTREE_UPDATE_JOURNAL_RES \
((BKEY_BTREE_PTR_U64s_MAX + 1) * (BTREE_MAX_DEPTH - 1) * 2)
/* /*
* Tracks an in progress split/rewrite of a btree node and the update to the * Tracks an in progress split/rewrite of a btree node and the update to the
* parent node: * parent node:
...@@ -105,8 +108,7 @@ struct btree_update { ...@@ -105,8 +108,7 @@ struct btree_update {
unsigned nr_new_nodes; unsigned nr_new_nodes;
unsigned journal_u64s; unsigned journal_u64s;
u64 journal_entries[ u64 journal_entries[BTREE_UPDATE_JOURNAL_RES];
(BKEY_BTREE_PTR_U64s_MAX + 1) * (BTREE_MAX_DEPTH - 1) * 2];
/* Only here to reduce stack usage on recursive splits: */ /* Only here to reduce stack usage on recursive splits: */
struct keylist parent_keys; struct keylist parent_keys;
...@@ -132,7 +134,7 @@ struct btree *__bch2_btree_node_alloc_replacement(struct btree_update *, ...@@ -132,7 +134,7 @@ struct btree *__bch2_btree_node_alloc_replacement(struct btree_update *,
void bch2_btree_update_done(struct btree_update *); void bch2_btree_update_done(struct btree_update *);
struct btree_update * struct btree_update *
bch2_btree_update_start(struct bch_fs *, enum btree_id, unsigned, bch2_btree_update_start(struct btree_trans *, enum btree_id, unsigned,
unsigned, struct closure *); unsigned, struct closure *);
void bch2_btree_interior_update_will_free_node(struct btree_update *, void bch2_btree_interior_update_will_free_node(struct btree_update *,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment