Commit 3e72acb7 authored by Kent Overstreet's avatar Kent Overstreet
Browse files

bcachefs: Ensure btree node scan runs before checking for scanned nodes



Previously, calling bch2_btree_has_scanned_nodes() when btree node
scan hadn't actually run would erroniously return false - causing us to
think a btree was entirely gone.

This fixes a 6.16 regression from moving the scheduling of btree node
scan out of bch2_btree_lost_data() (fixing the bug where we'd schedule
it persistently in the superblock) and only scheduling it when
check_toploogy() is asking for scanned btree nodes.

Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 1dcea078
Loading
Loading
Loading
Loading
+18 −11
Original line number Diff line number Diff line
@@ -534,32 +534,39 @@ static int bch2_btree_repair_topology_recurse(struct btree_trans *trans, struct
	return ret;
}

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

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

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

		r->alive = false;
		r->error = 0;
		ret = bch2_btree_has_scanned_nodes(c, btree);
		if (ret < 0)
			goto err;

		if (!bch2_btree_has_scanned_nodes(c, i)) {
		if (!ret) {
			__fsck_err(trans,
				   FSCK_CAN_FIX|(!btree_id_important(i) ? FSCK_AUTOFIX : 0),
				   FSCK_CAN_FIX|(!btree_id_important(btree) ? FSCK_AUTOFIX : 0),
				   btree_root_unreadable_and_scan_found_nothing,
				   "no nodes found for btree %s, continue?", buf.buf);
			bch2_btree_root_alloc_fake_trans(trans, i, 0);

			r->alive = false;
			r->error = 0;
			bch2_btree_root_alloc_fake_trans(trans, btree, 0);
		} else {
			bch2_btree_root_alloc_fake_trans(trans, i, 1);
			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);
			r->alive = false;
			r->error = 0;
			bch2_btree_root_alloc_fake_trans(trans, btree, 1);

			bch2_shoot_down_journal_keys(c, btree, 1, BTREE_MAX_DEPTH, POS_MIN, SPOS_MAX);
			ret = bch2_get_scanned_nodes(c, btree, 0, POS_MIN, SPOS_MAX);
			if (ret)
				goto err;
		}
+5 −1
Original line number Diff line number Diff line
@@ -521,8 +521,12 @@ bool bch2_btree_node_is_stale(struct bch_fs *c, struct btree *b)
	return false;
}

bool bch2_btree_has_scanned_nodes(struct bch_fs *c, enum btree_id btree)
int bch2_btree_has_scanned_nodes(struct bch_fs *c, enum btree_id btree)
{
	int ret = bch2_run_print_explicit_recovery_pass(c, BCH_RECOVERY_PASS_scan_for_btree_nodes);
	if (ret)
		return ret;

	struct found_btree_node search = {
		.btree_id	= btree,
		.level		= 0,
+1 −1
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@

int bch2_scan_for_btree_nodes(struct bch_fs *);
bool bch2_btree_node_is_stale(struct bch_fs *, struct btree *);
bool bch2_btree_has_scanned_nodes(struct bch_fs *, enum btree_id);
int bch2_btree_has_scanned_nodes(struct bch_fs *, enum btree_id);
int bch2_get_scanned_nodes(struct bch_fs *, enum btree_id, unsigned, struct bpos, struct bpos);
void bch2_find_btree_nodes_exit(struct find_btree_nodes *);