Commit 47fe65b1 authored by Kent Overstreet's avatar Kent Overstreet
Browse files

bcachefs: Add missing restart handling to check_topology()



The next patch will add logging of the specific error being corrected in
repair paths to the journal; this means __bch2_fsck_err() can return
transaction restarts in places that previously weren't expecting them.

check_topology() is old code that doesn't use btree iterators for btree
node locking - it'll have to be rewritten in the future to work online.

Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 19272b37
Loading
Loading
Loading
Loading
+60 −35
Original line number Diff line number Diff line
@@ -397,7 +397,11 @@ static int bch2_btree_repair_topology_recurse(struct btree_trans *trans, struct
			continue;
		}

		ret = btree_check_node_boundaries(trans, b, prev, cur, pulled_from_scan);
		ret = lockrestart_do(trans,
			btree_check_node_boundaries(trans, b, prev, cur, pulled_from_scan));
		if (ret < 0)
			goto err;

		if (ret == DID_FILL_FROM_SCAN) {
			new_pass = true;
			ret = 0;
@@ -438,7 +442,8 @@ static int bch2_btree_repair_topology_recurse(struct btree_trans *trans, struct

	if (!ret && !IS_ERR_OR_NULL(prev)) {
		BUG_ON(cur);
		ret = btree_repair_node_end(trans, b, prev, pulled_from_scan);
		ret = lockrestart_do(trans,
			btree_repair_node_end(trans, b, prev, pulled_from_scan));
		if (ret == DID_FILL_FROM_SCAN) {
			new_pass = true;
			ret = 0;
@@ -519,27 +524,21 @@ static int bch2_btree_repair_topology_recurse(struct btree_trans *trans, struct
	bch2_bkey_buf_exit(&prev_k, c);
	bch2_bkey_buf_exit(&cur_k, c);
	printbuf_exit(&buf);
	bch_err_fn(c, ret);
	return ret;
}

int bch2_check_topology(struct bch_fs *c)
static int bch2_check_root(struct btree_trans *trans, enum btree_id i,
			   bool *reconstructed_root)
{
	struct btree_trans *trans = bch2_trans_get(c);
	struct bpos pulled_from_scan = POS_MIN;
	struct bch_fs *c = trans->c;
	struct btree_root *r = bch2_btree_id_root(c, i);
	struct printbuf buf = PRINTBUF;
	int ret = 0;

	bch2_trans_srcu_unlock(trans);

	for (unsigned i = 0; i < btree_id_nr_alive(c) && !ret; i++) {
		struct btree_root *r = bch2_btree_id_root(c, i);
		bool reconstructed_root = false;

		printbuf_reset(&buf);
	bch2_btree_id_to_text(&buf, i);

	if (r->error) {
reconstruct_root:
		bch_info(c, "btree root %s unreadable, must recover from scan", buf.buf);

		r->alive = false;
@@ -556,12 +555,34 @@ int bch2_check_topology(struct bch_fs *c)
			bch2_shoot_down_journal_keys(c, i, 1, BTREE_MAX_DEPTH, POS_MIN, SPOS_MAX);
			ret = bch2_get_scanned_nodes(c, i, 0, POS_MIN, SPOS_MAX);
			if (ret)
					break;
				goto err;
		}

			reconstructed_root = true;
		*reconstructed_root = true;
	}
err:
fsck_err:
	printbuf_exit(&buf);
	bch_err_fn(c, ret);
	return ret;
}

int bch2_check_topology(struct bch_fs *c)
{
	struct btree_trans *trans = bch2_trans_get(c);
	struct bpos pulled_from_scan = POS_MIN;
	int ret = 0;

	bch2_trans_srcu_unlock(trans);

	for (unsigned i = 0; i < btree_id_nr_alive(c) && !ret; i++) {
		bool reconstructed_root = false;
recover:
		ret = lockrestart_do(trans, bch2_check_root(trans, i, &reconstructed_root));
		if (ret)
			break;

		struct btree_root *r = bch2_btree_id_root(c, i);
		struct btree *b = r->b;

		btree_node_lock_nopath_nofail(trans, &b->c, SIX_LOCK_read);
@@ -575,17 +596,21 @@ int bch2_check_topology(struct bch_fs *c)

			r->b = NULL;

			if (!reconstructed_root)
				goto reconstruct_root;
			if (!reconstructed_root) {
				r->error = -EIO;
				goto recover;
			}

			struct printbuf buf = PRINTBUF;
			bch2_btree_id_to_text(&buf, i);
			bch_err(c, "empty btree root %s", buf.buf);
			printbuf_exit(&buf);
			bch2_btree_root_alloc_fake_trans(trans, i, 0);
			r->alive = false;
			ret = 0;
		}
	}
fsck_err:
	printbuf_exit(&buf);

	bch2_trans_put(trans);
	return ret;
}