Skip to content

Commit 09d4c2a

Browse files
author
Kent Overstreet
committed
bcachefs: reconstruct_inode()
If an inode is missing, but corresponding extents and dirent still exist, it's well worth recreating it - this does so. Signed-off-by: Kent Overstreet <[email protected]>
1 parent cc05329 commit 09d4c2a

File tree

1 file changed

+50
-2
lines changed

1 file changed

+50
-2
lines changed

fs/bcachefs/fsck.c

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,33 @@ static int reconstruct_subvol(struct btree_trans *trans, u32 snapshotid, u32 sub
459459
return 0;
460460
}
461461

462+
static int reconstruct_inode(struct btree_trans *trans, u32 snapshot, u64 inum, u64 size, unsigned mode)
463+
{
464+
struct bch_fs *c = trans->c;
465+
struct bch_inode_unpacked new_inode;
466+
467+
bch2_inode_init_early(c, &new_inode);
468+
bch2_inode_init_late(&new_inode, bch2_current_time(c), 0, 0, mode|0755, 0, NULL);
469+
new_inode.bi_size = size;
470+
new_inode.bi_inum = inum;
471+
472+
return __bch2_fsck_write_inode(trans, &new_inode, snapshot);
473+
}
474+
475+
static int reconstruct_reg_inode(struct btree_trans *trans, u32 snapshot, u64 inum)
476+
{
477+
struct btree_iter iter = {};
478+
479+
bch2_trans_iter_init(trans, &iter, BTREE_ID_extents, SPOS(inum, U64_MAX, snapshot), 0);
480+
struct bkey_s_c k = bch2_btree_iter_peek_prev(&iter);
481+
bch2_trans_iter_exit(trans, &iter);
482+
int ret = bkey_err(k);
483+
if (ret)
484+
return ret;
485+
486+
return reconstruct_inode(trans, snapshot, inum, k.k->p.offset << 9, S_IFREG);
487+
}
488+
462489
struct snapshots_seen_entry {
463490
u32 id;
464491
u32 equiv;
@@ -1535,6 +1562,17 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter,
15351562
goto err;
15361563

15371564
if (k.k->type != KEY_TYPE_whiteout) {
1565+
if (!i && (c->sb.btrees_lost_data & BIT_ULL(BTREE_ID_inodes))) {
1566+
ret = reconstruct_reg_inode(trans, k.k->p.snapshot, k.k->p.inode) ?:
1567+
bch2_trans_commit(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc);
1568+
if (ret)
1569+
goto err;
1570+
1571+
inode->last_pos.inode--;
1572+
ret = -BCH_ERR_transaction_restart_nested;
1573+
goto err;
1574+
}
1575+
15381576
if (fsck_err_on(!i, c, extent_in_missing_inode,
15391577
"extent in missing inode:\n %s",
15401578
(printbuf_reset(&buf),
@@ -2012,7 +2050,6 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
20122050
struct snapshots_seen *s)
20132051
{
20142052
struct bch_fs *c = trans->c;
2015-
struct bkey_s_c_dirent d;
20162053
struct inode_walker_entry *i;
20172054
struct printbuf buf = PRINTBUF;
20182055
struct bpos equiv;
@@ -2051,6 +2088,17 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
20512088
*hash_info = bch2_hash_info_init(c, &dir->inodes.data[0].inode);
20522089
dir->first_this_inode = false;
20532090

2091+
if (!i && (c->sb.btrees_lost_data & BIT_ULL(BTREE_ID_inodes))) {
2092+
ret = reconstruct_inode(trans, k.k->p.snapshot, k.k->p.inode, 0, S_IFDIR) ?:
2093+
bch2_trans_commit(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc);
2094+
if (ret)
2095+
goto err;
2096+
2097+
dir->last_pos.inode--;
2098+
ret = -BCH_ERR_transaction_restart_nested;
2099+
goto err;
2100+
}
2101+
20542102
if (fsck_err_on(!i, c, dirent_in_missing_dir_inode,
20552103
"dirent in nonexisting directory:\n%s",
20562104
(printbuf_reset(&buf),
@@ -2085,7 +2133,7 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
20852133
if (k.k->type != KEY_TYPE_dirent)
20862134
goto out;
20872135

2088-
d = bkey_s_c_to_dirent(k);
2136+
struct bkey_s_c_dirent d = bkey_s_c_to_dirent(k);
20892137

20902138
if (d.v->d_type == DT_SUBVOL) {
20912139
ret = check_dirent_to_subvol(trans, iter, d);

0 commit comments

Comments
 (0)