@@ -63,9 +63,7 @@ static int subvol_lookup(struct btree_trans *trans, u32 subvol,
6363 u32 * snapshot , u64 * inum )
6464{
6565 struct bch_subvolume s ;
66- int ret ;
67-
68- ret = bch2_subvolume_get (trans , subvol , false, 0 , & s );
66+ int ret = bch2_subvolume_get (trans , subvol , false, 0 , & s );
6967
7068 * snapshot = le32_to_cpu (s .snapshot );
7169 * inum = le64_to_cpu (s .inode );
@@ -170,7 +168,8 @@ static int __remove_dirent(struct btree_trans *trans, struct bpos pos)
170168
171169/* Get lost+found, create if it doesn't exist: */
172170static int lookup_lostfound (struct btree_trans * trans , u32 snapshot ,
173- struct bch_inode_unpacked * lostfound )
171+ struct bch_inode_unpacked * lostfound ,
172+ u64 reattaching_inum )
174173{
175174 struct bch_fs * c = trans -> c ;
176175 struct qstr lostfound_str = QSTR ("lost+found" );
@@ -185,19 +184,36 @@ static int lookup_lostfound(struct btree_trans *trans, u32 snapshot,
185184 return ret ;
186185
187186 subvol_inum root_inum = { .subvol = le32_to_cpu (st .master_subvol ) };
188- u32 subvol_snapshot ;
189187
190- ret = subvol_lookup (trans , le32_to_cpu (st .master_subvol ),
191- & subvol_snapshot , & root_inum .inum );
192- bch_err_msg (c , ret , "looking up root subvol" );
188+ struct bch_subvolume subvol ;
189+ ret = bch2_subvolume_get (trans , le32_to_cpu (st .master_subvol ),
190+ false, 0 , & subvol );
191+ bch_err_msg (c , ret , "looking up root subvol %u for snapshot %u" ,
192+ le32_to_cpu (st .master_subvol ), snapshot );
193193 if (ret )
194194 return ret ;
195195
196+ if (!subvol .inode ) {
197+ struct btree_iter iter ;
198+ struct bkey_i_subvolume * subvol = bch2_bkey_get_mut_typed (trans , & iter ,
199+ BTREE_ID_subvolumes , POS (0 , le32_to_cpu (st .master_subvol )),
200+ 0 , subvolume );
201+ ret = PTR_ERR_OR_ZERO (subvol );
202+ if (ret )
203+ return ret ;
204+
205+ subvol -> v .inode = cpu_to_le64 (reattaching_inum );
206+ bch2_trans_iter_exit (trans , & iter );
207+ }
208+
209+ root_inum .inum = le64_to_cpu (subvol .inode );
210+
196211 struct bch_inode_unpacked root_inode ;
197212 struct bch_hash_info root_hash_info ;
198213 u32 root_inode_snapshot = snapshot ;
199214 ret = lookup_inode (trans , root_inum .inum , & root_inode , & root_inode_snapshot );
200- bch_err_msg (c , ret , "looking up root inode" );
215+ bch_err_msg (c , ret , "looking up root inode %llu for subvol %u" ,
216+ root_inum .inum , le32_to_cpu (st .master_subvol ));
201217 if (ret )
202218 return ret ;
203219
@@ -293,7 +309,7 @@ static int reattach_inode(struct btree_trans *trans,
293309 snprintf (name_buf , sizeof (name_buf ), "%llu" , inode -> bi_inum );
294310 }
295311
296- ret = lookup_lostfound (trans , dirent_snapshot , & lostfound );
312+ ret = lookup_lostfound (trans , dirent_snapshot , & lostfound , inode -> bi_inum );
297313 if (ret )
298314 return ret ;
299315
@@ -364,6 +380,85 @@ static int reattach_subvol(struct btree_trans *trans, struct bkey_s_c_subvolume
364380 return ret ;
365381}
366382
383+ static int reconstruct_subvol (struct btree_trans * trans , u32 snapshotid , u32 subvolid , u64 inum )
384+ {
385+ struct bch_fs * c = trans -> c ;
386+
387+ if (!bch2_snapshot_is_leaf (c , snapshotid )) {
388+ bch_err (c , "need to reconstruct subvol, but have interior node snapshot" );
389+ return - BCH_ERR_fsck_repair_unimplemented ;
390+ }
391+
392+ /*
393+ * If inum isn't set, that means we're being called from check_dirents,
394+ * not check_inodes - the root of this subvolume doesn't exist or we
395+ * would have found it there:
396+ */
397+ if (!inum ) {
398+ struct btree_iter inode_iter = {};
399+ struct bch_inode_unpacked new_inode ;
400+ u64 cpu = raw_smp_processor_id ();
401+
402+ bch2_inode_init_early (c , & new_inode );
403+ bch2_inode_init_late (& new_inode , bch2_current_time (c ), 0 , 0 , S_IFDIR |0755 , 0 , NULL );
404+
405+ new_inode .bi_subvol = subvolid ;
406+
407+ int ret = bch2_inode_create (trans , & inode_iter , & new_inode , snapshotid , cpu ) ?:
408+ bch2_btree_iter_traverse (& inode_iter ) ?:
409+ bch2_inode_write (trans , & inode_iter , & new_inode );
410+ bch2_trans_iter_exit (trans , & inode_iter );
411+ if (ret )
412+ return ret ;
413+
414+ inum = new_inode .bi_inum ;
415+ }
416+
417+ bch_info (c , "reconstructing subvol %u with root inode %llu" , subvolid , inum );
418+
419+ struct bkey_i_subvolume * new_subvol = bch2_trans_kmalloc (trans , sizeof (* new_subvol ));
420+ int ret = PTR_ERR_OR_ZERO (new_subvol );
421+ if (ret )
422+ return ret ;
423+
424+ bkey_subvolume_init (& new_subvol -> k_i );
425+ new_subvol -> k .p .offset = subvolid ;
426+ new_subvol -> v .snapshot = cpu_to_le32 (snapshotid );
427+ new_subvol -> v .inode = cpu_to_le64 (inum );
428+ ret = bch2_btree_insert_trans (trans , BTREE_ID_subvolumes , & new_subvol -> k_i , 0 );
429+ if (ret )
430+ return ret ;
431+
432+ struct btree_iter iter ;
433+ struct bkey_i_snapshot * s = bch2_bkey_get_mut_typed (trans , & iter ,
434+ BTREE_ID_snapshots , POS (0 , snapshotid ),
435+ 0 , snapshot );
436+ ret = PTR_ERR_OR_ZERO (s );
437+ bch_err_msg (c , ret , "getting snapshot %u" , snapshotid );
438+ if (ret )
439+ return ret ;
440+
441+ u32 snapshot_tree = le32_to_cpu (s -> v .tree );
442+
443+ s -> v .subvol = cpu_to_le32 (subvolid );
444+ SET_BCH_SNAPSHOT_SUBVOL (& s -> v , true);
445+ bch2_trans_iter_exit (trans , & iter );
446+
447+ struct bkey_i_snapshot_tree * st = bch2_bkey_get_mut_typed (trans , & iter ,
448+ BTREE_ID_snapshot_trees , POS (0 , snapshot_tree ),
449+ 0 , snapshot_tree );
450+ ret = PTR_ERR_OR_ZERO (st );
451+ bch_err_msg (c , ret , "getting snapshot tree %u" , snapshot_tree );
452+ if (ret )
453+ return ret ;
454+
455+ if (!st -> v .master_subvol )
456+ st -> v .master_subvol = cpu_to_le32 (subvolid );
457+
458+ bch2_trans_iter_exit (trans , & iter );
459+ return 0 ;
460+ }
461+
367462struct snapshots_seen_entry {
368463 u32 id ;
369464 u32 equiv ;
@@ -1065,6 +1160,11 @@ static int check_inode(struct btree_trans *trans,
10651160 if (ret && !bch2_err_matches (ret , ENOENT ))
10661161 goto err ;
10671162
1163+ if (ret && (c -> sb .btrees_lost_data & BIT_ULL (BTREE_ID_subvolumes ))) {
1164+ ret = reconstruct_subvol (trans , k .k -> p .snapshot , u .bi_subvol , u .bi_inum );
1165+ goto do_update ;
1166+ }
1167+
10681168 if (fsck_err_on (ret ,
10691169 c , inode_bi_subvol_missing ,
10701170 "inode %llu:%u bi_subvol points to missing subvolume %u" ,
@@ -1082,7 +1182,7 @@ static int check_inode(struct btree_trans *trans,
10821182 do_update = true;
10831183 }
10841184 }
1085-
1185+ do_update :
10861186 if (do_update ) {
10871187 ret = __bch2_fsck_write_inode (trans , & u , iter -> pos .snapshot );
10881188 bch_err_msg (c , ret , "in fsck updating inode" );
@@ -1785,6 +1885,7 @@ static int check_dirent_to_subvol(struct btree_trans *trans, struct btree_iter *
17851885 u32 parent_subvol = le32_to_cpu (d .v -> d_parent_subvol );
17861886 u32 target_subvol = le32_to_cpu (d .v -> d_child_subvol );
17871887 u32 parent_snapshot ;
1888+ u32 new_parent_subvol = 0 ;
17881889 u64 parent_inum ;
17891890 struct printbuf buf = PRINTBUF ;
17901891 int ret = 0 ;
@@ -1793,6 +1894,27 @@ static int check_dirent_to_subvol(struct btree_trans *trans, struct btree_iter *
17931894 if (ret && !bch2_err_matches (ret , ENOENT ))
17941895 return ret ;
17951896
1897+ if (ret ||
1898+ (!ret && !bch2_snapshot_is_ancestor (c , parent_snapshot , d .k -> p .snapshot ))) {
1899+ int ret2 = find_snapshot_subvol (trans , d .k -> p .snapshot , & new_parent_subvol );
1900+ if (ret2 && !bch2_err_matches (ret , ENOENT ))
1901+ return ret2 ;
1902+ }
1903+
1904+ if (ret &&
1905+ !new_parent_subvol &&
1906+ (c -> sb .btrees_lost_data & BIT_ULL (BTREE_ID_subvolumes ))) {
1907+ /*
1908+ * Couldn't find a subvol for dirent's snapshot - but we lost
1909+ * subvols, so we need to reconstruct:
1910+ */
1911+ ret = reconstruct_subvol (trans , d .k -> p .snapshot , parent_subvol , 0 );
1912+ if (ret )
1913+ return ret ;
1914+
1915+ parent_snapshot = d .k -> p .snapshot ;
1916+ }
1917+
17961918 if (fsck_err_on (ret , c , dirent_to_missing_parent_subvol ,
17971919 "dirent parent_subvol points to missing subvolume\n%s" ,
17981920 (bch2_bkey_val_to_text (& buf , c , d .s_c ), buf .buf )) ||
@@ -1801,10 +1923,10 @@ static int check_dirent_to_subvol(struct btree_trans *trans, struct btree_iter *
18011923 "dirent not visible in parent_subvol (not an ancestor of subvol snap %u)\n%s" ,
18021924 parent_snapshot ,
18031925 (bch2_bkey_val_to_text (& buf , c , d .s_c ), buf .buf ))) {
1804- u32 new_parent_subvol ;
1805- ret = find_snapshot_subvol ( trans , d .k -> p .snapshot , & new_parent_subvol );
1806- if ( ret )
1807- goto err ;
1926+ if (! new_parent_subvol ) {
1927+ bch_err ( c , "could not find a subvol for snapshot %u" , d .k -> p .snapshot );
1928+ return - BCH_ERR_fsck_repair_unimplemented ;
1929+ }
18081930
18091931 struct bkey_i_dirent * new_dirent = bch2_bkey_make_mut_typed (trans , iter , & d .s_c , 0 , dirent );
18101932 ret = PTR_ERR_OR_ZERO (new_dirent );
@@ -1850,23 +1972,30 @@ static int check_dirent_to_subvol(struct btree_trans *trans, struct btree_iter *
18501972
18511973 ret = lookup_inode (trans , target_inum , & subvol_root , & target_snapshot );
18521974 if (ret && !bch2_err_matches (ret , ENOENT ))
1853- return ret ;
1975+ goto err ;
18541976
1855- if (fsck_err_on (parent_subvol != subvol_root .bi_parent_subvol ,
1977+ if (ret ) {
1978+ bch_err (c , "subvol %u points to missing inode root %llu" , target_subvol , target_inum );
1979+ ret = - BCH_ERR_fsck_repair_unimplemented ;
1980+ ret = 0 ;
1981+ goto err ;
1982+ }
1983+
1984+ if (fsck_err_on (!ret && parent_subvol != subvol_root .bi_parent_subvol ,
18561985 c , inode_bi_parent_wrong ,
18571986 "subvol root %llu has wrong bi_parent_subvol: got %u, should be %u" ,
18581987 target_inum ,
18591988 subvol_root .bi_parent_subvol , parent_subvol )) {
18601989 subvol_root .bi_parent_subvol = parent_subvol ;
18611990 ret = __bch2_fsck_write_inode (trans , & subvol_root , target_snapshot );
18621991 if (ret )
1863- return ret ;
1992+ goto err ;
18641993 }
18651994
18661995 ret = check_dirent_target (trans , iter , d , & subvol_root ,
18671996 target_snapshot );
18681997 if (ret )
1869- return ret ;
1998+ goto err ;
18701999out :
18712000err :
18722001fsck_err :
0 commit comments