bcachefs: Evict btree nodes we're deleting
authorKent Overstreet <kent.overstreet@gmail.com>
Sun, 25 Apr 2021 20:24:03 +0000 (16:24 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:09:02 +0000 (17:09 -0400)
There was a bug that led to duplicate btree node pointers being inserted
at the wrong level. The new topology repair code can fix that, except
that the btree cache code gets confused when we read in a btree node
from the pointer that was at the wrong level. This patch evicts nodes
that we're deleting to, which nicely solves the problem.

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

index a42e0922f5e9f4976d55015e03e6f427b70ed157..85c19e4e521682b786b2a17d1fb0f5d69b45a796 100644 (file)
@@ -948,6 +948,36 @@ void bch2_btree_node_prefetch(struct bch_fs *c, struct btree_iter *iter,
        bch2_btree_node_fill(c, iter, k, btree_id, level, SIX_LOCK_read, false);
 }
 
+void bch2_btree_node_evict(struct bch_fs *c, const struct bkey_i *k)
+{
+       struct btree_cache *bc = &c->btree_cache;
+       struct btree *b;
+
+       b = btree_cache_find(bc, k);
+       if (!b)
+               return;
+
+       six_lock_intent(&b->c.lock, NULL, NULL);
+       six_lock_write(&b->c.lock, NULL, NULL);
+
+       wait_on_bit_io(&b->flags, BTREE_NODE_read_in_flight,
+                      TASK_UNINTERRUPTIBLE);
+       __bch2_btree_node_write(c, b);
+
+       /* wait for any in flight btree write */
+       btree_node_wait_on_io(b);
+
+       BUG_ON(btree_node_dirty(b));
+
+       mutex_lock(&bc->lock);
+       btree_node_data_free(c, b);
+       bch2_btree_node_hash_remove(bc, b);
+       mutex_unlock(&bc->lock);
+
+       six_unlock_write(&b->c.lock);
+       six_unlock_intent(&b->c.lock);
+}
+
 void bch2_btree_node_to_text(struct printbuf *out, struct bch_fs *c,
                             struct btree *b)
 {
index c517cc02945405f5bc1a77a31f7292f504833cfd..40dd263a7caa7b043ab75792cb30a94660399572 100644 (file)
@@ -30,6 +30,8 @@ struct btree *bch2_btree_node_get_noiter(struct bch_fs *, const struct bkey_i *,
 void bch2_btree_node_prefetch(struct bch_fs *, struct btree_iter *,
                              const struct bkey_i *, enum btree_id, unsigned);
 
+void bch2_btree_node_evict(struct bch_fs *, const struct bkey_i *);
+
 void bch2_fs_btree_cache_exit(struct bch_fs *);
 int bch2_fs_btree_cache_init(struct bch_fs *);
 void bch2_fs_btree_cache_init_early(struct btree_cache *);
index 09a49dc63144084068bfd3567be3a00f4560cd85..1c2eab41f7ca42340d079ccbfa0c9abbe871569f 100644 (file)
@@ -298,6 +298,7 @@ again:
                                bch2_btree_ids[b->c.btree_id],
                                b->c.level - 1,
                                (bch2_bkey_val_to_text(&PBUF(buf), c, bkey_i_to_s_c(tmp.k)), buf))) {
+                       bch2_btree_node_evict(c, tmp.k);
                        ret = bch2_journal_key_delete(c, b->c.btree_id,
                                                      b->c.level, tmp.k->k.p);
                        if (ret)
@@ -359,6 +360,7 @@ again:
                cur = NULL;
 
                if (ret == DROP_THIS_NODE) {
+                       bch2_btree_node_evict(c, tmp.k);
                        ret = bch2_journal_key_delete(c, b->c.btree_id,
                                                      b->c.level, tmp.k->k.p);
                        dropped_children = true;