Commit b169138d authored by Alan Huang's avatar Alan Huang Committed by Kent Overstreet
Browse files

bcachefs: Only abort the transactions in the cycle



When the cycle doesn't involve the initiator of the cycle detection,
we might choose a transaction that is not involved in the cycle to abort.
It shouldn't be that since it won't break the cycle, this patch
therefore chooses the transaction in the cycle to abort.

Signed-off-by: default avatarAlan Huang <mmpgouride@gmail.com>
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 6853a5e5
Loading
Loading
Loading
Loading
+14 −7
Original line number Diff line number Diff line
@@ -130,11 +130,17 @@ static void lock_graph_down(struct lock_graph *g, struct btree_trans *trans)
	__lock_graph_down(g, trans);
}

static bool lock_graph_remove_non_waiters(struct lock_graph *g)
static bool lock_graph_remove_non_waiters(struct lock_graph *g,
					  struct trans_waiting_for_lock *from)
{
	struct trans_waiting_for_lock *i;

	for (i = g->g + 1; i < g->g + g->nr; i++)
	if (from->trans->locking != from->node_want) {
		lock_graph_pop_from(g, from);
		return true;
	}

	for (i = from + 1; i < g->g + g->nr; i++)
		if (i->trans->locking != i->node_want ||
		    i->trans->locking_wait.start_time != i[-1].lock_start_time) {
			lock_graph_pop_from(g, i);
@@ -184,13 +190,14 @@ static int btree_trans_abort_preference(struct btree_trans *trans)
	return 3;
}

static noinline int break_cycle(struct lock_graph *g, struct printbuf *cycle)
static noinline int break_cycle(struct lock_graph *g, struct printbuf *cycle,
				struct trans_waiting_for_lock *from)
{
	struct trans_waiting_for_lock *i, *abort = NULL;
	unsigned best = 0, pref;
	int ret;

	if (lock_graph_remove_non_waiters(g))
	if (lock_graph_remove_non_waiters(g, from))
		return 0;

	/* Only checking, for debugfs: */
@@ -200,7 +207,7 @@ static noinline int break_cycle(struct lock_graph *g, struct printbuf *cycle)
		goto out;
	}

	for (i = g->g; i < g->g + g->nr; i++) {
	for (i = from; i < g->g + g->nr; i++) {
		pref = btree_trans_abort_preference(i->trans);
		if (pref > best) {
			abort = i;
@@ -247,7 +254,7 @@ static int lock_graph_descend(struct lock_graph *g, struct btree_trans *trans,
	for (i = g->g; i < g->g + g->nr; i++)
		if (i->trans == trans) {
			closure_put(&trans->ref);
			return break_cycle(g, cycle);
			return break_cycle(g, cycle, i);
		}

	if (g->nr == ARRAY_SIZE(g->g)) {
@@ -339,7 +346,7 @@ int bch2_check_for_deadlock(struct btree_trans *trans, struct printbuf *cycle)
				 * structures - which means it can't be blocked
				 * waiting on a lock:
				 */
				if (!lock_graph_remove_non_waiters(&g)) {
				if (!lock_graph_remove_non_waiters(&g, g.g)) {
					/*
					 * If lock_graph_remove_non_waiters()
					 * didn't do anything, it must be