Commit 32ed4a62 authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet

bcachefs: Btree path tracepoints

Fastpath tracepoints, rarely needed, only enabled with
CONFIG_BCACHEFS_PATH_TRACEPOINTS.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent abbfc4db
...@@ -87,6 +87,13 @@ config BCACHEFS_SIX_OPTIMISTIC_SPIN ...@@ -87,6 +87,13 @@ config BCACHEFS_SIX_OPTIMISTIC_SPIN
is held by another thread, spin for a short while, as long as the is held by another thread, spin for a short while, as long as the
thread owning the lock is running. thread owning the lock is running.
config BCACHEFS_PATH_TRACEPOINTS
bool "Extra btree_path tracepoints"
depends on BCACHEFS_FS
help
Enable extra tracepoints for debugging btree_path operations; we don't
normally want these enabled because they happen at very high rates.
config MEAN_AND_VARIANCE_UNIT_TEST config MEAN_AND_VARIANCE_UNIT_TEST
tristate "mean_and_variance unit tests" if !KUNIT_ALL_TESTS tristate "mean_and_variance unit tests" if !KUNIT_ALL_TESTS
depends on KUNIT depends on KUNIT
......
...@@ -1131,6 +1131,8 @@ int bch2_btree_path_traverse_one(struct btree_trans *trans, ...@@ -1131,6 +1131,8 @@ int bch2_btree_path_traverse_one(struct btree_trans *trans,
if (unlikely(!trans->srcu_held)) if (unlikely(!trans->srcu_held))
bch2_trans_srcu_lock(trans); bch2_trans_srcu_lock(trans);
trace_btree_path_traverse_start(trans, path);
/* /*
* Ensure we obey path->should_be_locked: if it's set, we can't unlock * Ensure we obey path->should_be_locked: if it's set, we can't unlock
* and re-traverse the path without a transaction restart: * and re-traverse the path without a transaction restart:
...@@ -1194,6 +1196,7 @@ int bch2_btree_path_traverse_one(struct btree_trans *trans, ...@@ -1194,6 +1196,7 @@ int bch2_btree_path_traverse_one(struct btree_trans *trans,
out_uptodate: out_uptodate:
path->uptodate = BTREE_ITER_UPTODATE; path->uptodate = BTREE_ITER_UPTODATE;
trace_btree_path_traverse_end(trans, path);
out: out:
if (bch2_err_matches(ret, BCH_ERR_transaction_restart) != !!trans->restarted) if (bch2_err_matches(ret, BCH_ERR_transaction_restart) != !!trans->restarted)
panic("ret %s (%i) trans->restarted %s (%i)\n", panic("ret %s (%i) trans->restarted %s (%i)\n",
...@@ -1236,8 +1239,10 @@ __flatten ...@@ -1236,8 +1239,10 @@ __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)
{ {
struct btree_path *old = trans->paths + path;
__btree_path_put(trans, 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);
trace_btree_path_clone(trans, old, trans->paths + path);
trans->paths[path].preserve = false; trans->paths[path].preserve = false;
return path; return path;
} }
...@@ -1252,6 +1257,8 @@ __bch2_btree_path_set_pos(struct btree_trans *trans, ...@@ -1252,6 +1257,8 @@ __bch2_btree_path_set_pos(struct btree_trans *trans,
bch2_trans_verify_not_in_restart(trans); bch2_trans_verify_not_in_restart(trans);
EBUG_ON(!trans->paths[path_idx].ref); EBUG_ON(!trans->paths[path_idx].ref);
trace_btree_path_set_pos(trans, trans->paths + path_idx, &new_pos);
path_idx = bch2_btree_path_make_mut(trans, path_idx, intent, ip); path_idx = bch2_btree_path_make_mut(trans, path_idx, intent, ip);
struct btree_path *path = trans->paths + path_idx; struct btree_path *path = trans->paths + path_idx;
...@@ -1368,6 +1375,8 @@ void bch2_path_put(struct btree_trans *trans, btree_path_idx_t path_idx, bool in ...@@ -1368,6 +1375,8 @@ void bch2_path_put(struct btree_trans *trans, btree_path_idx_t path_idx, bool in
? have_path_at_pos(trans, path) ? have_path_at_pos(trans, path)
: have_node_at_pos(trans, path); : have_node_at_pos(trans, path);
trace_btree_path_free(trans, path_idx, dup);
if (!dup && !(!path->preserve && !is_btree_node(path, path->level))) if (!dup && !(!path->preserve && !is_btree_node(path, path->level)))
return; return;
...@@ -1421,8 +1430,8 @@ void __noreturn bch2_trans_unlocked_error(struct btree_trans *trans) ...@@ -1421,8 +1430,8 @@ void __noreturn bch2_trans_unlocked_error(struct btree_trans *trans)
noinline __cold noinline __cold
void bch2_trans_updates_to_text(struct printbuf *buf, struct btree_trans *trans) void bch2_trans_updates_to_text(struct printbuf *buf, struct btree_trans *trans)
{ {
prt_printf(buf, "transaction updates for %s journal seq %llu\n", prt_printf(buf, "%u transaction updates for %s journal seq %llu\n",
trans->fn, trans->journal_res.seq); trans->nr_updates, trans->fn, trans->journal_res.seq);
printbuf_indent_add(buf, 2); printbuf_indent_add(buf, 2);
trans_for_each_update(trans, i) { trans_for_each_update(trans, i) {
...@@ -1464,7 +1473,7 @@ static void bch2_btree_path_to_text_short(struct printbuf *out, struct btree_tra ...@@ -1464,7 +1473,7 @@ static void bch2_btree_path_to_text_short(struct printbuf *out, struct btree_tra
{ {
struct btree_path *path = trans->paths + path_idx; struct btree_path *path = trans->paths + path_idx;
prt_printf(out, "path: idx %2u ref %u:%u %c %c %c btree=%s l=%u pos ", prt_printf(out, "path: idx %3u ref %u:%u %c %c %c btree=%s l=%u pos ",
path_idx, path->ref, path->intent_ref, path_idx, path->ref, path->intent_ref,
path->preserve ? 'P' : ' ', path->preserve ? 'P' : ' ',
path->should_be_locked ? 'S' : ' ', path->should_be_locked ? 'S' : ' ',
...@@ -1716,6 +1725,8 @@ btree_path_idx_t bch2_path_get(struct btree_trans *trans, ...@@ -1716,6 +1725,8 @@ 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) {
trace_btree_path_get(trans, trans->paths + path_pos, &pos);
__btree_path_get(trans, 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;
...@@ -1738,6 +1749,8 @@ btree_path_idx_t bch2_path_get(struct btree_trans *trans, ...@@ -1738,6 +1749,8 @@ btree_path_idx_t bch2_path_get(struct btree_trans *trans,
path->ip_allocated = ip; path->ip_allocated = ip;
#endif #endif
trans->paths_sorted = false; trans->paths_sorted = false;
trace_btree_path_alloc(trans, path);
} }
if (!(flags & BTREE_ITER_nopreserve)) if (!(flags & BTREE_ITER_nopreserve))
...@@ -1857,7 +1870,7 @@ bch2_btree_iter_traverse(struct btree_iter *iter) ...@@ -1857,7 +1870,7 @@ bch2_btree_iter_traverse(struct btree_iter *iter)
struct btree_path *path = btree_iter_path(trans, iter); struct btree_path *path = btree_iter_path(trans, iter);
if (btree_path_node(path, path->level)) if (btree_path_node(path, path->level))
btree_path_set_should_be_locked(path); btree_path_set_should_be_locked(trans, path);
return 0; return 0;
} }
...@@ -1889,7 +1902,7 @@ struct btree *bch2_btree_iter_peek_node(struct btree_iter *iter) ...@@ -1889,7 +1902,7 @@ struct btree *bch2_btree_iter_peek_node(struct btree_iter *iter)
iter->path = bch2_btree_path_set_pos(trans, iter->path, b->key.k.p, iter->path = bch2_btree_path_set_pos(trans, iter->path, b->key.k.p,
iter->flags & BTREE_ITER_intent, iter->flags & BTREE_ITER_intent,
btree_iter_ip_allocated(iter)); btree_iter_ip_allocated(iter));
btree_path_set_should_be_locked(btree_iter_path(trans, iter)); btree_path_set_should_be_locked(trans, btree_iter_path(trans, iter));
out: out:
bch2_btree_iter_verify_entry_exit(iter); bch2_btree_iter_verify_entry_exit(iter);
bch2_btree_iter_verify(iter); bch2_btree_iter_verify(iter);
...@@ -1983,7 +1996,7 @@ struct btree *bch2_btree_iter_next_node(struct btree_iter *iter) ...@@ -1983,7 +1996,7 @@ struct btree *bch2_btree_iter_next_node(struct btree_iter *iter)
iter->path = bch2_btree_path_set_pos(trans, iter->path, b->key.k.p, iter->path = bch2_btree_path_set_pos(trans, iter->path, b->key.k.p,
iter->flags & BTREE_ITER_intent, iter->flags & BTREE_ITER_intent,
btree_iter_ip_allocated(iter)); btree_iter_ip_allocated(iter));
btree_path_set_should_be_locked(btree_iter_path(trans, iter)); btree_path_set_should_be_locked(trans, btree_iter_path(trans, iter));
EBUG_ON(btree_iter_path(trans, iter)->uptodate); EBUG_ON(btree_iter_path(trans, iter)->uptodate);
out: out:
bch2_btree_iter_verify_entry_exit(iter); bch2_btree_iter_verify_entry_exit(iter);
...@@ -2155,7 +2168,7 @@ struct bkey_s_c btree_trans_peek_key_cache(struct btree_iter *iter, struct bpos ...@@ -2155,7 +2168,7 @@ struct bkey_s_c btree_trans_peek_key_cache(struct btree_iter *iter, struct bpos
if (unlikely(ret)) if (unlikely(ret))
return bkey_s_c_err(ret); return bkey_s_c_err(ret);
btree_path_set_should_be_locked(trans->paths + iter->key_cache_path); btree_path_set_should_be_locked(trans, trans->paths + iter->key_cache_path);
k = bch2_btree_path_peek_slot(trans->paths + iter->key_cache_path, &u); k = bch2_btree_path_peek_slot(trans->paths + iter->key_cache_path, &u);
if (k.k && !bkey_err(k)) { if (k.k && !bkey_err(k)) {
...@@ -2199,7 +2212,7 @@ static struct bkey_s_c __bch2_btree_iter_peek(struct btree_iter *iter, struct bp ...@@ -2199,7 +2212,7 @@ static struct bkey_s_c __bch2_btree_iter_peek(struct btree_iter *iter, struct bp
goto out; goto out;
} }
btree_path_set_should_be_locked(path); btree_path_set_should_be_locked(trans, path);
k = btree_path_level_peek_all(trans->c, l, &iter->k); k = btree_path_level_peek_all(trans->c, l, &iter->k);
...@@ -2382,14 +2395,14 @@ struct bkey_s_c bch2_btree_iter_peek_upto(struct btree_iter *iter, struct bpos e ...@@ -2382,14 +2395,14 @@ struct bkey_s_c bch2_btree_iter_peek_upto(struct btree_iter *iter, struct bpos e
iter->flags & BTREE_ITER_intent, iter->flags & BTREE_ITER_intent,
btree_iter_ip_allocated(iter)); btree_iter_ip_allocated(iter));
btree_path_set_should_be_locked(btree_iter_path(trans, iter)); btree_path_set_should_be_locked(trans, btree_iter_path(trans, iter));
out_no_locked: out_no_locked:
if (iter->update_path) { if (iter->update_path) {
ret = bch2_btree_path_relock(trans, trans->paths + iter->update_path, _THIS_IP_); ret = bch2_btree_path_relock(trans, trans->paths + iter->update_path, _THIS_IP_);
if (unlikely(ret)) if (unlikely(ret))
k = bkey_s_c_err(ret); k = bkey_s_c_err(ret);
else else
btree_path_set_should_be_locked(trans->paths + iter->update_path); btree_path_set_should_be_locked(trans, trans->paths + iter->update_path);
} }
if (!(iter->flags & BTREE_ITER_all_snapshots)) if (!(iter->flags & BTREE_ITER_all_snapshots))
...@@ -2511,6 +2524,7 @@ struct bkey_s_c bch2_btree_iter_peek_prev(struct btree_iter *iter) ...@@ -2511,6 +2524,7 @@ struct bkey_s_c bch2_btree_iter_peek_prev(struct btree_iter *iter)
iter->flags & BTREE_ITER_intent, iter->flags & BTREE_ITER_intent,
_THIS_IP_); _THIS_IP_);
path = btree_iter_path(trans, iter); path = btree_iter_path(trans, iter);
trace_btree_path_save_pos(trans, path, trans->paths + saved_path);
saved_k = *k.k; saved_k = *k.k;
saved_v = k.v; saved_v = k.v;
} }
...@@ -2527,7 +2541,7 @@ struct bkey_s_c bch2_btree_iter_peek_prev(struct btree_iter *iter) ...@@ -2527,7 +2541,7 @@ struct bkey_s_c bch2_btree_iter_peek_prev(struct btree_iter *iter)
continue; continue;
} }
btree_path_set_should_be_locked(path); btree_path_set_should_be_locked(trans, path);
break; break;
} else if (likely(!bpos_eq(path->l[0].b->data->min_key, POS_MIN))) { } else if (likely(!bpos_eq(path->l[0].b->data->min_key, POS_MIN))) {
/* Advance to previous leaf node: */ /* Advance to previous leaf node: */
...@@ -2685,7 +2699,7 @@ struct bkey_s_c bch2_btree_iter_peek_slot(struct btree_iter *iter) ...@@ -2685,7 +2699,7 @@ struct bkey_s_c bch2_btree_iter_peek_slot(struct btree_iter *iter)
} }
} }
out: out:
btree_path_set_should_be_locked(btree_iter_path(trans, iter)); btree_path_set_should_be_locked(trans, btree_iter_path(trans, iter));
out_no_locked: out_no_locked:
bch2_btree_iter_verify_entry_exit(iter); bch2_btree_iter_verify_entry_exit(iter);
bch2_btree_iter_verify(iter); bch2_btree_iter_verify(iter);
......
...@@ -31,6 +31,7 @@ static inline void __btree_path_get(struct btree_trans *trans, struct btree_path ...@@ -31,6 +31,7 @@ static inline void __btree_path_get(struct btree_trans *trans, struct btree_path
path->ref++; path->ref++;
path->intent_ref += intent; path->intent_ref += intent;
trace_btree_path_get_ll(trans, path);
} }
static inline bool __btree_path_put(struct btree_trans *trans, struct btree_path *path, bool intent) static inline bool __btree_path_put(struct btree_trans *trans, struct btree_path *path, bool intent)
...@@ -39,6 +40,7 @@ static inline bool __btree_path_put(struct btree_trans *trans, struct btree_path ...@@ -39,6 +40,7 @@ static inline bool __btree_path_put(struct btree_trans *trans, struct btree_path
EBUG_ON(!path->ref); EBUG_ON(!path->ref);
EBUG_ON(!path->intent_ref && intent); EBUG_ON(!path->intent_ref && intent);
trace_btree_path_put_ll(trans, path);
path->intent_ref -= intent; path->intent_ref -= intent;
return --path->ref == 0; return --path->ref == 0;
} }
......
...@@ -228,6 +228,9 @@ static inline int __btree_node_lock_nopath(struct btree_trans *trans, ...@@ -228,6 +228,9 @@ static inline int __btree_node_lock_nopath(struct btree_trans *trans,
bch2_six_check_for_deadlock, trans, ip); bch2_six_check_for_deadlock, trans, ip);
WRITE_ONCE(trans->locking, NULL); WRITE_ONCE(trans->locking, NULL);
WRITE_ONCE(trans->locking_wait.start_time, 0); WRITE_ONCE(trans->locking_wait.start_time, 0);
if (!ret)
trace_btree_path_lock(trans, _THIS_IP_, b);
return ret; return ret;
} }
...@@ -400,12 +403,13 @@ static inline int bch2_btree_path_upgrade(struct btree_trans *trans, ...@@ -400,12 +403,13 @@ static inline int bch2_btree_path_upgrade(struct btree_trans *trans,
/* misc: */ /* misc: */
static inline void btree_path_set_should_be_locked(struct btree_path *path) static inline void btree_path_set_should_be_locked(struct btree_trans *trans, struct btree_path *path)
{ {
EBUG_ON(!btree_node_locked(path, path->level)); EBUG_ON(!btree_node_locked(path, path->level));
EBUG_ON(path->uptodate); EBUG_ON(path->uptodate);
path->should_be_locked = true; path->should_be_locked = true;
trace_btree_path_should_be_locked(trans, path);
} }
static inline void __btree_path_set_level_up(struct btree_trans *trans, static inline void __btree_path_set_level_up(struct btree_trans *trans,
......
...@@ -374,7 +374,7 @@ static noinline int flush_new_cached_update(struct btree_trans *trans, ...@@ -374,7 +374,7 @@ static noinline int flush_new_cached_update(struct btree_trans *trans,
i->key_cache_already_flushed = true; i->key_cache_already_flushed = true;
i->flags |= BTREE_TRIGGER_norun; i->flags |= BTREE_TRIGGER_norun;
btree_path_set_should_be_locked(btree_path); btree_path_set_should_be_locked(trans, btree_path);
ret = bch2_trans_update_by_path(trans, path_idx, i->k, flags, ip); ret = bch2_trans_update_by_path(trans, path_idx, i->k, flags, ip);
out: out:
bch2_path_put(trans, path_idx, true); bch2_path_put(trans, path_idx, true);
...@@ -422,7 +422,9 @@ bch2_trans_update_by_path(struct btree_trans *trans, btree_path_idx_t path_idx, ...@@ -422,7 +422,9 @@ bch2_trans_update_by_path(struct btree_trans *trans, btree_path_idx_t path_idx,
break; break;
} }
if (!cmp && i < trans->updates + trans->nr_updates) { bool overwrite = !cmp && i < trans->updates + trans->nr_updates;
if (overwrite) {
EBUG_ON(i->insert_trigger_run || i->overwrite_trigger_run); EBUG_ON(i->insert_trigger_run || i->overwrite_trigger_run);
bch2_path_put(trans, i->path, true); bch2_path_put(trans, i->path, true);
...@@ -451,6 +453,8 @@ bch2_trans_update_by_path(struct btree_trans *trans, btree_path_idx_t path_idx, ...@@ -451,6 +453,8 @@ bch2_trans_update_by_path(struct btree_trans *trans, btree_path_idx_t path_idx,
__btree_path_get(trans, trans->paths + i->path, true); __btree_path_get(trans, trans->paths + i->path, true);
trace_update_by_path(trans, path, i, overwrite);
/* /*
* 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
* btree - this is necessary for cache coherency. When iterating over * btree - this is necessary for cache coherency. When iterating over
...@@ -498,7 +502,7 @@ static noinline int bch2_trans_update_get_key_cache(struct btree_trans *trans, ...@@ -498,7 +502,7 @@ static noinline int bch2_trans_update_get_key_cache(struct btree_trans *trans,
return btree_trans_restart(trans, BCH_ERR_transaction_restart_key_cache_raced); return btree_trans_restart(trans, BCH_ERR_transaction_restart_key_cache_raced);
} }
btree_path_set_should_be_locked(trans->paths + iter->key_cache_path); btree_path_set_should_be_locked(trans, trans->paths + iter->key_cache_path);
} }
return 0; return 0;
......
...@@ -1981,7 +1981,7 @@ int __bch2_foreground_maybe_merge(struct btree_trans *trans, ...@@ -1981,7 +1981,7 @@ int __bch2_foreground_maybe_merge(struct btree_trans *trans,
if (ret) if (ret)
goto err; goto err;
btree_path_set_should_be_locked(trans->paths + sib_path); btree_path_set_should_be_locked(trans, trans->paths + sib_path);
m = trans->paths[sib_path].l[level].b; m = trans->paths[sib_path].l[level].b;
......
This diff is collapsed.
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