summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2021-04-25 16:24:03 -0400
committerKent Overstreet <kent.overstreet@gmail.com>2021-05-19 15:33:46 -0400
commit5f5842cbbe9615145ea00ea283c9b04d208e4b4f (patch)
tree561067c352654db04daf4e3f1f4681945d3ca015 /fs
parent278294b648ec00b804fa21e7709b33ecfd2d0cb6 (diff)
bcachefs: Evict btree nodes we're deleting
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>
Diffstat (limited to 'fs')
-rw-r--r--fs/bcachefs/btree_cache.c30
-rw-r--r--fs/bcachefs/btree_cache.h2
-rw-r--r--fs/bcachefs/btree_gc.c2
3 files changed, 34 insertions, 0 deletions
diff --git a/fs/bcachefs/btree_cache.c b/fs/bcachefs/btree_cache.c
index 4e90cc383aec..a010cf2b55b5 100644
--- a/fs/bcachefs/btree_cache.c
+++ b/fs/bcachefs/btree_cache.c
@@ -939,6 +939,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)
{
diff --git a/fs/bcachefs/btree_cache.h b/fs/bcachefs/btree_cache.h
index c517cc029454..40dd263a7caa 100644
--- a/fs/bcachefs/btree_cache.h
+++ b/fs/bcachefs/btree_cache.h
@@ -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 *);
diff --git a/fs/bcachefs/btree_gc.c b/fs/bcachefs/btree_gc.c
index 12f960be41b6..24fa279d1cdb 100644
--- a/fs/bcachefs/btree_gc.c
+++ b/fs/bcachefs/btree_gc.c
@@ -295,6 +295,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)
@@ -356,6 +357,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;