Commit 872c0311 authored by Kent Overstreet's avatar Kent Overstreet

bcachefs: Fix bch2_check_extents_to_backpointers()

In rare cases, bch2_check_extents_to_backpointers() would incorrectly
flag an extent has having a missing backpointer when we just needed to
flush the btree write buffer - we weren't tracking the last flushed
position correctly.

This adds a level field to the last_flushed pos, fixing a bug where we'd
sometimes fail on a new root node.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent c639c29c
...@@ -549,13 +549,18 @@ int bch2_check_btree_backpointers(struct bch_fs *c) ...@@ -549,13 +549,18 @@ int bch2_check_btree_backpointers(struct bch_fs *c)
bch2_check_btree_backpointer(&trans, &iter, k))); bch2_check_btree_backpointer(&trans, &iter, k)));
} }
struct bpos_level {
unsigned level;
struct bpos pos;
};
static int check_bp_exists(struct btree_trans *trans, static int check_bp_exists(struct btree_trans *trans,
struct bpos bucket_pos, struct bpos bucket_pos,
struct bch_backpointer bp, struct bch_backpointer bp,
struct bkey_s_c orig_k, struct bkey_s_c orig_k,
struct bpos bucket_start, struct bpos bucket_start,
struct bpos bucket_end, struct bpos bucket_end,
struct bpos *last_flushed_pos) struct bpos_level *last_flushed)
{ {
struct bch_fs *c = trans->c; struct bch_fs *c = trans->c;
struct btree_iter alloc_iter, bp_iter = { NULL }; struct btree_iter alloc_iter, bp_iter = { NULL };
...@@ -600,8 +605,11 @@ static int check_bp_exists(struct btree_trans *trans, ...@@ -600,8 +605,11 @@ static int check_bp_exists(struct btree_trans *trans,
if (bp_k.k->type != KEY_TYPE_backpointer || if (bp_k.k->type != KEY_TYPE_backpointer ||
memcmp(bkey_s_c_to_backpointer(bp_k).v, &bp, sizeof(bp))) { memcmp(bkey_s_c_to_backpointer(bp_k).v, &bp, sizeof(bp))) {
if (!bpos_eq(*last_flushed_pos, orig_k.k->p)) { if (last_flushed->level != bp.level ||
*last_flushed_pos = orig_k.k->p; !bpos_eq(last_flushed->pos, orig_k.k->p)) {
last_flushed->level = bp.level;
last_flushed->pos = orig_k.k->p;
ret = bch2_btree_write_buffer_flush_sync(trans) ?: ret = bch2_btree_write_buffer_flush_sync(trans) ?:
-BCH_ERR_transaction_restart_write_buffer_flush; -BCH_ERR_transaction_restart_write_buffer_flush;
goto out; goto out;
...@@ -639,7 +647,7 @@ static int check_extent_to_backpointers(struct btree_trans *trans, ...@@ -639,7 +647,7 @@ static int check_extent_to_backpointers(struct btree_trans *trans,
struct btree_iter *iter, struct btree_iter *iter,
struct bpos bucket_start, struct bpos bucket_start,
struct bpos bucket_end, struct bpos bucket_end,
struct bpos *last_flushed_pos) struct bpos_level *last_flushed)
{ {
struct bch_fs *c = trans->c; struct bch_fs *c = trans->c;
struct bkey_ptrs_c ptrs; struct bkey_ptrs_c ptrs;
...@@ -668,7 +676,7 @@ static int check_extent_to_backpointers(struct btree_trans *trans, ...@@ -668,7 +676,7 @@ static int check_extent_to_backpointers(struct btree_trans *trans,
ret = check_bp_exists(trans, bucket_pos, bp, k, ret = check_bp_exists(trans, bucket_pos, bp, k,
bucket_start, bucket_end, bucket_start, bucket_end,
last_flushed_pos); last_flushed);
if (ret) if (ret)
return ret; return ret;
} }
...@@ -680,7 +688,7 @@ static int check_btree_root_to_backpointers(struct btree_trans *trans, ...@@ -680,7 +688,7 @@ static int check_btree_root_to_backpointers(struct btree_trans *trans,
enum btree_id btree_id, enum btree_id btree_id,
struct bpos bucket_start, struct bpos bucket_start,
struct bpos bucket_end, struct bpos bucket_end,
struct bpos *last_flushed_pos) struct bpos_level *last_flushed)
{ {
struct bch_fs *c = trans->c; struct bch_fs *c = trans->c;
struct btree_iter iter; struct btree_iter iter;
...@@ -709,12 +717,12 @@ static int check_btree_root_to_backpointers(struct btree_trans *trans, ...@@ -709,12 +717,12 @@ static int check_btree_root_to_backpointers(struct btree_trans *trans,
if (p.ptr.cached) if (p.ptr.cached)
continue; continue;
bch2_extent_ptr_to_bp(c, iter.btree_id, iter.path->level + 1, bch2_extent_ptr_to_bp(c, iter.btree_id, b->c.level + 1,
k, p, &bucket_pos, &bp); k, p, &bucket_pos, &bp);
ret = check_bp_exists(trans, bucket_pos, bp, k, ret = check_bp_exists(trans, bucket_pos, bp, k,
bucket_start, bucket_end, bucket_start, bucket_end,
last_flushed_pos); last_flushed);
if (ret) if (ret)
goto err; goto err;
} }
...@@ -794,7 +802,7 @@ static int bch2_check_extents_to_backpointers_pass(struct btree_trans *trans, ...@@ -794,7 +802,7 @@ static int bch2_check_extents_to_backpointers_pass(struct btree_trans *trans,
{ {
struct btree_iter iter; struct btree_iter iter;
enum btree_id btree_id; enum btree_id btree_id;
struct bpos last_flushed_pos = SPOS_MAX; struct bpos_level last_flushed = { UINT_MAX };
int ret = 0; int ret = 0;
for (btree_id = 0; btree_id < BTREE_ID_NR; btree_id++) { for (btree_id = 0; btree_id < BTREE_ID_NR; btree_id++) {
...@@ -811,7 +819,7 @@ static int bch2_check_extents_to_backpointers_pass(struct btree_trans *trans, ...@@ -811,7 +819,7 @@ static int bch2_check_extents_to_backpointers_pass(struct btree_trans *trans,
BTREE_INSERT_NOFAIL, BTREE_INSERT_NOFAIL,
check_extent_to_backpointers(trans, &iter, check_extent_to_backpointers(trans, &iter,
bucket_start, bucket_end, bucket_start, bucket_end,
&last_flushed_pos)); &last_flushed));
if (ret) if (ret)
break; break;
} while (!bch2_btree_iter_advance(&iter)); } while (!bch2_btree_iter_advance(&iter));
...@@ -826,7 +834,7 @@ static int bch2_check_extents_to_backpointers_pass(struct btree_trans *trans, ...@@ -826,7 +834,7 @@ static int bch2_check_extents_to_backpointers_pass(struct btree_trans *trans,
BTREE_INSERT_NOFAIL, BTREE_INSERT_NOFAIL,
check_btree_root_to_backpointers(trans, btree_id, check_btree_root_to_backpointers(trans, btree_id,
bucket_start, bucket_end, bucket_start, bucket_end,
&last_flushed_pos)); &last_flushed));
if (ret) if (ret)
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment