mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-01 10:45:49 +00:00
bcachefs: Rewrite btree nodes with errors
This patch adds self healing functionality for btree nodes - if we notice a problem when reading a btree node, we just rewrite 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
8058b532ac
commit
bcd25dac53
@ -986,6 +986,7 @@ static void btree_node_read_work(struct work_struct *work)
|
||||
struct bch_io_failures failed = { .nr = 0 };
|
||||
char buf[200];
|
||||
struct printbuf out;
|
||||
bool saw_error = false;
|
||||
bool can_retry;
|
||||
|
||||
goto start;
|
||||
@ -1022,6 +1023,8 @@ static void btree_node_read_work(struct work_struct *work)
|
||||
!bch2_btree_node_read_done(c, ca, b, can_retry))
|
||||
break;
|
||||
|
||||
saw_error = true;
|
||||
|
||||
if (!can_retry) {
|
||||
set_btree_node_read_error(b);
|
||||
break;
|
||||
@ -1031,6 +1034,10 @@ static void btree_node_read_work(struct work_struct *work)
|
||||
bch2_time_stats_update(&c->times[BCH_TIME_btree_node_read],
|
||||
rb->start_time);
|
||||
bio_put(&rb->bio);
|
||||
|
||||
if (saw_error && !btree_node_read_error(b))
|
||||
bch2_btree_node_rewrite_async(c, b);
|
||||
|
||||
clear_btree_node_read_in_flight(b);
|
||||
wake_up_bit(&b->flags, BTREE_NODE_read_in_flight);
|
||||
}
|
||||
|
@ -72,6 +72,7 @@ int bch2_btree_delete_range(struct bch_fs *, enum btree_id,
|
||||
|
||||
int bch2_btree_node_rewrite(struct bch_fs *c, struct btree_iter *,
|
||||
__le64, unsigned);
|
||||
void bch2_btree_node_rewrite_async(struct bch_fs *, struct btree *);
|
||||
int bch2_btree_node_update_key(struct bch_fs *, struct btree_iter *,
|
||||
struct btree *, struct bkey_i *);
|
||||
|
||||
|
@ -1797,6 +1797,56 @@ int bch2_btree_node_rewrite(struct bch_fs *c, struct btree_iter *iter,
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct async_btree_rewrite {
|
||||
struct bch_fs *c;
|
||||
struct work_struct work;
|
||||
enum btree_id btree_id;
|
||||
unsigned level;
|
||||
struct bpos pos;
|
||||
__le64 seq;
|
||||
};
|
||||
|
||||
void async_btree_node_rewrite_work(struct work_struct *work)
|
||||
{
|
||||
struct async_btree_rewrite *a =
|
||||
container_of(work, struct async_btree_rewrite, work);
|
||||
struct bch_fs *c = a->c;
|
||||
struct btree_trans trans;
|
||||
struct btree_iter *iter;
|
||||
|
||||
bch2_trans_init(&trans, c, 0, 0);
|
||||
iter = bch2_trans_get_node_iter(&trans, a->btree_id, a->pos,
|
||||
BTREE_MAX_DEPTH, a->level, 0);
|
||||
bch2_btree_node_rewrite(c, iter, a->seq, 0);
|
||||
bch2_trans_iter_put(&trans, iter);
|
||||
bch2_trans_exit(&trans);
|
||||
percpu_ref_put(&c->writes);
|
||||
kfree(a);
|
||||
}
|
||||
|
||||
void bch2_btree_node_rewrite_async(struct bch_fs *c, struct btree *b)
|
||||
{
|
||||
struct async_btree_rewrite *a;
|
||||
|
||||
if (!percpu_ref_tryget(&c->writes))
|
||||
return;
|
||||
|
||||
a = kmalloc(sizeof(*a), GFP_NOFS);
|
||||
if (!a) {
|
||||
percpu_ref_put(&c->writes);
|
||||
return;
|
||||
}
|
||||
|
||||
a->c = c;
|
||||
a->btree_id = b->c.btree_id;
|
||||
a->level = b->c.level;
|
||||
a->pos = b->key.k.p;
|
||||
a->seq = b->data->keys.seq;
|
||||
|
||||
INIT_WORK(&a->work, async_btree_node_rewrite_work);
|
||||
queue_work(system_long_wq, &a->work);
|
||||
}
|
||||
|
||||
static void __bch2_btree_node_update_key(struct bch_fs *c,
|
||||
struct btree_update *as,
|
||||
struct btree_iter *iter,
|
||||
|
Loading…
Reference in New Issue
Block a user