Commit abbfc4db authored by Kent Overstreet's avatar Kent Overstreet

bcachefs: Add check for btree_path ref overflow

Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 094c6a9f
...@@ -1010,9 +1010,9 @@ static int bch2_btree_path_traverse_all(struct btree_trans *trans) ...@@ -1010,9 +1010,9 @@ static int bch2_btree_path_traverse_all(struct btree_trans *trans)
* the same position: * the same position:
*/ */
if (trans->paths[idx].uptodate) { 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_); 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) || if (bch2_err_matches(ret, BCH_ERR_transaction_restart) ||
bch2_err_matches(ret, ENOMEM)) bch2_err_matches(ret, ENOMEM))
...@@ -1225,7 +1225,7 @@ static btree_path_idx_t btree_path_clone(struct btree_trans *trans, btree_path_i ...@@ -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_idx_t new = btree_path_alloc(trans, src);
btree_path_copy(trans, trans->paths + new, trans->paths + 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 #ifdef TRACK_PATH_ALLOCATED
trans->paths[new].ip_allocated = ip; trans->paths[new].ip_allocated = ip;
#endif #endif
...@@ -1236,7 +1236,7 @@ __flatten ...@@ -1236,7 +1236,7 @@ __flatten
btree_path_idx_t __bch2_btree_path_make_mut(struct btree_trans *trans, 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_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); path = btree_path_clone(trans, path, intent, ip);
trans->paths[path].preserve = false; trans->paths[path].preserve = false;
return path; return path;
...@@ -1361,7 +1361,7 @@ void bch2_path_put(struct btree_trans *trans, btree_path_idx_t path_idx, bool in ...@@ -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; struct btree_path *path = trans->paths + path_idx, *dup;
if (!__btree_path_put(path, intent)) if (!__btree_path_put(trans, path, intent))
return; return;
dup = path->preserve dup = path->preserve
...@@ -1392,7 +1392,7 @@ void bch2_path_put(struct btree_trans *trans, btree_path_idx_t path_idx, bool in ...@@ -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, static void bch2_path_put_nokeep(struct btree_trans *trans, btree_path_idx_t path,
bool intent) bool intent)
{ {
if (!__btree_path_put(trans->paths + path, intent)) if (!__btree_path_put(trans, trans->paths + path, intent))
return; return;
__bch2_path_free(trans, path); __bch2_path_free(trans, path);
...@@ -1716,14 +1716,14 @@ btree_path_idx_t bch2_path_get(struct btree_trans *trans, ...@@ -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].cached == cached &&
trans->paths[path_pos].btree_id == btree_id && trans->paths[path_pos].btree_id == btree_id &&
trans->paths[path_pos].level == level) { 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_idx = bch2_btree_path_set_pos(trans, path_pos, pos, intent, ip);
path = trans->paths + path_idx; path = trans->paths + path_idx;
} else { } else {
path_idx = btree_path_alloc(trans, path_pos); path_idx = btree_path_alloc(trans, path_pos);
path = trans->paths + path_idx; path = trans->paths + path_idx;
__btree_path_get(path, intent); __btree_path_get(trans, path, intent);
path->pos = pos; path->pos = pos;
path->btree_id = btree_id; path->btree_id = btree_id;
path->cached = cached; path->cached = cached;
...@@ -2326,7 +2326,7 @@ struct bkey_s_c bch2_btree_iter_peek_upto(struct btree_iter *iter, struct bpos e ...@@ -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 * advance, same as on exit for iter->path, but only up
* to snapshot * 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 = iter->path;
iter->update_path = bch2_btree_path_set_pos(trans, 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) ...@@ -2911,9 +2911,9 @@ void bch2_trans_copy_iter(struct btree_iter *dst, struct btree_iter *src)
dst->ip_allocated = _RET_IP_; dst->ip_allocated = _RET_IP_;
#endif #endif
if (src->path) 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) 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; dst->key_cache_path = 0;
} }
...@@ -3237,7 +3237,7 @@ void bch2_trans_put(struct btree_trans *trans) ...@@ -3237,7 +3237,7 @@ void bch2_trans_put(struct btree_trans *trans)
bch2_trans_unlock(trans); bch2_trans_unlock(trans);
trans_for_each_update(trans, i) 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; trans->nr_updates = 0;
check_btree_paths_leaked(trans); check_btree_paths_leaked(trans);
......
...@@ -6,6 +6,12 @@ ...@@ -6,6 +6,12 @@
#include "btree_types.h" #include "btree_types.h"
#include "trace.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) static inline int __bkey_err(const struct bkey *k)
{ {
return PTR_ERR_OR_ZERO(k); return PTR_ERR_OR_ZERO(k);
...@@ -13,16 +19,26 @@ static inline int __bkey_err(const struct bkey *k) ...@@ -13,16 +19,26 @@ static inline int __bkey_err(const struct bkey *k)
#define bkey_err(_k) __bkey_err((_k).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->ref++;
path->intent_ref += intent; 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->ref);
EBUG_ON(!path->intent_ref && intent); EBUG_ON(!path->intent_ref && intent);
path->intent_ref -= intent; path->intent_ref -= intent;
return --path->ref == 0; return --path->ref == 0;
} }
...@@ -894,12 +910,6 @@ __bch2_btree_iter_peek_and_restart(struct btree_trans *trans, ...@@ -894,12 +910,6 @@ __bch2_btree_iter_peek_and_restart(struct btree_trans *trans,
_ret; \ _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); struct btree_trans *__bch2_trans_get(struct bch_fs *, unsigned);
void bch2_trans_put(struct btree_trans *); void bch2_trans_put(struct btree_trans *);
......
...@@ -449,7 +449,7 @@ bch2_trans_update_by_path(struct btree_trans *trans, btree_path_idx_t path_idx, ...@@ -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 * If a key is present in the key cache, it must also exist in the
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment