bcachefs: Don't drop ptrs to btree nodes
If a ptr gen doesn't match the bucket gen, the bucket likely doesn't contain the data we want - but it's still possible the data we want might have been overwritten, and for btree node pointers we can verify whether or not the node is the one we wanted with the node's sequence number, so it's better to keep the pointer and try reading from it. Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com> Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
d065472c3a
commit
006d69aa26
@ -244,25 +244,40 @@ static int bch2_check_fix_ptrs(struct bch_fs *c, enum btree_id btree_id,
|
||||
|
||||
bkey_reassemble(new, *k);
|
||||
|
||||
bch2_bkey_drop_ptrs(bkey_i_to_s(new), ptr, ({
|
||||
struct bch_dev *ca = bch_dev_bkey_exists(c, ptr->dev);
|
||||
struct bucket *g = PTR_BUCKET(ca, ptr, true);
|
||||
if (level) {
|
||||
/*
|
||||
* We don't want to drop btree node pointers - if the
|
||||
* btree node isn't there anymore, the read path will
|
||||
* sort it out:
|
||||
*/
|
||||
ptrs = bch2_bkey_ptrs(bkey_i_to_s(new));
|
||||
bkey_for_each_ptr(ptrs, ptr) {
|
||||
struct bch_dev *ca = bch_dev_bkey_exists(c, ptr->dev);
|
||||
struct bucket *g = PTR_BUCKET(ca, ptr, true);
|
||||
|
||||
(ptr->cached &&
|
||||
(!g->gen_valid || gen_cmp(ptr->gen, g->mark.gen) > 0)) ||
|
||||
(!ptr->cached &&
|
||||
gen_cmp(ptr->gen, g->mark.gen) < 0);
|
||||
}));
|
||||
ptr->gen = g->mark.gen;
|
||||
}
|
||||
} else {
|
||||
bch2_bkey_drop_ptrs(bkey_i_to_s(new), ptr, ({
|
||||
struct bch_dev *ca = bch_dev_bkey_exists(c, ptr->dev);
|
||||
struct bucket *g = PTR_BUCKET(ca, ptr, true);
|
||||
|
||||
(ptr->cached &&
|
||||
(!g->gen_valid || gen_cmp(ptr->gen, g->mark.gen) > 0)) ||
|
||||
(!ptr->cached &&
|
||||
gen_cmp(ptr->gen, g->mark.gen) < 0);
|
||||
}));
|
||||
again:
|
||||
ptrs = bch2_bkey_ptrs(bkey_i_to_s(new));
|
||||
bkey_extent_entry_for_each(ptrs, entry) {
|
||||
if (extent_entry_type(entry) == BCH_EXTENT_ENTRY_stripe_ptr) {
|
||||
struct stripe *m = genradix_ptr(&c->stripes[true],
|
||||
entry->stripe_ptr.idx);
|
||||
ptrs = bch2_bkey_ptrs(bkey_i_to_s(new));
|
||||
bkey_extent_entry_for_each(ptrs, entry) {
|
||||
if (extent_entry_type(entry) == BCH_EXTENT_ENTRY_stripe_ptr) {
|
||||
struct stripe *m = genradix_ptr(&c->stripes[true],
|
||||
entry->stripe_ptr.idx);
|
||||
|
||||
if (!m || !m->alive) {
|
||||
bch2_bkey_extent_entry_drop(new, entry);
|
||||
goto again;
|
||||
if (!m || !m->alive) {
|
||||
bch2_bkey_extent_entry_drop(new, entry);
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1206,14 +1206,17 @@ void bch2_btree_node_read(struct bch_fs *c, struct btree *b,
|
||||
struct btree_read_bio *rb;
|
||||
struct bch_dev *ca;
|
||||
struct bio *bio;
|
||||
char buf[200];
|
||||
int ret;
|
||||
|
||||
btree_pos_to_text(&PBUF(buf), c, b);
|
||||
trace_btree_read(c, b);
|
||||
|
||||
ret = bch2_bkey_pick_read_device(c, bkey_i_to_s_c(&b->key),
|
||||
NULL, &pick);
|
||||
if (bch2_fs_fatal_err_on(ret <= 0, c,
|
||||
"btree node read error: no device to read from")) {
|
||||
"btree node read error: no device to read from\n"
|
||||
" at %s", buf)) {
|
||||
set_btree_node_read_error(b);
|
||||
return;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user