summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2025-06-24 15:55:40 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2025-07-05 12:42:42 -0400
commit75b7fbdd86d31d4735c06984f2c50d4186a912ff (patch)
treebabcb522fa1a7c55ae515d21e4eb9d1526d7803f
parentaea02d5cad44d93735a9200a141e1dc7d41eddf2 (diff)
bcachefs: Don't peek key cache unless we have a real key
We require that if a key exists in the key cache it also be present in the underlying btree, for cache coherency reasons. So checking the key cache on whiteout is unnecessary. This is part of fixing a major performance bug when doing many unlinks all in a row - we end up scanning through a ton of key cache whiteouts before peek() can return a real key. Reported-by: John Schoenick <johns@valvesoftware.com> Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--fs/bcachefs/btree_iter.c18
1 files changed, 10 insertions, 8 deletions
diff --git a/fs/bcachefs/btree_iter.c b/fs/bcachefs/btree_iter.c
index d7dc7a25b95d..87d98a5cb02a 100644
--- a/fs/bcachefs/btree_iter.c
+++ b/fs/bcachefs/btree_iter.c
@@ -2288,6 +2288,7 @@ static struct bkey_s_c __bch2_btree_iter_peek(struct btree_trans *trans, struct
if (unlikely(iter->flags & BTREE_ITER_with_key_cache) &&
k.k &&
+ !bkey_deleted(k.k) &&
(k2 = btree_trans_peek_key_cache(trans, iter, k.k->p)).k) {
k = k2;
if (bkey_err(k)) {
@@ -2580,6 +2581,7 @@ static struct bkey_s_c __bch2_btree_iter_peek_prev(struct btree_trans *trans, st
if (unlikely(iter->flags & BTREE_ITER_with_key_cache) &&
k.k &&
+ !bkey_deleted(k.k) &&
(k2 = btree_trans_peek_key_cache(trans, iter, k.k->p)).k) {
k = k2;
if (bkey_err(k2)) {
@@ -2795,7 +2797,7 @@ struct bkey_s_c bch2_btree_iter_prev(struct btree_trans *trans, struct btree_ite
struct bkey_s_c bch2_btree_iter_peek_slot(struct btree_trans *trans, struct btree_iter *iter)
{
struct bpos search_key;
- struct bkey_s_c k;
+ struct bkey_s_c k, k2;
int ret;
bch2_trans_verify_not_unlocked_or_in_restart(trans);
@@ -2854,18 +2856,18 @@ struct bkey_s_c bch2_btree_iter_peek_slot(struct btree_trans *trans, struct btre
(k = btree_trans_peek_slot_journal(trans, iter)).k)
goto out;
+ k = bch2_btree_path_peek_slot(btree_iter_path(trans, iter), &iter->k);
+ if (unlikely(!k.k))
+ goto out;
+
if (unlikely(iter->flags & BTREE_ITER_with_key_cache) &&
- (k = btree_trans_peek_key_cache(trans, iter, iter->pos)).k) {
+ !bkey_deleted(k.k) &&
+ (k2 = btree_trans_peek_key_cache(trans, iter, iter->pos)).k) {
+ k = k2;
if (!bkey_err(k))
iter->k = *k.k;
- /* We're not returning a key from iter->path: */
- goto out;
}
- k = bch2_btree_path_peek_slot(btree_iter_path(trans, iter), &iter->k);
- if (unlikely(!k.k))
- goto out;
-
if (unlikely(k.k->type == KEY_TYPE_whiteout &&
(iter->flags & BTREE_ITER_filter_snapshots) &&
!(iter->flags & BTREE_ITER_key_cache_fill)))