bcachefs: Check for dirents to overwritten inodes

This fixes various "dirent to missing inode" errors.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
Kent Overstreet
2024-12-31 15:59:02 -05:00
parent d3d0fac57d
commit 15734b5e6f
2 changed files with 36 additions and 5 deletions

View File

@@ -832,11 +832,13 @@ struct inode_walker {
struct bpos last_pos;
DARRAY(struct inode_walker_entry) inodes;
snapshot_id_list deletes;
};
static void inode_walker_exit(struct inode_walker *w)
{
darray_exit(&w->inodes);
darray_exit(&w->deletes);
}
static struct inode_walker inode_walker_init(void)
@@ -960,8 +962,9 @@ static int get_visible_inodes(struct btree_trans *trans,
int ret;
w->inodes.nr = 0;
w->deletes.nr = 0;
for_each_btree_key_norestart(trans, iter, BTREE_ID_inodes, POS(0, inum),
for_each_btree_key_reverse_norestart(trans, iter, BTREE_ID_inodes, SPOS(0, inum, s->pos.snapshot),
BTREE_ITER_all_snapshots, k, ret) {
if (k.k->p.offset != inum)
break;
@@ -969,10 +972,13 @@ static int get_visible_inodes(struct btree_trans *trans,
if (!ref_visible(c, s, s->pos.snapshot, k.k->p.snapshot))
continue;
if (bkey_is_inode(k.k))
add_inode(c, w, k);
if (snapshot_list_has_ancestor(c, &w->deletes, k.k->p.snapshot))
continue;
if (k.k->p.snapshot >= s->pos.snapshot)
ret = bkey_is_inode(k.k)
? add_inode(c, w, k)
: snapshot_list_add(c, &w->deletes, k.k->p.snapshot);
if (ret)
break;
}
bch2_trans_iter_exit(trans, &iter);
@@ -2380,6 +2386,30 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
if (ret)
goto err;
}
darray_for_each(target->deletes, i)
if (fsck_err_on(!snapshot_list_has_id(&s->ids, *i),
trans, dirent_to_overwritten_inode,
"dirent points to inode overwritten in snapshot %u:\n%s",
*i,
(printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, k),
buf.buf))) {
struct btree_iter delete_iter;
bch2_trans_iter_init(trans, &delete_iter,
BTREE_ID_dirents,
SPOS(k.k->p.inode, k.k->p.offset, *i),
BTREE_ITER_intent);
ret = bch2_btree_iter_traverse(&delete_iter) ?:
bch2_hash_delete_at(trans, bch2_dirent_hash_desc,
hash_info,
&delete_iter,
BTREE_UPDATE_internal_snapshot_node);
bch2_trans_iter_exit(trans, &delete_iter);
if (ret)
goto err;
}
}
ret = bch2_trans_commit(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc);

View File

@@ -256,6 +256,7 @@ enum bch_fsck_flags {
x(dirent_in_missing_dir_inode, 227, 0) \
x(dirent_in_non_dir_inode, 228, 0) \
x(dirent_to_missing_inode, 229, 0) \
x(dirent_to_overwritten_inode, 302, 0) \
x(dirent_to_missing_subvol, 230, 0) \
x(dirent_to_itself, 231, 0) \
x(quota_type_invalid, 232, 0) \
@@ -312,7 +313,7 @@ enum bch_fsck_flags {
x(logged_op_but_clean, 283, FSCK_AUTOFIX) \
x(compression_opt_not_marked_in_sb, 295, FSCK_AUTOFIX) \
x(compression_type_not_marked_in_sb, 296, FSCK_AUTOFIX) \
x(MAX, 302, 0)
x(MAX, 303, 0)
enum bch_sb_error_id {
#define x(t, n, ...) BCH_FSCK_ERR_##t = n,