summaryrefslogtreecommitdiff
path: root/fs/bcachefs/fsck.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/bcachefs/fsck.c')
-rw-r--r--fs/bcachefs/fsck.c53
1 files changed, 52 insertions, 1 deletions
diff --git a/fs/bcachefs/fsck.c b/fs/bcachefs/fsck.c
index 62756f465e56..00afe0a3593f 100644
--- a/fs/bcachefs/fsck.c
+++ b/fs/bcachefs/fsck.c
@@ -1500,6 +1500,10 @@ static int check_key_has_inode(struct btree_trans *trans,
SPOS(k.k->p.inode, 0, k.k->p.snapshot),
POS(k.k->p.inode, U64_MAX),
0, k2, ret) {
+ if (k.k->type == KEY_TYPE_error ||
+ k.k->type == KEY_TYPE_hash_whiteout)
+ continue;
+
nr_keys++;
if (nr_keys <= 10) {
bch2_bkey_val_to_text(&buf, c, k2);
@@ -1512,9 +1516,11 @@ static int check_key_has_inode(struct btree_trans *trans,
if (ret)
goto err;
+ unsigned reconstruct_limit = iter->btree_id == BTREE_ID_extents ? 3 : 0;
+
if (nr_keys > 100)
prt_printf(&buf, "found > %u keys for this missing inode\n", nr_keys);
- else if (nr_keys > 10)
+ else if (nr_keys > reconstruct_limit)
prt_printf(&buf, "found %u keys for this missing inode\n", nr_keys);
if (!have_inode) {
@@ -1572,6 +1578,44 @@ reconstruct:
goto out;
}
+static int maybe_reconstruct_inum_btree(struct btree_trans *trans,
+ u64 inum, u32 snapshot,
+ enum btree_id btree)
+{
+ struct btree_iter iter;
+ struct bkey_s_c k;
+ int ret = 0;
+
+ for_each_btree_key_max_norestart(trans, iter, btree,
+ SPOS(inum, 0, snapshot),
+ POS(inum, U64_MAX),
+ 0, k, ret) {
+ ret = 1;
+ break;
+ }
+ bch2_trans_iter_exit(trans, &iter);
+
+ if (ret <= 0)
+ return ret;
+
+ if (fsck_err(trans, missing_inode_with_contents,
+ "inode %llu:%u type %s missing, but contents found: reconstruct?",
+ inum, snapshot,
+ btree == BTREE_ID_extents ? "reg" : "dir"))
+ return reconstruct_inode(trans, btree, snapshot, inum) ?:
+ bch2_trans_commit(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc) ?:
+ bch_err_throw(trans->c, transaction_restart_commit);
+fsck_err:
+ return ret;
+}
+
+static int maybe_reconstruct_inum(struct btree_trans *trans,
+ u64 inum, u32 snapshot)
+{
+ return maybe_reconstruct_inum_btree(trans, inum, snapshot, BTREE_ID_extents) ?:
+ maybe_reconstruct_inum_btree(trans, inum, snapshot, BTREE_ID_dirents);
+}
+
static int check_i_sectors_notnested(struct btree_trans *trans, struct inode_walker *w)
{
struct bch_fs *c = trans->c;
@@ -2366,6 +2410,13 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
if (ret)
goto err;
+ if (!target->inodes.nr) {
+ ret = maybe_reconstruct_inum(trans, le64_to_cpu(d.v->d_inum),
+ d.k->p.snapshot);
+ if (ret)
+ return ret;
+ }
+
if (fsck_err_on(!target->inodes.nr,
trans, dirent_to_missing_inode,
"dirent points to missing inode:\n%s",