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: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
Kent Overstreet 2025-05-17 18:37:02 -04:00
parent 9c09e59cc5
commit 49771a7578
3 changed files with 19 additions and 11 deletions

View File

@ -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;
}

View File

@ -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 @@ err:
}
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 @@ retry:
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;
}

View File

@ -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 *);