]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bcachefs: peek_prev_min(): Search forwards for extents, snapshots
authorKent Overstreet <kent.overstreet@linux.dev>
Sat, 26 Oct 2024 00:41:06 +0000 (20:41 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sat, 21 Dec 2024 06:36:18 +0000 (01:36 -0500)
With extents and snapshots, for slightly different reasons, we may have
to search forwards to find a key that compares equal to iter->pos (i.e.
a key that peek_prev() should return, as it returns keys <= iter->pos).

peek_slot() does this, and is an easy way to fix this case.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/btree_iter.c

index d66d773a37b4a4035f19d42f9fb48e622dd8e546..ed74f0655d984e2e7a73f8412a75b92d8a1aa16a 100644 (file)
@@ -2575,6 +2575,26 @@ static struct bkey_s_c __bch2_btree_iter_peek_prev(struct btree_iter *iter, stru
  */
 struct bkey_s_c bch2_btree_iter_peek_prev_min(struct btree_iter *iter, struct bpos end)
 {
+       if ((iter->flags & (BTREE_ITER_is_extents|BTREE_ITER_filter_snapshots)) &&
+          !bkey_eq(iter->pos, POS_MAX)) {
+               /*
+                * bkey_start_pos(), for extents, is not monotonically
+                * increasing until after filtering for snapshots:
+                *
+                * Thus, for extents we need to search forward until we find a
+                * real visible extents - easiest to just use peek_slot() (which
+                * internally uses peek() for extents)
+                */
+               struct bkey_s_c k = bch2_btree_iter_peek_slot(iter);
+               if (bkey_err(k))
+                       return k;
+
+               if (!bkey_deleted(k.k) &&
+                   (!(iter->flags & BTREE_ITER_is_extents) ||
+                    bkey_lt(bkey_start_pos(k.k), iter->pos)))
+                       return k;
+       }
+
        struct btree_trans *trans = iter->trans;
        struct bpos search_key = iter->pos;
        struct bkey_s_c k;
@@ -2584,9 +2604,6 @@ struct bkey_s_c bch2_btree_iter_peek_prev_min(struct btree_iter *iter, struct bp
        bch2_btree_iter_verify_entry_exit(iter);
        EBUG_ON((iter->flags & BTREE_ITER_filter_snapshots) && bpos_eq(end, POS_MIN));
 
-       if (iter->flags & BTREE_ITER_filter_snapshots)
-               search_key.snapshot = U32_MAX;
-
        while (1) {
                k = __bch2_btree_iter_peek_prev(iter, search_key);
                if (unlikely(!k.k))