bcachefs: reconstruct_alloc cleanup

Now that we've got the errors_silent mechanism, we don't have to check
if the reconstruct_alloc option is set all over the place.

Also - users no longer have to explicitly select fsck and fix_errors.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
Kent Overstreet 2024-03-11 21:15:26 -04:00
parent 3bbed37214
commit cdce109431
7 changed files with 113 additions and 95 deletions

View File

@ -1052,14 +1052,13 @@ int bch2_check_alloc_key(struct btree_trans *trans,
if (ret) if (ret)
goto err; goto err;
if (k.k->type != discard_key_type && if (fsck_err_on(k.k->type != discard_key_type,
(c->opts.reconstruct_alloc || c, need_discard_key_wrong,
fsck_err(c, need_discard_key_wrong, "incorrect key in need_discard btree (got %s should be %s)\n"
"incorrect key in need_discard btree (got %s should be %s)\n" " %s",
" %s", bch2_bkey_types[k.k->type],
bch2_bkey_types[k.k->type], bch2_bkey_types[discard_key_type],
bch2_bkey_types[discard_key_type], (bch2_bkey_val_to_text(&buf, c, alloc_k), buf.buf))) {
(bch2_bkey_val_to_text(&buf, c, alloc_k), buf.buf)))) {
struct bkey_i *update = struct bkey_i *update =
bch2_trans_kmalloc(trans, sizeof(*update)); bch2_trans_kmalloc(trans, sizeof(*update));
@ -1083,15 +1082,14 @@ int bch2_check_alloc_key(struct btree_trans *trans,
if (ret) if (ret)
goto err; goto err;
if (k.k->type != freespace_key_type && if (fsck_err_on(k.k->type != freespace_key_type,
(c->opts.reconstruct_alloc || c, freespace_key_wrong,
fsck_err(c, freespace_key_wrong, "incorrect key in freespace btree (got %s should be %s)\n"
"incorrect key in freespace btree (got %s should be %s)\n" " %s",
" %s", bch2_bkey_types[k.k->type],
bch2_bkey_types[k.k->type], bch2_bkey_types[freespace_key_type],
bch2_bkey_types[freespace_key_type], (printbuf_reset(&buf),
(printbuf_reset(&buf), bch2_bkey_val_to_text(&buf, c, alloc_k), buf.buf))) {
bch2_bkey_val_to_text(&buf, c, alloc_k), buf.buf)))) {
struct bkey_i *update = struct bkey_i *update =
bch2_trans_kmalloc(trans, sizeof(*update)); bch2_trans_kmalloc(trans, sizeof(*update));
@ -1115,14 +1113,13 @@ int bch2_check_alloc_key(struct btree_trans *trans,
if (ret) if (ret)
goto err; goto err;
if (a->gen != alloc_gen(k, gens_offset) && if (fsck_err_on(a->gen != alloc_gen(k, gens_offset),
(c->opts.reconstruct_alloc || c, bucket_gens_key_wrong,
fsck_err(c, bucket_gens_key_wrong, "incorrect gen in bucket_gens btree (got %u should be %u)\n"
"incorrect gen in bucket_gens btree (got %u should be %u)\n" " %s",
" %s", alloc_gen(k, gens_offset), a->gen,
alloc_gen(k, gens_offset), a->gen, (printbuf_reset(&buf),
(printbuf_reset(&buf), bch2_bkey_val_to_text(&buf, c, alloc_k), buf.buf))) {
bch2_bkey_val_to_text(&buf, c, alloc_k), buf.buf)))) {
struct bkey_i_bucket_gens *g = struct bkey_i_bucket_gens *g =
bch2_trans_kmalloc(trans, sizeof(*g)); bch2_trans_kmalloc(trans, sizeof(*g));
@ -1174,14 +1171,13 @@ int bch2_check_alloc_hole_freespace(struct btree_trans *trans,
*end = bkey_min(k.k->p, *end); *end = bkey_min(k.k->p, *end);
if (k.k->type != KEY_TYPE_set && if (fsck_err_on(k.k->type != KEY_TYPE_set,
(c->opts.reconstruct_alloc || c, freespace_hole_missing,
fsck_err(c, freespace_hole_missing, "hole in alloc btree missing in freespace btree\n"
"hole in alloc btree missing in freespace btree\n" " device %llu buckets %llu-%llu",
" device %llu buckets %llu-%llu", freespace_iter->pos.inode,
freespace_iter->pos.inode, freespace_iter->pos.offset,
freespace_iter->pos.offset, end->offset)) {
end->offset))) {
struct bkey_i *update = struct bkey_i *update =
bch2_trans_kmalloc(trans, sizeof(*update)); bch2_trans_kmalloc(trans, sizeof(*update));

View File

@ -477,8 +477,7 @@ missing:
prt_printf(&buf, "\nbp pos "); prt_printf(&buf, "\nbp pos ");
bch2_bpos_to_text(&buf, bp_iter.pos); bch2_bpos_to_text(&buf, bp_iter.pos);
if (c->opts.reconstruct_alloc || if (fsck_err(c, ptr_to_missing_backpointer, "%s", buf.buf))
fsck_err(c, ptr_to_missing_backpointer, "%s", buf.buf))
ret = bch2_bucket_backpointer_mod(trans, bucket, bp, orig_k, true); ret = bch2_bucket_backpointer_mod(trans, bucket, bp, orig_k, true);
goto out; goto out;

View File

@ -593,16 +593,15 @@ static int bch2_check_fix_ptrs(struct btree_trans *trans, enum btree_id btree_id
struct bucket *g = PTR_GC_BUCKET(ca, &p.ptr); struct bucket *g = PTR_GC_BUCKET(ca, &p.ptr);
enum bch_data_type data_type = bch2_bkey_ptr_data_type(*k, &entry_c->ptr); enum bch_data_type data_type = bch2_bkey_ptr_data_type(*k, &entry_c->ptr);
if (!g->gen_valid && if (fsck_err_on(!g->gen_valid,
(c->opts.reconstruct_alloc || c, ptr_to_missing_alloc_key,
fsck_err(c, ptr_to_missing_alloc_key, "bucket %u:%zu data type %s ptr gen %u missing in alloc btree\n"
"bucket %u:%zu data type %s ptr gen %u missing in alloc btree\n" "while marking %s",
"while marking %s", p.ptr.dev, PTR_BUCKET_NR(ca, &p.ptr),
p.ptr.dev, PTR_BUCKET_NR(ca, &p.ptr), bch2_data_type_str(ptr_data_type(k->k, &p.ptr)),
bch2_data_type_str(ptr_data_type(k->k, &p.ptr)), p.ptr.gen,
p.ptr.gen, (printbuf_reset(&buf),
(printbuf_reset(&buf), bch2_bkey_val_to_text(&buf, c, *k), buf.buf))) {
bch2_bkey_val_to_text(&buf, c, *k), buf.buf)))) {
if (!p.ptr.cached) { if (!p.ptr.cached) {
g->gen_valid = true; g->gen_valid = true;
g->gen = p.ptr.gen; g->gen = p.ptr.gen;
@ -611,16 +610,15 @@ static int bch2_check_fix_ptrs(struct btree_trans *trans, enum btree_id btree_id
} }
} }
if (gen_cmp(p.ptr.gen, g->gen) > 0 && if (fsck_err_on(gen_cmp(p.ptr.gen, g->gen) > 0,
(c->opts.reconstruct_alloc || c, ptr_gen_newer_than_bucket_gen,
fsck_err(c, ptr_gen_newer_than_bucket_gen, "bucket %u:%zu data type %s ptr gen in the future: %u > %u\n"
"bucket %u:%zu data type %s ptr gen in the future: %u > %u\n" "while marking %s",
"while marking %s", p.ptr.dev, PTR_BUCKET_NR(ca, &p.ptr),
p.ptr.dev, PTR_BUCKET_NR(ca, &p.ptr), bch2_data_type_str(ptr_data_type(k->k, &p.ptr)),
bch2_data_type_str(ptr_data_type(k->k, &p.ptr)), p.ptr.gen, g->gen,
p.ptr.gen, g->gen, (printbuf_reset(&buf),
(printbuf_reset(&buf), bch2_bkey_val_to_text(&buf, c, *k), buf.buf))) {
bch2_bkey_val_to_text(&buf, c, *k), buf.buf)))) {
if (!p.ptr.cached) { if (!p.ptr.cached) {
g->gen_valid = true; g->gen_valid = true;
g->gen = p.ptr.gen; g->gen = p.ptr.gen;
@ -633,28 +631,26 @@ static int bch2_check_fix_ptrs(struct btree_trans *trans, enum btree_id btree_id
} }
} }
if (gen_cmp(g->gen, p.ptr.gen) > BUCKET_GC_GEN_MAX && if (fsck_err_on(gen_cmp(g->gen, p.ptr.gen) > BUCKET_GC_GEN_MAX,
(c->opts.reconstruct_alloc || c, ptr_gen_newer_than_bucket_gen,
fsck_err(c, ptr_gen_newer_than_bucket_gen, "bucket %u:%zu gen %u data type %s: ptr gen %u too stale\n"
"bucket %u:%zu gen %u data type %s: ptr gen %u too stale\n" "while marking %s",
"while marking %s", p.ptr.dev, PTR_BUCKET_NR(ca, &p.ptr), g->gen,
p.ptr.dev, PTR_BUCKET_NR(ca, &p.ptr), g->gen, bch2_data_type_str(ptr_data_type(k->k, &p.ptr)),
bch2_data_type_str(ptr_data_type(k->k, &p.ptr)), p.ptr.gen,
p.ptr.gen, (printbuf_reset(&buf),
(printbuf_reset(&buf), bch2_bkey_val_to_text(&buf, c, *k), buf.buf)))
bch2_bkey_val_to_text(&buf, c, *k), buf.buf))))
do_update = true; do_update = true;
if (!p.ptr.cached && gen_cmp(p.ptr.gen, g->gen) < 0 && if (fsck_err_on(!p.ptr.cached && gen_cmp(p.ptr.gen, g->gen) < 0,
(c->opts.reconstruct_alloc || c, stale_dirty_ptr,
fsck_err(c, stale_dirty_ptr, "bucket %u:%zu data type %s stale dirty ptr: %u < %u\n"
"bucket %u:%zu data type %s stale dirty ptr: %u < %u\n" "while marking %s",
"while marking %s", p.ptr.dev, PTR_BUCKET_NR(ca, &p.ptr),
p.ptr.dev, PTR_BUCKET_NR(ca, &p.ptr), bch2_data_type_str(ptr_data_type(k->k, &p.ptr)),
bch2_data_type_str(ptr_data_type(k->k, &p.ptr)), p.ptr.gen, g->gen,
p.ptr.gen, g->gen, (printbuf_reset(&buf),
(printbuf_reset(&buf), bch2_bkey_val_to_text(&buf, c, *k), buf.buf)))
bch2_bkey_val_to_text(&buf, c, *k), buf.buf))))
do_update = true; do_update = true;
if (data_type != BCH_DATA_btree && p.ptr.gen != g->gen) if (data_type != BCH_DATA_btree && p.ptr.gen != g->gen)
@ -1411,8 +1407,7 @@ static int bch2_alloc_write_key(struct btree_trans *trans,
if (gen_after(old->gen, gc.gen)) if (gen_after(old->gen, gc.gen))
return 0; return 0;
if (c->opts.reconstruct_alloc || if (fsck_err_on(new.data_type != gc.data_type, c,
fsck_err_on(new.data_type != gc.data_type, c,
alloc_key_data_type_wrong, alloc_key_data_type_wrong,
"bucket %llu:%llu gen %u has wrong data_type" "bucket %llu:%llu gen %u has wrong data_type"
": got %s, should be %s", ": got %s, should be %s",
@ -1423,8 +1418,7 @@ static int bch2_alloc_write_key(struct btree_trans *trans,
new.data_type = gc.data_type; new.data_type = gc.data_type;
#define copy_bucket_field(_errtype, _f) \ #define copy_bucket_field(_errtype, _f) \
if (c->opts.reconstruct_alloc || \ if (fsck_err_on(new._f != gc._f, c, _errtype, \
fsck_err_on(new._f != gc._f, c, _errtype, \
"bucket %llu:%llu gen %u data type %s has wrong " #_f \ "bucket %llu:%llu gen %u data type %s has wrong " #_f \
": got %u, should be %u", \ ": got %u, should be %u", \
iter->pos.inode, iter->pos.offset, \ iter->pos.inode, iter->pos.offset, \

View File

@ -125,8 +125,7 @@ static int bch2_check_lru_key(struct btree_trans *trans,
goto out; goto out;
} }
if (c->opts.reconstruct_alloc || if (fsck_err(c, lru_entry_bad,
fsck_err(c, lru_entry_bad,
"incorrect lru entry: lru %s time %llu\n" "incorrect lru entry: lru %s time %llu\n"
" %s\n" " %s\n"
" for %s", " for %s",

View File

@ -52,14 +52,47 @@ static bool btree_id_is_alloc(enum btree_id id)
} }
/* for -o reconstruct_alloc: */ /* for -o reconstruct_alloc: */
static void drop_alloc_keys(struct journal_keys *keys) static void do_reconstruct_alloc(struct bch_fs *c)
{ {
bch2_journal_log_msg(c, "dropping alloc info");
bch_info(c, "dropping and reconstructing all alloc info");
mutex_lock(&c->sb_lock);
struct bch_sb_field_ext *ext = bch2_sb_field_get(c->disk_sb.sb, ext);
__set_bit_le64(BCH_RECOVERY_PASS_STABLE_check_allocations, ext->recovery_passes_required);
__set_bit_le64(BCH_RECOVERY_PASS_STABLE_check_alloc_info, ext->recovery_passes_required);
__set_bit_le64(BCH_RECOVERY_PASS_STABLE_check_lrus, ext->recovery_passes_required);
__set_bit_le64(BCH_RECOVERY_PASS_STABLE_check_extents_to_backpointers, ext->recovery_passes_required);
__set_bit_le64(BCH_RECOVERY_PASS_STABLE_check_alloc_to_lru_refs, ext->recovery_passes_required);
__set_bit_le64(BCH_FSCK_ERR_ptr_to_missing_alloc_key, ext->errors_silent);
__set_bit_le64(BCH_FSCK_ERR_ptr_gen_newer_than_bucket_gen, ext->errors_silent);
__set_bit_le64(BCH_FSCK_ERR_stale_dirty_ptr, ext->errors_silent);
__set_bit_le64(BCH_FSCK_ERR_alloc_key_data_type_wrong, ext->errors_silent);
__set_bit_le64(BCH_FSCK_ERR_alloc_key_gen_wrong, ext->errors_silent);
__set_bit_le64(BCH_FSCK_ERR_alloc_key_dirty_sectors_wrong, ext->errors_silent);
__set_bit_le64(BCH_FSCK_ERR_alloc_key_stripe_wrong, ext->errors_silent);
__set_bit_le64(BCH_FSCK_ERR_alloc_key_stripe_redundancy_wrong, ext->errors_silent);
__set_bit_le64(BCH_FSCK_ERR_need_discard_key_wrong, ext->errors_silent);
__set_bit_le64(BCH_FSCK_ERR_freespace_key_wrong, ext->errors_silent);
__set_bit_le64(BCH_FSCK_ERR_bucket_gens_key_wrong, ext->errors_silent);
__set_bit_le64(BCH_FSCK_ERR_freespace_hole_missing, ext->errors_silent);
__set_bit_le64(BCH_FSCK_ERR_ptr_to_missing_backpointer, ext->errors_silent);
__set_bit_le64(BCH_FSCK_ERR_lru_entry_bad, ext->errors_silent);
c->sb.compat &= ~(1ULL << BCH_COMPAT_alloc_info);
bch2_write_super(c);
mutex_unlock(&c->sb_lock);
c->recovery_passes_explicit |= bch2_recovery_passes_from_stable(le64_to_cpu(ext->recovery_passes_required[0]));
struct journal_keys *keys = &c->journal_keys;
size_t src, dst; size_t src, dst;
for (src = 0, dst = 0; src < keys->nr; src++) for (src = 0, dst = 0; src < keys->nr; src++)
if (!btree_id_is_alloc(keys->data[src].btree_id)) if (!btree_id_is_alloc(keys->data[src].btree_id))
keys->data[dst++] = keys->data[src]; keys->data[dst++] = keys->data[src];
keys->nr = dst; keys->nr = dst;
} }
@ -395,11 +428,8 @@ static int read_btree_roots(struct bch_fs *c)
if (!r->alive) if (!r->alive)
continue; continue;
if (btree_id_is_alloc(i) && if (btree_id_is_alloc(i) && c->opts.reconstruct_alloc)
c->opts.reconstruct_alloc) {
c->sb.compat &= ~(1ULL << BCH_COMPAT_alloc_info);
continue; continue;
}
if (r->error) { if (r->error) {
__fsck_err(c, __fsck_err(c,
@ -930,10 +960,8 @@ use_clean:
c->journal_replay_seq_start = last_seq; c->journal_replay_seq_start = last_seq;
c->journal_replay_seq_end = blacklist_seq - 1; c->journal_replay_seq_end = blacklist_seq - 1;
if (c->opts.reconstruct_alloc) { if (c->opts.reconstruct_alloc)
c->sb.compat &= ~(1ULL << BCH_COMPAT_alloc_info); do_reconstruct_alloc(c);
drop_alloc_keys(&c->journal_keys);
}
zero_out_btree_mem_ptr(&c->journal_keys); zero_out_btree_mem_ptr(&c->journal_keys);
@ -968,9 +996,6 @@ use_clean:
if (ret) if (ret)
goto err; goto err;
if (c->opts.reconstruct_alloc)
bch2_journal_log_msg(c, "dropping alloc info");
/* /*
* Skip past versions that might have possibly been used (as nonces), * Skip past versions that might have possibly been used (as nonces),
* but hadn't had their pointers written: * but hadn't had their pointers written:

View File

@ -259,7 +259,7 @@ void bch2_sb_set_downgrade(struct bch_fs *c, unsigned new_minor, unsigned old_mi
if (e < BCH_SB_ERR_MAX) if (e < BCH_SB_ERR_MAX)
__set_bit(e, c->sb.errors_silent); __set_bit(e, c->sb.errors_silent);
if (e < sizeof(ext->errors_silent) * 8) if (e < sizeof(ext->errors_silent) * 8)
ext->errors_silent[e / 64] |= cpu_to_le64(BIT_ULL(e % 64)); __set_bit_le64(e, ext->errors_silent);
} }
} }
} }

View File

@ -864,4 +864,9 @@ static inline int copy_from_user_errcode(void *to, const void __user *from, unsi
#endif #endif
static inline void __set_bit_le64(size_t bit, __le64 *addr)
{
addr[bit / 64] |= cpu_to_le64(BIT_ULL(bit % 64));
}
#endif /* _BCACHEFS_UTIL_H */ #endif /* _BCACHEFS_UTIL_H */