bcachefs: Add check for btree_path ref overflow
authorKent Overstreet <kent.overstreet@linux.dev>
Tue, 16 Jul 2024 21:23:10 +0000 (17:23 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Mon, 9 Sep 2024 13:41:48 +0000 (09:41 -0400)
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/btree_iter.c
fs/bcachefs/btree_iter.h
fs/bcachefs/btree_update.c

index 2e84d22..95afa35 100644 (file)
@@ -1010,9 +1010,9 @@ retry_all:
                 * the same position:
                 */
                if (trans->paths[idx].uptodate) {
-                       __btree_path_get(&trans->paths[idx], false);
+                       __btree_path_get(trans, &trans->paths[idx], false);
                        ret = bch2_btree_path_traverse_one(trans, idx, 0, _THIS_IP_);
-                       __btree_path_put(&trans->paths[idx], false);
+                       __btree_path_put(trans, &trans->paths[idx], false);
 
                        if (bch2_err_matches(ret, BCH_ERR_transaction_restart) ||
                            bch2_err_matches(ret, ENOMEM))
@@ -1225,7 +1225,7 @@ static btree_path_idx_t btree_path_clone(struct btree_trans *trans, btree_path_i
 {
        btree_path_idx_t new = btree_path_alloc(trans, src);
        btree_path_copy(trans, trans->paths + new, trans->paths + src);
-       __btree_path_get(trans->paths + new, intent);
+       __btree_path_get(trans, trans->paths + new, intent);
 #ifdef TRACK_PATH_ALLOCATED
        trans->paths[new].ip_allocated = ip;
 #endif
@@ -1236,7 +1236,7 @@ __flatten
 btree_path_idx_t __bch2_btree_path_make_mut(struct btree_trans *trans,
                        btree_path_idx_t path, bool intent, unsigned long ip)
 {
-       __btree_path_put(trans->paths + path, intent);
+       __btree_path_put(trans, trans->paths + path, intent);
        path = btree_path_clone(trans, path, intent, ip);
        trans->paths[path].preserve = false;
        return path;
@@ -1361,7 +1361,7 @@ void bch2_path_put(struct btree_trans *trans, btree_path_idx_t path_idx, bool in
 {
        struct btree_path *path = trans->paths + path_idx, *dup;
 
-       if (!__btree_path_put(path, intent))
+       if (!__btree_path_put(trans, path, intent))
                return;
 
        dup = path->preserve
@@ -1392,7 +1392,7 @@ void bch2_path_put(struct btree_trans *trans, btree_path_idx_t path_idx, bool in
 static void bch2_path_put_nokeep(struct btree_trans *trans, btree_path_idx_t path,
                                 bool intent)
 {
-       if (!__btree_path_put(trans->paths + path, intent))
+       if (!__btree_path_put(trans, trans->paths + path, intent))
                return;
 
        __bch2_path_free(trans, path);
@@ -1716,14 +1716,14 @@ btree_path_idx_t bch2_path_get(struct btree_trans *trans,
            trans->paths[path_pos].cached       == cached &&
            trans->paths[path_pos].btree_id     == btree_id &&
            trans->paths[path_pos].level        == level) {
-               __btree_path_get(trans->paths + path_pos, intent);
+               __btree_path_get(trans, trans->paths + path_pos, intent);
                path_idx = bch2_btree_path_set_pos(trans, path_pos, pos, intent, ip);
                path = trans->paths + path_idx;
        } else {
                path_idx = btree_path_alloc(trans, path_pos);
                path = trans->paths + path_idx;
 
-               __btree_path_get(path, intent);
+               __btree_path_get(trans, path, intent);
                path->pos                       = pos;
                path->btree_id                  = btree_id;
                path->cached                    = cached;
@@ -2326,7 +2326,7 @@ struct bkey_s_c bch2_btree_iter_peek_upto(struct btree_iter *iter, struct bpos e
                         * advance, same as on exit for iter->path, but only up
                         * to snapshot
                         */
-                       __btree_path_get(trans->paths + iter->path, iter->flags & BTREE_ITER_intent);
+                       __btree_path_get(trans, trans->paths + iter->path, iter->flags & BTREE_ITER_intent);
                        iter->update_path = iter->path;
 
                        iter->update_path = bch2_btree_path_set_pos(trans,
@@ -2911,9 +2911,9 @@ void bch2_trans_copy_iter(struct btree_iter *dst, struct btree_iter *src)
        dst->ip_allocated = _RET_IP_;
 #endif
        if (src->path)
-               __btree_path_get(trans->paths + src->path, src->flags & BTREE_ITER_intent);
+               __btree_path_get(trans, trans->paths + src->path, src->flags & BTREE_ITER_intent);
        if (src->update_path)
-               __btree_path_get(trans->paths + src->update_path, src->flags & BTREE_ITER_intent);
+               __btree_path_get(trans, trans->paths + src->update_path, src->flags & BTREE_ITER_intent);
        dst->key_cache_path = 0;
 }
 
@@ -3237,7 +3237,7 @@ void bch2_trans_put(struct btree_trans *trans)
        bch2_trans_unlock(trans);
 
        trans_for_each_update(trans, i)
-               __btree_path_put(trans->paths + i->path, true);
+               __btree_path_put(trans, trans->paths + i->path, true);
        trans->nr_updates       = 0;
 
        check_btree_paths_leaked(trans);
index 222b7ce..9289931 100644 (file)
@@ -6,6 +6,12 @@
 #include "btree_types.h"
 #include "trace.h"
 
+void bch2_trans_updates_to_text(struct printbuf *, struct btree_trans *);
+void bch2_btree_path_to_text(struct printbuf *, struct btree_trans *, btree_path_idx_t);
+void bch2_trans_paths_to_text(struct printbuf *, struct btree_trans *);
+void bch2_dump_trans_updates(struct btree_trans *);
+void bch2_dump_trans_paths_updates(struct btree_trans *);
+
 static inline int __bkey_err(const struct bkey *k)
 {
        return PTR_ERR_OR_ZERO(k);
@@ -13,16 +19,26 @@ static inline int __bkey_err(const struct bkey *k)
 
 #define bkey_err(_k)   __bkey_err((_k).k)
 
-static inline void __btree_path_get(struct btree_path *path, bool intent)
+static inline void __btree_path_get(struct btree_trans *trans, struct btree_path *path, bool intent)
 {
+       unsigned idx = path - trans->paths;
+
+       EBUG_ON(!test_bit(idx, trans->paths_allocated));
+       if (unlikely(path->ref == U8_MAX)) {
+               bch2_dump_trans_paths_updates(trans);
+               panic("path %u refcount overflow\n", idx);
+       }
+
        path->ref++;
        path->intent_ref += intent;
 }
 
-static inline bool __btree_path_put(struct btree_path *path, bool intent)
+static inline bool __btree_path_put(struct btree_trans *trans, struct btree_path *path, bool intent)
 {
+       EBUG_ON(!test_bit(path - trans->paths, trans->paths_allocated));
        EBUG_ON(!path->ref);
        EBUG_ON(!path->intent_ref && intent);
+
        path->intent_ref -= intent;
        return --path->ref == 0;
 }
@@ -894,12 +910,6 @@ __bch2_btree_iter_peek_and_restart(struct btree_trans *trans,
        _ret;                                                           \
 })
 
-void bch2_trans_updates_to_text(struct printbuf *, struct btree_trans *);
-void bch2_btree_path_to_text(struct printbuf *, struct btree_trans *, btree_path_idx_t);
-void bch2_trans_paths_to_text(struct printbuf *, struct btree_trans *);
-void bch2_dump_trans_updates(struct btree_trans *);
-void bch2_dump_trans_paths_updates(struct btree_trans *);
-
 struct btree_trans *__bch2_trans_get(struct bch_fs *, unsigned);
 void bch2_trans_put(struct btree_trans *);
 
index d6f6df1..57610c7 100644 (file)
@@ -449,7 +449,7 @@ bch2_trans_update_by_path(struct btree_trans *trans, btree_path_idx_t path_idx,
                }
        }
 
-       __btree_path_get(trans->paths + i->path, true);
+       __btree_path_get(trans, trans->paths + i->path, true);
 
        /*
         * If a key is present in the key cache, it must also exist in the