]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bcachefs: Fix bch2_btree_path_traverse_cached() when paths realloced
authorKent Overstreet <kent.overstreet@linux.dev>
Sat, 17 May 2025 22:37:02 +0000 (18:37 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sat, 17 May 2025 22:46:17 +0000 (18:46 -0400)
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>
fs/bcachefs/btree_iter.c
fs/bcachefs/btree_key_cache.c
fs/bcachefs/btree_key_cache.h

index a873ec1baf581cad2cf6a6561b094dbe63683571..ac5f2046550da3244320376b0d36cf4ac73a2006 100644 (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;
        }
 
index 2b186584a291bbd601e29c2990014b0f17b9c70c..669825f89cdd849c5ac4e3b6713b18689c284b96 100644 (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;
 }
 
index 51d6289b8dee3205ee5e8f8292906a588c92d1c0..82d8c72512a93a568b62268ce1cb63be385b1db0 100644 (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 *);