mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-22 07:27:12 +08:00
bcachefs: Fix restart handling in btree_node_scrub_work()
btree node scrub was sometimes failing to rewrite nodes with errors; bch2_btree_node_rewrite() can return a transaction restart and we weren't checking - the lockrestart_do() needs to wrap the entire operation. And there's a better helper it should've been using, bch2_btree_node_rewrite_key(), which makes all this more convenient. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
@@ -1986,28 +1986,12 @@ static void btree_node_scrub_work(struct work_struct *work)
|
||||
prt_newline(&err);
|
||||
|
||||
if (!btree_node_scrub_check(c, scrub->buf, scrub->written, &err)) {
|
||||
struct btree_trans *trans = bch2_trans_get(c);
|
||||
|
||||
struct btree_iter iter;
|
||||
bch2_trans_node_iter_init(trans, &iter, scrub->btree,
|
||||
scrub->key.k->k.p, 0, scrub->level - 1, 0);
|
||||
|
||||
struct btree *b;
|
||||
int ret = lockrestart_do(trans,
|
||||
PTR_ERR_OR_ZERO(b = bch2_btree_iter_peek_node(trans, &iter)));
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
if (bkey_i_to_btree_ptr_v2(&b->key)->v.seq == scrub->seq) {
|
||||
bch_err(c, "error validating btree node during scrub on %s at btree %s",
|
||||
scrub->ca->name, err.buf);
|
||||
|
||||
ret = bch2_btree_node_rewrite(trans, &iter, b, 0, 0);
|
||||
}
|
||||
err:
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
bch2_trans_begin(trans);
|
||||
bch2_trans_put(trans);
|
||||
int ret = bch2_trans_do(c,
|
||||
bch2_btree_node_rewrite_key(trans, scrub->btree, scrub->level - 1,
|
||||
scrub->key.k, 0));
|
||||
if (!bch2_err_matches(ret, ENOENT) &&
|
||||
!bch2_err_matches(ret, EROFS))
|
||||
bch_err_fn_ratelimited(c, ret);
|
||||
}
|
||||
|
||||
printbuf_exit(&err);
|
||||
|
||||
@@ -2293,9 +2293,9 @@ err:
|
||||
goto out;
|
||||
}
|
||||
|
||||
static int bch2_btree_node_rewrite_key(struct btree_trans *trans,
|
||||
enum btree_id btree, unsigned level,
|
||||
struct bkey_i *k, unsigned flags)
|
||||
int bch2_btree_node_rewrite_key(struct btree_trans *trans,
|
||||
enum btree_id btree, unsigned level,
|
||||
struct bkey_i *k, unsigned flags)
|
||||
{
|
||||
struct btree_iter iter;
|
||||
bch2_trans_node_iter_init(trans, &iter,
|
||||
@@ -2367,9 +2367,8 @@ static void async_btree_node_rewrite_work(struct work_struct *work)
|
||||
|
||||
int ret = bch2_trans_do(c, bch2_btree_node_rewrite_key(trans,
|
||||
a->btree_id, a->level, a->key.k, 0));
|
||||
if (ret != -ENOENT &&
|
||||
!bch2_err_matches(ret, EROFS) &&
|
||||
ret != -BCH_ERR_journal_shutdown)
|
||||
if (!bch2_err_matches(ret, ENOENT) &&
|
||||
!bch2_err_matches(ret, EROFS))
|
||||
bch_err_fn_ratelimited(c, ret);
|
||||
|
||||
spin_lock(&c->btree_node_rewrites_lock);
|
||||
|
||||
@@ -176,6 +176,9 @@ static inline int bch2_foreground_maybe_merge(struct btree_trans *trans,
|
||||
|
||||
int bch2_btree_node_rewrite(struct btree_trans *, struct btree_iter *,
|
||||
struct btree *, unsigned, unsigned);
|
||||
int bch2_btree_node_rewrite_key(struct btree_trans *,
|
||||
enum btree_id, unsigned,
|
||||
struct bkey_i *, unsigned);
|
||||
int bch2_btree_node_rewrite_pos(struct btree_trans *,
|
||||
enum btree_id, unsigned,
|
||||
struct bpos, unsigned, unsigned);
|
||||
|
||||
Reference in New Issue
Block a user