178 lines
6.3 KiB
Diff
178 lines
6.3 KiB
Diff
From 19b148fc65a3eb2d583738f9f4390400c80f2419 Mon Sep 17 00:00:00 2001
|
|
From: Kent Overstreet <kent.overstreet@linux.dev>
|
|
Date: Tue, 12 Nov 2024 03:46:31 -0500
|
|
Subject: [PATCH 217/233] bcachefs: bch2_backpointer_get_key() now repairs
|
|
dangling backpointers
|
|
Content-Type: text/plain; charset="utf-8"
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
Continuing on with the self healing theme, we should be running any
|
|
check and repair code at runtime that we can - instead of declaring the
|
|
filesystemt inconsistent.
|
|
|
|
This will also let us skip running the backpointers -> extents fsck pass
|
|
except in debug mode.
|
|
|
|
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
|
|
Signed-off-by: Alexander Miroshnichenko <alex@millerson.name>
|
|
---
|
|
fs/bcachefs/backpointers.c | 70 +++++++++++++++-----------------------
|
|
1 file changed, 28 insertions(+), 42 deletions(-)
|
|
|
|
diff --git a/fs/bcachefs/backpointers.c b/fs/bcachefs/backpointers.c
|
|
index 892939763c3a..5cc4aaa3a325 100644
|
|
--- a/fs/bcachefs/backpointers.c
|
|
+++ b/fs/bcachefs/backpointers.c
|
|
@@ -172,9 +172,10 @@ int bch2_bucket_backpointer_mod_nowritebuffer(struct btree_trans *trans,
|
|
|
|
static int bch2_backpointer_del(struct btree_trans *trans, struct bpos pos)
|
|
{
|
|
- return likely(!bch2_backpointers_no_use_write_buffer)
|
|
- ? bch2_btree_delete_at_buffered(trans, BTREE_ID_backpointers, pos)
|
|
- : bch2_btree_delete(trans, BTREE_ID_backpointers, pos, 0);
|
|
+ return (likely(!bch2_backpointers_no_use_write_buffer)
|
|
+ ? bch2_btree_delete_at_buffered(trans, BTREE_ID_backpointers, pos)
|
|
+ : bch2_btree_delete(trans, BTREE_ID_backpointers, pos, 0)) ?:
|
|
+ bch2_trans_commit(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc);
|
|
}
|
|
|
|
static inline int bch2_backpointers_maybe_flush(struct btree_trans *trans,
|
|
@@ -186,20 +187,25 @@ static inline int bch2_backpointers_maybe_flush(struct btree_trans *trans,
|
|
: 0;
|
|
}
|
|
|
|
-static void backpointer_target_not_found(struct btree_trans *trans,
|
|
- struct bkey_s_c_backpointer bp,
|
|
- struct bkey_s_c target_k)
|
|
+static int backpointer_target_not_found(struct btree_trans *trans,
|
|
+ struct bkey_s_c_backpointer bp,
|
|
+ struct bkey_s_c target_k,
|
|
+ struct bkey_buf *last_flushed)
|
|
{
|
|
struct bch_fs *c = trans->c;
|
|
struct printbuf buf = PRINTBUF;
|
|
+ int ret = 0;
|
|
|
|
/*
|
|
* If we're using the btree write buffer, the backpointer we were
|
|
* looking at may have already been deleted - failure to find what it
|
|
* pointed to is not an error:
|
|
*/
|
|
- if (likely(!bch2_backpointers_no_use_write_buffer))
|
|
- return;
|
|
+ ret = last_flushed
|
|
+ ? bch2_backpointers_maybe_flush(trans, bp.s_c, last_flushed)
|
|
+ : 0;
|
|
+ if (ret)
|
|
+ return ret;
|
|
|
|
prt_printf(&buf, "backpointer doesn't match %s it points to:\n ",
|
|
bp.v->level ? "btree node" : "extent");
|
|
@@ -207,12 +213,13 @@ static void backpointer_target_not_found(struct btree_trans *trans,
|
|
prt_printf(&buf, "\n ");
|
|
|
|
bch2_bkey_val_to_text(&buf, c, target_k);
|
|
- if (c->curr_recovery_pass >= BCH_RECOVERY_PASS_check_extents_to_backpointers)
|
|
- bch_err_ratelimited(c, "%s", buf.buf);
|
|
- else
|
|
- bch2_trans_inconsistent(trans, "%s", buf.buf);
|
|
|
|
+ if (fsck_err(trans, backpointer_to_missing_ptr,
|
|
+ "%s", buf.buf))
|
|
+ ret = bch2_backpointer_del(trans, bp.k->p);
|
|
+fsck_err:
|
|
printbuf_exit(&buf);
|
|
+ return ret;
|
|
}
|
|
|
|
struct bkey_s_c bch2_backpointer_get_key(struct btree_trans *trans,
|
|
@@ -243,15 +250,13 @@ struct bkey_s_c bch2_backpointer_get_key(struct btree_trans *trans,
|
|
return k;
|
|
|
|
bch2_trans_iter_exit(trans, iter);
|
|
- backpointer_target_not_found(trans, bp, k);
|
|
- return bkey_s_c_null;
|
|
+ int ret = backpointer_target_not_found(trans, bp, k, last_flushed);
|
|
+ return ret ? bkey_s_c_err(ret) : bkey_s_c_null;
|
|
} else {
|
|
struct btree *b = bch2_backpointer_get_node(trans, bp, iter, last_flushed);
|
|
+ if (IS_ERR_OR_NULL(b))
|
|
+ return ((struct bkey_s_c) { .k = ERR_CAST(b) });
|
|
|
|
- if (IS_ERR_OR_NULL(b)) {
|
|
- bch2_trans_iter_exit(trans, iter);
|
|
- return IS_ERR(b) ? bkey_s_c_err(PTR_ERR(b)) : bkey_s_c_null;
|
|
- }
|
|
return bkey_i_to_s_c(&b->key);
|
|
}
|
|
}
|
|
@@ -284,8 +289,8 @@ struct btree *bch2_backpointer_get_node(struct btree_trans *trans,
|
|
if (btree_node_will_make_reachable(b)) {
|
|
b = ERR_PTR(-BCH_ERR_backpointer_to_overwritten_btree_node);
|
|
} else {
|
|
- backpointer_target_not_found(trans, bp, bkey_i_to_s_c(&b->key));
|
|
- b = NULL;
|
|
+ int ret = backpointer_target_not_found(trans, bp, bkey_i_to_s_c(&b->key), last_flushed);
|
|
+ b = ret ? ERR_PTR(ret) : NULL;
|
|
}
|
|
err:
|
|
bch2_trans_iter_exit(trans, iter);
|
|
@@ -488,7 +493,7 @@ static int check_bp_exists(struct btree_trans *trans,
|
|
struct bkey_s_c_backpointer other_bp = bkey_s_c_to_backpointer(bp_k);
|
|
|
|
struct bkey_s_c other_extent =
|
|
- bch2_backpointer_get_key(trans, other_bp, &other_extent_iter, 0, &s->last_flushed);
|
|
+ bch2_backpointer_get_key(trans, other_bp, &other_extent_iter, 0, NULL);
|
|
ret = bkey_err(other_extent);
|
|
if (ret == -BCH_ERR_backpointer_to_overwritten_btree_node)
|
|
ret = 0;
|
|
@@ -1143,9 +1148,7 @@ static int check_one_backpointer(struct btree_trans *trans,
|
|
return 0;
|
|
|
|
struct bkey_s_c_backpointer bp = bkey_s_c_to_backpointer(bp_k);
|
|
- struct bch_fs *c = trans->c;
|
|
struct bbpos pos = bp_to_bbpos(*bp.v);
|
|
- struct printbuf buf = PRINTBUF;
|
|
|
|
if (bbpos_cmp(pos, start) < 0 ||
|
|
bbpos_cmp(pos, end) > 0)
|
|
@@ -1159,23 +1162,7 @@ static int check_one_backpointer(struct btree_trans *trans,
|
|
if (ret)
|
|
return ret;
|
|
|
|
- if (!k.k) {
|
|
- ret = bch2_backpointers_maybe_flush(trans, bp.s_c, last_flushed);
|
|
- if (ret)
|
|
- goto out;
|
|
-
|
|
- if (fsck_err(trans, backpointer_to_missing_ptr,
|
|
- "backpointer for missing %s\n %s",
|
|
- bp.v->level ? "btree node" : "extent",
|
|
- (bch2_bkey_val_to_text(&buf, c, bp.s_c), buf.buf))) {
|
|
- ret = bch2_backpointer_del(trans, bp.k->p);
|
|
- goto out;
|
|
- }
|
|
- }
|
|
-out:
|
|
-fsck_err:
|
|
bch2_trans_iter_exit(trans, &iter);
|
|
- printbuf_exit(&buf);
|
|
return ret;
|
|
}
|
|
|
|
@@ -1210,9 +1197,8 @@ static int bch2_check_backpointers_to_extents_pass(struct btree_trans *trans,
|
|
bkey_init(&last_flushed.k->k);
|
|
progress_init(&progress, trans->c, BIT_ULL(BTREE_ID_backpointers));
|
|
|
|
- int ret = for_each_btree_key_commit(trans, iter, BTREE_ID_backpointers,
|
|
- POS_MIN, BTREE_ITER_prefetch, k,
|
|
- NULL, NULL, BCH_TRANS_COMMIT_no_enospc, ({
|
|
+ int ret = for_each_btree_key(trans, iter, BTREE_ID_backpointers,
|
|
+ POS_MIN, BTREE_ITER_prefetch, k, ({
|
|
progress_update_iter(trans, &progress, &iter, "backpointers_to_extents");
|
|
check_one_backpointer(trans, start, end, k, &last_flushed);
|
|
}));
|
|
--
|
|
2.45.2
|
|
|