diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2022-09-20 13:01:44 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2022-09-20 13:01:44 -0400 |
commit | 4fb76991f7742ead11ab1d8e0bb7542f08d1bbed (patch) | |
tree | 13cd76b8e14c815a0f7ec3c6cf072a3b9a89884a | |
parent | b1ec8ed080f487022444c0ad9f019160e1b37176 (diff) |
bcachefs: Deadlock handling improvement
When we detect a deadlock, prefer to abort a transaction that isn't in
traverse_all, since transactions in traverse_all should never deadlock
with each other.
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r-- | fs/bcachefs/btree_locking.c | 29 |
1 files changed, 20 insertions, 9 deletions
diff --git a/fs/bcachefs/btree_locking.c b/fs/bcachefs/btree_locking.c index 9ece0f318e57..0a3090f8a633 100644 --- a/fs/bcachefs/btree_locking.c +++ b/fs/bcachefs/btree_locking.c @@ -87,23 +87,34 @@ static noinline void print_cycle(struct printbuf *out, struct lock_graph *g) bch2_btree_trans_to_text(out, i->trans); } +static int abort_lock(struct lock_graph *g, struct trans_waiting_for_lock *i) +{ + if (i == g->g) { + trace_and_count(i->trans->c, trans_restart_would_deadlock, i->trans, _RET_IP_); + return btree_trans_restart(i->trans, BCH_ERR_transaction_restart_would_deadlock); + } else { + i->trans->lock_must_abort = true; + wake_up_process(i->trans->locking_wait.task); + return 1; + } +} + static noinline int break_cycle(struct lock_graph *g) { - struct btree_trans *orig_trans = g->g->trans; struct trans_waiting_for_lock *i; for (i = g->g; i < g->g + g->nr; i++) { - if (i->trans->lock_may_not_fail) + if (i->trans->lock_may_not_fail || i->trans->in_traverse_all) continue; - if (i == g->g) { - trace_and_count(orig_trans->c, trans_restart_would_deadlock, orig_trans, _RET_IP_); - return btree_trans_restart(orig_trans, BCH_ERR_transaction_restart_would_deadlock); - } + return abort_lock(g, i); + } - i->trans->lock_must_abort = true; - wake_up_process(i->trans->locking_wait.task); - return 1; + for (i = g->g; i < g->g + g->nr; i++) { + if (i->trans->lock_may_not_fail) + continue; + + return abort_lock(g, i); } BUG(); |