Commit 49771a75 authored by Kent Overstreet's avatar Kent Overstreet
Browse files

bcachefs: Fix bch2_btree_path_traverse_cached() when paths realloced



btree_key_cache_fill() will allocate and traverse another path (for the
underlying btree), so we can't hold pointers to paths across a call - we
have to pass indices.

Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 9c09e59c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1162,7 +1162,7 @@ int bch2_btree_path_traverse_one(struct btree_trans *trans,
	}

	if (path->cached) {
		ret = bch2_btree_path_traverse_cached(trans, path, flags);
		ret = bch2_btree_path_traverse_cached(trans, path_idx, flags);
		goto out;
	}

+17 −8
Original line number Diff line number Diff line
@@ -301,9 +301,11 @@ static noinline_for_stack void do_trace_key_cache_fill(struct btree_trans *trans
}

static noinline int btree_key_cache_fill(struct btree_trans *trans,
					 struct btree_path *ck_path,
					 btree_path_idx_t ck_path_idx,
					 unsigned flags)
{
	struct btree_path *ck_path = trans->paths + ck_path_idx;

	if (flags & BTREE_ITER_cached_nofill) {
		ck_path->l[0].b = NULL;
		return 0;
@@ -325,6 +327,7 @@ static noinline int btree_key_cache_fill(struct btree_trans *trans,
		goto err;

	/* Recheck after btree lookup, before allocating: */
	ck_path = trans->paths + ck_path_idx;
	ret = bch2_btree_key_cache_find(c, ck_path->btree_id, ck_path->pos) ? -EEXIST : 0;
	if (unlikely(ret))
		goto out;
@@ -344,10 +347,11 @@ static noinline int btree_key_cache_fill(struct btree_trans *trans,
}

static inline int btree_path_traverse_cached_fast(struct btree_trans *trans,
						  struct btree_path *path)
						  btree_path_idx_t path_idx)
{
	struct bch_fs *c = trans->c;
	struct bkey_cached *ck;
	struct btree_path *path = trans->paths + path_idx;
retry:
	ck = bch2_btree_key_cache_find(c, path->btree_id, path->pos);
	if (!ck)
@@ -373,27 +377,32 @@ static inline int btree_path_traverse_cached_fast(struct btree_trans *trans,
	return 0;
}

int bch2_btree_path_traverse_cached(struct btree_trans *trans, struct btree_path *path,
int bch2_btree_path_traverse_cached(struct btree_trans *trans,
				    btree_path_idx_t path_idx,
				    unsigned flags)
{
	EBUG_ON(path->level);

	path->l[1].b = NULL;
	EBUG_ON(trans->paths[path_idx].level);

	int ret;
	do {
		ret = btree_path_traverse_cached_fast(trans, path);
		ret = btree_path_traverse_cached_fast(trans, path_idx);
		if (unlikely(ret == -ENOENT))
			ret = btree_key_cache_fill(trans, path, flags);
			ret = btree_key_cache_fill(trans, path_idx, flags);
	} while (ret == -EEXIST);

	struct btree_path *path = trans->paths + path_idx;

	if (unlikely(ret)) {
		path->uptodate = BTREE_ITER_NEED_TRAVERSE;
		if (!bch2_err_matches(ret, BCH_ERR_transaction_restart)) {
			btree_node_unlock(trans, path, 0);
			path->l[0].b = ERR_PTR(ret);
		}
	} else {
		BUG_ON(path->uptodate);
		BUG_ON(!path->nodes_locked);
	}

	return ret;
}

+1 −2
Original line number Diff line number Diff line
@@ -40,8 +40,7 @@ int bch2_btree_key_cache_journal_flush(struct journal *,
struct bkey_cached *
bch2_btree_key_cache_find(struct bch_fs *, enum btree_id, struct bpos);

int bch2_btree_path_traverse_cached(struct btree_trans *, struct btree_path *,
				    unsigned);
int bch2_btree_path_traverse_cached(struct btree_trans *, btree_path_idx_t, unsigned);

bool bch2_btree_insert_key_cached(struct btree_trans *, unsigned,
			struct btree_insert_entry *);