bcachefs: Don't drop ptrs to btree nodes
authorKent Overstreet <kent.overstreet@gmail.com>
Fri, 16 Apr 2021 22:59:54 +0000 (18:59 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:08:54 +0000 (17:08 -0400)
If a ptr gen doesn't match the bucket gen, the bucket likely doesn't
contain the data we want - but it's still possible the data we want
might have been overwritten, and for btree node pointers we can verify
whether or not the node is the one we wanted with the node's sequence
number, so it's better to keep the pointer and try reading from it.

Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/btree_gc.c
fs/bcachefs/btree_io.c

index f7a5bd9eca0b6ff9dd74c76b9bb955343429017d..7506a3de58ff04498b627f09e5cfef77d35305b9 100644 (file)
@@ -244,25 +244,40 @@ static int bch2_check_fix_ptrs(struct bch_fs *c, enum btree_id btree_id,
 
                bkey_reassemble(new, *k);
 
-               bch2_bkey_drop_ptrs(bkey_i_to_s(new), ptr, ({
-                       struct bch_dev *ca = bch_dev_bkey_exists(c, ptr->dev);
-                       struct bucket *g = PTR_BUCKET(ca, ptr, true);
-
-                       (ptr->cached &&
-                        (!g->gen_valid || gen_cmp(ptr->gen, g->mark.gen) > 0)) ||
-                       (!ptr->cached &&
-                        gen_cmp(ptr->gen, g->mark.gen) < 0);
-               }));
+               if (level) {
+                       /*
+                        * We don't want to drop btree node pointers - if the
+                        * btree node isn't there anymore, the read path will
+                        * sort it out:
+                        */
+                       ptrs = bch2_bkey_ptrs(bkey_i_to_s(new));
+                       bkey_for_each_ptr(ptrs, ptr) {
+                               struct bch_dev *ca = bch_dev_bkey_exists(c, ptr->dev);
+                               struct bucket *g = PTR_BUCKET(ca, ptr, true);
+
+                               ptr->gen = g->mark.gen;
+                       }
+               } else {
+                       bch2_bkey_drop_ptrs(bkey_i_to_s(new), ptr, ({
+                               struct bch_dev *ca = bch_dev_bkey_exists(c, ptr->dev);
+                               struct bucket *g = PTR_BUCKET(ca, ptr, true);
+
+                               (ptr->cached &&
+                                (!g->gen_valid || gen_cmp(ptr->gen, g->mark.gen) > 0)) ||
+                               (!ptr->cached &&
+                                gen_cmp(ptr->gen, g->mark.gen) < 0);
+                       }));
 again:
-               ptrs = bch2_bkey_ptrs(bkey_i_to_s(new));
-               bkey_extent_entry_for_each(ptrs, entry) {
-                       if (extent_entry_type(entry) == BCH_EXTENT_ENTRY_stripe_ptr) {
-                               struct stripe *m = genradix_ptr(&c->stripes[true],
-                                                               entry->stripe_ptr.idx);
-
-                               if (!m || !m->alive) {
-                                       bch2_bkey_extent_entry_drop(new, entry);
-                                       goto again;
+                       ptrs = bch2_bkey_ptrs(bkey_i_to_s(new));
+                       bkey_extent_entry_for_each(ptrs, entry) {
+                               if (extent_entry_type(entry) == BCH_EXTENT_ENTRY_stripe_ptr) {
+                                       struct stripe *m = genradix_ptr(&c->stripes[true],
+                                                                       entry->stripe_ptr.idx);
+
+                                       if (!m || !m->alive) {
+                                               bch2_bkey_extent_entry_drop(new, entry);
+                                               goto again;
+                                       }
                                }
                        }
                }
index eac51c39fc6ca3779f66bdba4178e6284c67da04..c7c91c1d5b2305ddafedd6b7f6f42061d14bb535 100644 (file)
@@ -1206,14 +1206,17 @@ void bch2_btree_node_read(struct bch_fs *c, struct btree *b,
        struct btree_read_bio *rb;
        struct bch_dev *ca;
        struct bio *bio;
+       char buf[200];
        int ret;
 
+       btree_pos_to_text(&PBUF(buf), c, b);
        trace_btree_read(c, b);
 
        ret = bch2_bkey_pick_read_device(c, bkey_i_to_s_c(&b->key),
                                         NULL, &pick);
        if (bch2_fs_fatal_err_on(ret <= 0, c,
-                       "btree node read error: no device to read from")) {
+                       "btree node read error: no device to read from\n"
+                       " at %s", buf)) {
                set_btree_node_read_error(b);
                return;
        }