mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-02-24 07:46:28 -05:00
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:
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user