Commit be9e782d authored by Kent Overstreet's avatar Kent Overstreet
Browse files

bcachefs: Don't downgrade locks on transaction restart



We should only be downgrading locks on success - otherwise, our
transaction restarts won't be getting the correct locks and we'll
livelock.

Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 2e7acdfb
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -1523,6 +1523,7 @@ static inline struct btree_path *btree_path_alloc(struct btree_trans *trans,
	path->ref		= 0;
	path->intent_ref	= 0;
	path->nodes_locked	= 0;
	path->alloc_seq++;

	btree_path_list_add(trans, pos, path);
	trans->paths_sorted = false;
@@ -1598,7 +1599,7 @@ struct btree_path *bch2_path_get(struct btree_trans *trans,

	locks_want = min(locks_want, BTREE_MAX_DEPTH);
	if (locks_want > path->locks_want)
		bch2_btree_path_upgrade_noupgrade_sibs(trans, path, locks_want);
		bch2_btree_path_upgrade_noupgrade_sibs(trans, path, locks_want, NULL);

	return path;
}
+1 −1
Original line number Diff line number Diff line
@@ -509,7 +509,7 @@ bch2_btree_path_traverse_cached_slowpath(struct btree_trans *trans, struct btree
		 * path->uptodate yet:
		 */
		if (!path->locks_want &&
		    !__bch2_btree_path_upgrade(trans, path, 1)) {
		    !__bch2_btree_path_upgrade(trans, path, 1, NULL)) {
			trace_and_count(trans->c, trans_restart_key_cache_upgrade, trans, _THIS_IP_);
			ret = btree_trans_restart(trans, BCH_ERR_transaction_restart_key_cache_upgrade);
			goto err;
+29 −9
Original line number Diff line number Diff line
@@ -431,7 +431,8 @@ void bch2_btree_node_lock_write_nofail(struct btree_trans *trans,

static inline bool btree_path_get_locks(struct btree_trans *trans,
					struct btree_path *path,
					bool upgrade)
					bool upgrade,
					struct get_locks_fail *f)
{
	unsigned l = path->level;
	int fail_idx = -1;
@@ -442,9 +443,15 @@ static inline bool btree_path_get_locks(struct btree_trans *trans,

		if (!(upgrade
		      ? bch2_btree_node_upgrade(trans, path, l)
		      : bch2_btree_node_relock(trans, path, l)))
		      : bch2_btree_node_relock(trans, path, l))) {
			fail_idx	= l;

			if (f) {
				f->l	= l;
				f->b	= path->l[l].b;
			}
		}

		l++;
	} while (l < path->locks_want);

@@ -584,7 +591,9 @@ __flatten
bool bch2_btree_path_relock_norestart(struct btree_trans *trans,
			struct btree_path *path, unsigned long trace_ip)
{
	return btree_path_get_locks(trans, path, false);
	struct get_locks_fail f;

	return btree_path_get_locks(trans, path, false, &f);
}

int __bch2_btree_path_relock(struct btree_trans *trans,
@@ -600,22 +609,24 @@ int __bch2_btree_path_relock(struct btree_trans *trans,

bool bch2_btree_path_upgrade_noupgrade_sibs(struct btree_trans *trans,
			       struct btree_path *path,
			       unsigned new_locks_want)
			       unsigned new_locks_want,
			       struct get_locks_fail *f)
{
	EBUG_ON(path->locks_want >= new_locks_want);

	path->locks_want = new_locks_want;

	return btree_path_get_locks(trans, path, true);
	return btree_path_get_locks(trans, path, true, f);
}

bool __bch2_btree_path_upgrade(struct btree_trans *trans,
			       struct btree_path *path,
			       unsigned new_locks_want)
			       unsigned new_locks_want,
			       struct get_locks_fail *f)
{
	struct btree_path *linked;

	if (bch2_btree_path_upgrade_noupgrade_sibs(trans, path, new_locks_want))
	if (bch2_btree_path_upgrade_noupgrade_sibs(trans, path, new_locks_want, f))
		return true;

	/*
@@ -644,7 +655,7 @@ bool __bch2_btree_path_upgrade(struct btree_trans *trans,
			    linked->btree_id == path->btree_id &&
			    linked->locks_want < new_locks_want) {
				linked->locks_want = new_locks_want;
				btree_path_get_locks(trans, linked, true);
				btree_path_get_locks(trans, linked, true, NULL);
			}

	return false;
@@ -656,6 +667,9 @@ void __bch2_btree_path_downgrade(struct btree_trans *trans,
{
	unsigned l;

	if (trans->restarted)
		return;

	EBUG_ON(path->locks_want < new_locks_want);

	path->locks_want = new_locks_want;
@@ -674,6 +688,9 @@ void __bch2_btree_path_downgrade(struct btree_trans *trans,
	}

	bch2_btree_path_verify_locks(path);

	path->downgrade_seq++;
	trace_path_downgrade(trans, _RET_IP_, path);
}

/* Btree transaction locking: */
@@ -682,6 +699,9 @@ void bch2_trans_downgrade(struct btree_trans *trans)
{
	struct btree_path *path;

	if (trans->restarted)
		return;

	trans_for_each_path(trans, path)
		bch2_btree_path_downgrade(trans, path);
}
+14 −4
Original line number Diff line number Diff line
@@ -355,26 +355,36 @@ static inline bool bch2_btree_node_relock_notrace(struct btree_trans *trans,

/* upgrade */


struct get_locks_fail {
	unsigned	l;
	struct btree	*b;
};

bool bch2_btree_path_upgrade_noupgrade_sibs(struct btree_trans *,
			       struct btree_path *, unsigned);
			       struct btree_path *, unsigned,
			       struct get_locks_fail *);

bool __bch2_btree_path_upgrade(struct btree_trans *,
			       struct btree_path *, unsigned);
			       struct btree_path *, unsigned,
			       struct get_locks_fail *);

static inline int bch2_btree_path_upgrade(struct btree_trans *trans,
					  struct btree_path *path,
					  unsigned new_locks_want)
{
	struct get_locks_fail f;
	unsigned old_locks_want = path->locks_want;

	new_locks_want = min(new_locks_want, BTREE_MAX_DEPTH);

	if (path->locks_want < new_locks_want
	    ? __bch2_btree_path_upgrade(trans, path, new_locks_want)
	    ? __bch2_btree_path_upgrade(trans, path, new_locks_want, &f)
	    : path->uptodate == BTREE_ITER_UPTODATE)
		return 0;

	trace_and_count(trans->c, trans_restart_upgrade, trans, _THIS_IP_, path,
			old_locks_want, new_locks_want);
			old_locks_want, new_locks_want, &f);
	return btree_trans_restart(trans, BCH_ERR_transaction_restart_upgrade);
}

+3 −6
Original line number Diff line number Diff line
@@ -861,12 +861,7 @@ static inline int do_bch2_trans_commit(struct btree_trans *trans, unsigned flags
	 */
	bch2_journal_res_put(&c->journal, &trans->journal_res);

	if (unlikely(ret))
	return ret;

	bch2_trans_downgrade(trans);

	return 0;
}

static int journal_reclaim_wait_done(struct bch_fs *c)
@@ -1135,6 +1130,8 @@ int __bch2_trans_commit(struct btree_trans *trans, unsigned flags)
	if (likely(!(flags & BTREE_INSERT_NOCHECK_RW)))
		bch2_write_ref_put(c, BCH_WRITE_REF_trans);
out_reset:
	if (!ret)
		bch2_trans_downgrade(trans);
	bch2_trans_reset_updates(trans);

	return ret;
Loading