diff options
Diffstat (limited to 'fs/bcachefs/fsck.c')
-rw-r--r-- | fs/bcachefs/fsck.c | 53 |
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", |