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-03 01:20:18 -0400
commit100142f6ec4d184a3e78870a878bdd80415852d4 (patch)
treef246ed1e84e5cece89837f52b562ee5bb448d21e
parent11b492c6511d035d92d5526bc1ed8a58dacbe36e (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)))