bcachefs: Flag btrees with missing data

We need this to know when we should attempt to reconstruct the snapshots
btree

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
Kent Overstreet 2024-03-15 23:03:42 -04:00
parent 43f5ea4646
commit 55936afe11
6 changed files with 44 additions and 5 deletions

View file

@ -797,6 +797,7 @@ struct bch_fs {
u64 features; u64 features;
u64 compat; u64 compat;
unsigned long errors_silent[BITS_TO_LONGS(BCH_SB_ERR_MAX)]; unsigned long errors_silent[BITS_TO_LONGS(BCH_SB_ERR_MAX)];
u64 btrees_lost_data;
} sb; } sb;

View file

@ -818,6 +818,7 @@ struct bch_sb_field_ext {
struct bch_sb_field field; struct bch_sb_field field;
__le64 recovery_passes_required[2]; __le64 recovery_passes_required[2];
__le64 errors_silent[8]; __le64 errors_silent[8];
__le64 btrees_lost_data;
}; };
struct bch_sb_field_downgrade_entry { struct bch_sb_field_downgrade_entry {

View file

@ -1264,10 +1264,12 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct bch_dev *ca,
return retry_read; return retry_read;
fsck_err: fsck_err:
if (ret == -BCH_ERR_btree_node_read_err_want_retry || if (ret == -BCH_ERR_btree_node_read_err_want_retry ||
ret == -BCH_ERR_btree_node_read_err_must_retry) ret == -BCH_ERR_btree_node_read_err_must_retry) {
retry_read = 1; retry_read = 1;
else } else {
set_btree_node_read_error(b); set_btree_node_read_error(b);
bch2_btree_lost_data(c, b->c.btree_id);
}
goto out; goto out;
} }
@ -1328,6 +1330,7 @@ static void btree_node_read_work(struct work_struct *work)
if (!can_retry) { if (!can_retry) {
set_btree_node_read_error(b); set_btree_node_read_error(b);
bch2_btree_lost_data(c, b->c.btree_id);
break; break;
} }
} }
@ -1527,9 +1530,10 @@ static CLOSURE_CALLBACK(btree_node_read_all_replicas_done)
ret = -1; ret = -1;
} }
if (ret) if (ret) {
set_btree_node_read_error(b); set_btree_node_read_error(b);
else if (*saw_error) bch2_btree_lost_data(c, b->c.btree_id);
} else if (*saw_error)
bch2_btree_node_rewrite_async(c, b); bch2_btree_node_rewrite_async(c, b);
for (i = 0; i < ra->nr; i++) { for (i = 0; i < ra->nr; i++) {
@ -1665,6 +1669,7 @@ void bch2_btree_node_read(struct btree_trans *trans, struct btree *b,
bch2_fatal_error(c); bch2_fatal_error(c);
set_btree_node_read_error(b); set_btree_node_read_error(b);
bch2_btree_lost_data(c, b->c.btree_id);
clear_btree_node_read_in_flight(b); clear_btree_node_read_in_flight(b);
wake_up_bit(&b->flags, BTREE_NODE_read_in_flight); wake_up_bit(&b->flags, BTREE_NODE_read_in_flight);
printbuf_exit(&buf); printbuf_exit(&buf);

View file

@ -33,6 +33,20 @@
#define QSTR(n) { { { .len = strlen(n) } }, .name = n } #define QSTR(n) { { { .len = strlen(n) } }, .name = n }
void bch2_btree_lost_data(struct bch_fs *c, enum btree_id btree)
{
u64 b = BIT_ULL(btree);
if (!(c->sb.btrees_lost_data & b)) {
bch_err(c, "flagging btree %s lost data", bch2_btree_id_str(btree));
mutex_lock(&c->sb_lock);
bch2_sb_field_get(c->disk_sb.sb, ext)->btrees_lost_data |= cpu_to_le64(b);
bch2_write_super(c);
mutex_unlock(&c->sb_lock);
}
}
static bool btree_id_is_alloc(enum btree_id id) static bool btree_id_is_alloc(enum btree_id id)
{ {
switch (id) { switch (id) {
@ -470,6 +484,7 @@ static int read_btree_roots(struct bch_fs *c)
} }
ret = 0; ret = 0;
bch2_btree_lost_data(c, i);
} }
} }
@ -848,6 +863,14 @@ int bch2_fs_recovery(struct bch_fs *c)
write_sb = true; write_sb = true;
} }
if (c->opts.fsck &&
!test_bit(BCH_FS_error, &c->flags) &&
c->recovery_pass_done == BCH_RECOVERY_PASS_NR - 1 &&
ext->btrees_lost_data) {
ext->btrees_lost_data = 0;
write_sb = true;
}
if (c->opts.fsck && if (c->opts.fsck &&
!test_bit(BCH_FS_error, &c->flags) && !test_bit(BCH_FS_error, &c->flags) &&
!test_bit(BCH_FS_errors_not_fixed, &c->flags)) { !test_bit(BCH_FS_errors_not_fixed, &c->flags)) {

View file

@ -2,6 +2,8 @@
#ifndef _BCACHEFS_RECOVERY_H #ifndef _BCACHEFS_RECOVERY_H
#define _BCACHEFS_RECOVERY_H #define _BCACHEFS_RECOVERY_H
void bch2_btree_lost_data(struct bch_fs *, enum btree_id);
int bch2_journal_replay(struct bch_fs *); int bch2_journal_replay(struct bch_fs *);
int bch2_fs_recovery(struct bch_fs *); int bch2_fs_recovery(struct bch_fs *);

View file

@ -527,9 +527,11 @@ static void bch2_sb_update(struct bch_fs *c)
memset(c->sb.errors_silent, 0, sizeof(c->sb.errors_silent)); memset(c->sb.errors_silent, 0, sizeof(c->sb.errors_silent));
struct bch_sb_field_ext *ext = bch2_sb_field_get(src, ext); struct bch_sb_field_ext *ext = bch2_sb_field_get(src, ext);
if (ext) if (ext) {
le_bitvector_to_cpu(c->sb.errors_silent, (void *) ext->errors_silent, le_bitvector_to_cpu(c->sb.errors_silent, (void *) ext->errors_silent,
sizeof(c->sb.errors_silent) * 8); sizeof(c->sb.errors_silent) * 8);
c->sb.btrees_lost_data = le64_to_cpu(ext->btrees_lost_data);
}
for_each_member_device(c, ca) { for_each_member_device(c, ca) {
struct bch_member m = bch2_sb_member_get(src, ca->dev_idx); struct bch_member m = bch2_sb_member_get(src, ca->dev_idx);
@ -1162,6 +1164,11 @@ static void bch2_sb_ext_to_text(struct printbuf *out, struct bch_sb *sb,
kfree(errors_silent); kfree(errors_silent);
} }
prt_printf(out, "Btrees with missing data:");
prt_tab(out);
prt_bitflags(out, __bch2_btree_ids, le64_to_cpu(e->btrees_lost_data));
prt_newline(out);
} }
static const struct bch_sb_field_ops bch_sb_field_ops_ext = { static const struct bch_sb_field_ops bch_sb_field_ops_ext = {