Commit aa8889c0 authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet

bcachefs: Fix assertion popping in transaction commit path

We can't be holding read locks on btree nodes when we go to take write
locks: this would deadlock if another thread is holding an intent lock
on the node we have a read lock on, and it tries to commit and upgrade
to a write lock.

But instead of triggering an assertion, if this happens we can just
upgrade the read lock to an intent lock.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent f3721e12
...@@ -503,6 +503,10 @@ static inline int do_bch2_trans_commit(struct btree_trans *trans, ...@@ -503,6 +503,10 @@ static inline int do_bch2_trans_commit(struct btree_trans *trans,
/* /*
* Can't be holding any read locks when we go to take write locks: * Can't be holding any read locks when we go to take write locks:
* another thread could be holding an intent lock on the same node we
* have a read lock on, and it'll block trying to take a write lock
* (because we hold a read lock) and it could be blocking us by holding
* its own read lock (while we're trying to to take write locks).
* *
* note - this must be done after bch2_trans_journal_preres_get_cold() * note - this must be done after bch2_trans_journal_preres_get_cold()
* or anything else that might call bch2_trans_relock(), since that * or anything else that might call bch2_trans_relock(), since that
...@@ -510,9 +514,15 @@ static inline int do_bch2_trans_commit(struct btree_trans *trans, ...@@ -510,9 +514,15 @@ static inline int do_bch2_trans_commit(struct btree_trans *trans,
*/ */
trans_for_each_iter(trans, iter) { trans_for_each_iter(trans, iter) {
if (iter->nodes_locked != iter->nodes_intent_locked) { if (iter->nodes_locked != iter->nodes_intent_locked) {
EBUG_ON(iter->flags & BTREE_ITER_KEEP_UNTIL_COMMIT); if ((iter->flags & BTREE_ITER_KEEP_UNTIL_COMMIT) ||
EBUG_ON(trans->iters_live & (1ULL << iter->idx)); (trans->iters_live & (1ULL << iter->idx))) {
bch2_btree_iter_unlock_noinline(iter); if (!bch2_btree_iter_upgrade(iter, 1)) {
trace_trans_restart_upgrade(trans->ip);
return -EINTR;
}
} else {
bch2_btree_iter_unlock_noinline(iter);
}
} }
} }
......
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