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: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
@@ -1045,6 +1045,7 @@ got_good_key:
|
||||
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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user