@@ -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+
462489struct 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