bcachefs: Fix bch2_btree_node_iter_prev_filter()
authorKent Overstreet <kent.overstreet@gmail.com>
Mon, 19 Aug 2019 17:43:01 +0000 (13:43 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:08:25 +0000 (17:08 -0400)
bch2_btree_node_iter_prev_filter() tried to be smart about iterating
backwards when skipping over whiteouts/discards - but unfortunately,
doing so can leave the node iterator in an inconsistent state; the sane
solution is to just always iterate backwards one key at a time.

But we compact btree nodes when more than a quarter of the keys are
whiteouts/discards, so the optimization wasn't buying us that much
anyways.

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

index 78e6fd3f1306b27aa4a3ef7571eab504d4176133..1dd2bcc69c351637ee27c2660be395f3ee38d673 100644 (file)
@@ -1682,12 +1682,10 @@ void bch2_btree_node_iter_advance(struct btree_node_iter *iter,
 /*
  * Expensive:
  */
-struct bkey_packed *bch2_btree_node_iter_prev_filter(struct btree_node_iter *iter,
-                                                    struct btree *b,
-                                                    unsigned min_key_type)
+struct bkey_packed *bch2_btree_node_iter_prev_all(struct btree_node_iter *iter,
+                                                 struct btree *b)
 {
        struct bkey_packed *k, *prev = NULL;
-       struct bkey_packed *orig_pos = bch2_btree_node_iter_peek_all(iter, b);
        struct btree_node_iter_set *set;
        struct bset_tree *t;
        unsigned end = 0;
@@ -1695,9 +1693,8 @@ struct bkey_packed *bch2_btree_node_iter_prev_filter(struct btree_node_iter *ite
        bch2_btree_node_iter_verify(iter, b);
 
        for_each_bset(b, t) {
-               k = bch2_bkey_prev_filter(b, t,
-                       bch2_btree_node_iter_bset_pos(iter, b, t),
-                       min_key_type);
+               k = bch2_bkey_prev_all(b, t,
+                       bch2_btree_node_iter_bset_pos(iter, b, t));
                if (k &&
                    (!prev || bkey_iter_cmp(b, k, prev) > 0)) {
                        prev = k;
@@ -1706,7 +1703,7 @@ struct bkey_packed *bch2_btree_node_iter_prev_filter(struct btree_node_iter *ite
        }
 
        if (!prev)
-               goto out;
+               return NULL;
 
        /*
         * We're manually memmoving instead of just calling sort() to ensure the
@@ -1727,18 +1724,20 @@ found:
 
        iter->data[0].k = __btree_node_key_to_offset(b, prev);
        iter->data[0].end = end;
-out:
-       if (btree_keys_expensive_checks(b)) {
-               struct btree_node_iter iter2 = *iter;
 
-               if (prev)
-                       __bch2_btree_node_iter_advance(&iter2, b);
+       bch2_btree_node_iter_verify(iter, b);
+       return prev;
+}
 
-               while ((k = bch2_btree_node_iter_peek_all(&iter2, b)) != orig_pos) {
-                       BUG_ON(k->type >= min_key_type);
-                       __bch2_btree_node_iter_advance(&iter2, b);
-               }
-       }
+struct bkey_packed *bch2_btree_node_iter_prev_filter(struct btree_node_iter *iter,
+                                                    struct btree *b,
+                                                    unsigned min_key_type)
+{
+       struct bkey_packed *prev;
+
+       do {
+               prev = bch2_btree_node_iter_prev_all(iter, b);
+       } while (prev && prev->type < min_key_type);
 
        return prev;
 }
index da3e41cc975743bd8c041b2100eb96b3815a2121..209d2ed5db3a20eb76dbddc1c6cc8e445f4979e1 100644 (file)
@@ -543,15 +543,11 @@ bch2_btree_node_iter_next_all(struct btree_node_iter *iter, struct btree *b)
        return ret;
 }
 
+struct bkey_packed *bch2_btree_node_iter_prev_all(struct btree_node_iter *,
+                                                 struct btree *);
 struct bkey_packed *bch2_btree_node_iter_prev_filter(struct btree_node_iter *,
                                                     struct btree *, unsigned);
 
-static inline struct bkey_packed *
-bch2_btree_node_iter_prev_all(struct btree_node_iter *iter, struct btree *b)
-{
-       return bch2_btree_node_iter_prev_filter(iter, b, 0);
-}
-
 static inline struct bkey_packed *
 bch2_btree_node_iter_prev(struct btree_node_iter *iter, struct btree *b)
 {