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-01 11:39:30 -0400
commit7610360136de688029cc77eb824ce4541da5f1e5 (patch)
tree1555ca523fdaf25fea2db8167e1a57d7f92541e9
parentc8e753a254f8edbdceaa6241b4918ca4f27d8082 (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)))