Commit e1f0e1a4 authored by Kent Overstreet's avatar Kent Overstreet
Browse files

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: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 6c4897ca
Loading
Loading
Loading
Loading
+6 −22
Original line number Diff line number Diff line
@@ -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);
+5 −6
Original line number Diff line number Diff line
@@ -2293,7 +2293,7 @@ int bch2_btree_node_rewrite(struct btree_trans *trans,
	goto out;
}

static int bch2_btree_node_rewrite_key(struct btree_trans *trans,
int bch2_btree_node_rewrite_key(struct btree_trans *trans,
				enum btree_id btree, unsigned level,
				struct bkey_i *k, unsigned flags)
{
@@ -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);
+3 −0
Original line number Diff line number Diff line
@@ -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);