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

bcachefs: Add more flags to btree nodes for rewrite reason



It seems excessive forced btree node rewrites can cause interior btree
updates to become wedged during recovery, before we're using the write
buffer for backpointer updates.

Add more flags so we can determine where these are coming from.

Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent c7e351be
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -1045,6 +1045,7 @@ static int validate_bset_keys(struct bch_fs *c, struct btree *b,
		le16_add_cpu(&i->u64s, -next_good_key);
		memmove_u64s_down(k, (u64 *) k + next_good_key, (u64 *) vstruct_end(i) - (u64 *) k);
		set_btree_node_need_rewrite(b);
		set_btree_node_need_rewrite_error(b);
	}
fsck_err:
	printbuf_exit(&buf);
@@ -1305,6 +1306,7 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct bch_dev *ca,
					  (u64 *) vstruct_end(i) - (u64 *) k);
			set_btree_bset_end(b, b->set);
			set_btree_node_need_rewrite(b);
			set_btree_node_need_rewrite_error(b);
			continue;
		}
		if (ret)
@@ -1329,12 +1331,16 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct bch_dev *ca,
		bkey_for_each_ptr(bch2_bkey_ptrs(bkey_i_to_s(&b->key)), ptr) {
			struct bch_dev *ca2 = bch2_dev_rcu(c, ptr->dev);

			if (!ca2 || ca2->mi.state != BCH_MEMBER_STATE_rw)
			if (!ca2 || ca2->mi.state != BCH_MEMBER_STATE_rw) {
				set_btree_node_need_rewrite(b);
				set_btree_node_need_rewrite_degraded(b);
			}
		}

	if (!ptr_written)
	if (!ptr_written) {
		set_btree_node_need_rewrite(b);
		set_btree_node_need_rewrite_ptr_written_zero(b);
	}
fsck_err:
	mempool_free(iter, &c->fill_iter);
	printbuf_exit(&buf);
+29 −0
Original line number Diff line number Diff line
@@ -617,6 +617,9 @@ enum btree_write_type {
	x(dying)							\
	x(fake)								\
	x(need_rewrite)							\
	x(need_rewrite_error)						\
	x(need_rewrite_degraded)					\
	x(need_rewrite_ptr_written_zero)				\
	x(never_write)							\
	x(pinned)

@@ -641,6 +644,32 @@ static inline void clear_btree_node_ ## flag(struct btree *b) \
BTREE_FLAGS()
#undef x

#define BTREE_NODE_REWRITE_REASON()					\
	x(none)								\
	x(unknown)							\
	x(error)							\
	x(degraded)							\
	x(ptr_written_zero)

enum btree_node_rewrite_reason {
#define x(n)	BTREE_NODE_REWRITE_##n,
	BTREE_NODE_REWRITE_REASON()
#undef x
};

static inline enum btree_node_rewrite_reason btree_node_rewrite_reason(struct btree *b)
{
	if (btree_node_need_rewrite_ptr_written_zero(b))
		return BTREE_NODE_REWRITE_ptr_written_zero;
	if (btree_node_need_rewrite_degraded(b))
		return BTREE_NODE_REWRITE_degraded;
	if (btree_node_need_rewrite_error(b))
		return BTREE_NODE_REWRITE_error;
	if (btree_node_need_rewrite(b))
		return BTREE_NODE_REWRITE_unknown;
	return BTREE_NODE_REWRITE_none;
}

static inline struct btree_write *btree_current_write(struct btree *b)
{
	return b->writes + btree_node_write_idx(b);
+10 −3
Original line number Diff line number Diff line
@@ -1138,6 +1138,13 @@ static void bch2_btree_update_done(struct btree_update *as, struct btree_trans *
			       start_time);
}

static const char * const btree_node_reawrite_reason_strs[] = {
#define x(n)	#n,
	BTREE_NODE_REWRITE_REASON()
#undef x
	NULL,
};

static struct btree_update *
bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path,
			unsigned level_start, bool split,
@@ -1235,7 +1242,7 @@ bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path,
	struct btree *b = btree_path_node(path, path->level);
	as->node_start	= b->data->min_key;
	as->node_end	= b->data->max_key;
	as->node_needed_rewrite = btree_node_need_rewrite(b);
	as->node_needed_rewrite = btree_node_rewrite_reason(b);
	as->node_written = b->written;
	as->node_sectors = btree_buf_bytes(b) >> 9;
	as->node_remaining = __bch2_btree_u64s_remaining(b,
@@ -2699,11 +2706,11 @@ static void bch2_btree_update_to_text(struct printbuf *out, struct btree_update
	bch2_bpos_to_text(out, as->node_start);
	prt_char(out, ' ');
	bch2_bpos_to_text(out, as->node_end);
	prt_printf(out, "\nwritten %u/%u u64s_remaining %u need_rewrite %u",
	prt_printf(out, "\nwritten %u/%u u64s_remaining %u need_rewrite %s",
		   as->node_written,
		   as->node_sectors,
		   as->node_remaining,
		   as->node_needed_rewrite);
		   btree_node_reawrite_reason_strs[as->node_needed_rewrite]);

	prt_printf(out, "\nmode=%s nodes_written=%u cl.remaining=%u journal_seq=%llu\n",
		   bch2_btree_update_modes[as->mode],
+1 −1
Original line number Diff line number Diff line
@@ -59,7 +59,7 @@ struct btree_update {
	enum btree_id			btree_id;
	struct bpos			node_start;
	struct bpos			node_end;
	bool				node_needed_rewrite;
	enum btree_node_rewrite_reason	node_needed_rewrite;
	u16				node_written;
	u16				node_sectors;
	u16				node_remaining;