summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2022-04-09 15:15:36 -0400
committerKent Overstreet <kent.overstreet@gmail.com>2022-04-17 15:44:31 -0400
commit6adf13a45513dcc2c2a8cafe292157ddbcc6a42c (patch)
treeca049f0c46a0902f09816bd182eaba64d70085e7
parentaf31e5417aee386eae1bd5ab9bf4e51af6b5f015 (diff)
bcachefs: Minor device removal fixes
- We weren't clearing the LRU btree - bch2_alloc_read() runs before bch2_check_alloc_key() deletes alloc keys for devices/buckets that don't exists, so it needs to check for that - bch2_check_lrus() needs to check that buckets exists - improve some error messages Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
-rw-r--r--fs/bcachefs/alloc_background.c15
-rw-r--r--fs/bcachefs/lru.c13
-rw-r--r--fs/bcachefs/super.c20
3 files changed, 33 insertions, 15 deletions
diff --git a/fs/bcachefs/alloc_background.c b/fs/bcachefs/alloc_background.c
index 263bcdb736c1..4f208fab799a 100644
--- a/fs/bcachefs/alloc_background.c
+++ b/fs/bcachefs/alloc_background.c
@@ -446,6 +446,13 @@ int bch2_alloc_read(struct bch_fs *c)
for_each_btree_key(&trans, iter, BTREE_ID_alloc, POS_MIN,
BTREE_ITER_PREFETCH, k, ret) {
+ /*
+ * Not a fsck error because this is checked/repaired by
+ * bch2_check_alloc_key() which runs later:
+ */
+ if (!bch2_dev_bucket_exists(c, k.k->p))
+ continue;
+
ca = bch_dev_bkey_exists(c, k.k->p.inode);
bch2_alloc_to_v4(k, &a);
@@ -614,7 +621,8 @@ static int bch2_check_alloc_key(struct btree_trans *trans,
return ret;
if (fsck_err_on(!bch2_dev_bucket_exists(c, alloc_k.k->p), c,
- "alloc key for invalid device or bucket"))
+ "alloc key for invalid device:bucket %llu:%llu",
+ alloc_k.k->p.inode, alloc_k.k->p.offset))
return bch2_btree_delete_at(trans, alloc_iter, 0);
ca = bch_dev_bkey_exists(c, alloc_k.k->p.inode);
@@ -727,9 +735,8 @@ static int bch2_check_discard_freespace_key(struct btree_trans *trans,
bch2_trans_iter_init(trans, &alloc_iter, BTREE_ID_alloc, pos, 0);
if (fsck_err_on(!bch2_dev_bucket_exists(c, pos), c,
- "%llu:%llu set in %s btree but device or bucket does not exist",
- pos.inode, pos.offset,
- bch2_btree_ids[iter->btree_id]))
+ "entry in %s btree for nonexistant dev:bucket %llu:%llu",
+ bch2_btree_ids[iter->btree_id], pos.inode, pos.offset))
goto delete;
k = bch2_btree_iter_peek_slot(&alloc_iter);
diff --git a/fs/bcachefs/lru.c b/fs/bcachefs/lru.c
index 267f2f8fb13b..ef4b4a9f0d5f 100644
--- a/fs/bcachefs/lru.c
+++ b/fs/bcachefs/lru.c
@@ -133,7 +133,7 @@ static int bch2_check_lru_key(struct btree_trans *trans,
struct bch_alloc_v4 a;
struct printbuf buf1 = PRINTBUF;
struct printbuf buf2 = PRINTBUF;
- u64 idx;
+ struct bpos alloc_pos;
int ret;
lru_k = bch2_btree_iter_peek(lru_iter);
@@ -144,10 +144,15 @@ static int bch2_check_lru_key(struct btree_trans *trans,
if (ret)
return ret;
- idx = le64_to_cpu(bkey_s_c_to_lru(lru_k).v->idx);
+ alloc_pos = POS(lru_k.k->p.inode,
+ le64_to_cpu(bkey_s_c_to_lru(lru_k).v->idx));
- bch2_trans_iter_init(trans, &iter, BTREE_ID_alloc,
- POS(lru_k.k->p.inode, idx), 0);
+ if (fsck_err_on(!bch2_dev_bucket_exists(c, alloc_pos), c,
+ "lru key points to nonexistent device:bucket %llu:%llu",
+ alloc_pos.inode, alloc_pos.offset))
+ return bch2_btree_delete_at(trans, lru_iter, 0);
+
+ bch2_trans_iter_init(trans, &iter, BTREE_ID_alloc, alloc_pos, 0);
k = bch2_btree_iter_peek_slot(&iter);
ret = bkey_err(k);
if (ret)
diff --git a/fs/bcachefs/super.c b/fs/bcachefs/super.c
index aba679c6f30f..1401cb576fa2 100644
--- a/fs/bcachefs/super.c
+++ b/fs/bcachefs/super.c
@@ -1420,11 +1420,17 @@ static int bch2_dev_remove_alloc(struct bch_fs *c, struct bch_dev *ca)
struct bpos end = POS(ca->dev_idx, U64_MAX);
int ret;
- ret = bch2_btree_delete_range(c, BTREE_ID_alloc, start, end,
+ /*
+ * We clear the LRU and need_discard btrees first so that we don't race
+ * with bch2_do_invalidates() and bch2_do_discards()
+ */
+ ret = bch2_btree_delete_range(c, BTREE_ID_lru, start, end,
+ BTREE_TRIGGER_NORUN, NULL) ?:
+ bch2_btree_delete_range(c, BTREE_ID_need_discard, start, end,
BTREE_TRIGGER_NORUN, NULL) ?:
bch2_btree_delete_range(c, BTREE_ID_freespace, start, end,
BTREE_TRIGGER_NORUN, NULL) ?:
- bch2_btree_delete_range(c, BTREE_ID_need_discard, start, end,
+ bch2_btree_delete_range(c, BTREE_ID_alloc, start, end,
BTREE_TRIGGER_NORUN, NULL);
if (ret)
bch_err(c, "error %i removing dev alloc info", ret);
@@ -1459,19 +1465,19 @@ int bch2_dev_remove(struct bch_fs *c, struct bch_dev *ca, int flags)
goto err;
}
- ret = bch2_journal_flush_device_pins(&c->journal, ca->dev_idx);
+ ret = bch2_dev_remove_alloc(c, ca);
if (ret) {
- bch_err(ca, "Remove failed: error %i flushing journal", ret);
+ bch_err(ca, "Remove failed, error deleting alloc info");
goto err;
}
- ret = bch2_dev_remove_alloc(c, ca);
+ ret = bch2_journal_flush_device_pins(&c->journal, ca->dev_idx);
if (ret) {
- bch_err(ca, "Remove failed, error deleting alloc info");
+ bch_err(ca, "Remove failed: error %i flushing journal", ret);
goto err;
}
- ret = bch2_journal_error(&c->journal);
+ ret = bch2_journal_flush(&c->journal);
if (ret) {
bch_err(ca, "Remove failed, journal error");
goto err;