@@ -63,9 +63,7 @@ static int subvol_lookup(struct btree_trans *trans, u32 subvol,
63
63
u32 * snapshot , u64 * inum )
64
64
{
65
65
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 );
69
67
70
68
* snapshot = le32_to_cpu (s .snapshot );
71
69
* inum = le64_to_cpu (s .inode );
@@ -170,7 +168,8 @@ static int __remove_dirent(struct btree_trans *trans, struct bpos pos)
170
168
171
169
/* Get lost+found, create if it doesn't exist: */
172
170
static 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 )
174
173
{
175
174
struct bch_fs * c = trans -> c ;
176
175
struct qstr lostfound_str = QSTR ("lost+found" );
@@ -185,19 +184,36 @@ static int lookup_lostfound(struct btree_trans *trans, u32 snapshot,
185
184
return ret ;
186
185
187
186
subvol_inum root_inum = { .subvol = le32_to_cpu (st .master_subvol ) };
188
- u32 subvol_snapshot ;
189
187
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 );
193
193
if (ret )
194
194
return ret ;
195
195
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
+
196
211
struct bch_inode_unpacked root_inode ;
197
212
struct bch_hash_info root_hash_info ;
198
213
u32 root_inode_snapshot = snapshot ;
199
214
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 ));
201
217
if (ret )
202
218
return ret ;
203
219
@@ -293,7 +309,7 @@ static int reattach_inode(struct btree_trans *trans,
293
309
snprintf (name_buf , sizeof (name_buf ), "%llu" , inode -> bi_inum );
294
310
}
295
311
296
- ret = lookup_lostfound (trans , dirent_snapshot , & lostfound );
312
+ ret = lookup_lostfound (trans , dirent_snapshot , & lostfound , inode -> bi_inum );
297
313
if (ret )
298
314
return ret ;
299
315
@@ -364,6 +380,85 @@ static int reattach_subvol(struct btree_trans *trans, struct bkey_s_c_subvolume
364
380
return ret ;
365
381
}
366
382
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
+
367
462
struct snapshots_seen_entry {
368
463
u32 id ;
369
464
u32 equiv ;
@@ -1065,6 +1160,11 @@ static int check_inode(struct btree_trans *trans,
1065
1160
if (ret && !bch2_err_matches (ret , ENOENT ))
1066
1161
goto err ;
1067
1162
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
+
1068
1168
if (fsck_err_on (ret ,
1069
1169
c , inode_bi_subvol_missing ,
1070
1170
"inode %llu:%u bi_subvol points to missing subvolume %u" ,
@@ -1082,7 +1182,7 @@ static int check_inode(struct btree_trans *trans,
1082
1182
do_update = true;
1083
1183
}
1084
1184
}
1085
-
1185
+ do_update :
1086
1186
if (do_update ) {
1087
1187
ret = __bch2_fsck_write_inode (trans , & u , iter -> pos .snapshot );
1088
1188
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 *
1785
1885
u32 parent_subvol = le32_to_cpu (d .v -> d_parent_subvol );
1786
1886
u32 target_subvol = le32_to_cpu (d .v -> d_child_subvol );
1787
1887
u32 parent_snapshot ;
1888
+ u32 new_parent_subvol = 0 ;
1788
1889
u64 parent_inum ;
1789
1890
struct printbuf buf = PRINTBUF ;
1790
1891
int ret = 0 ;
@@ -1793,6 +1894,27 @@ static int check_dirent_to_subvol(struct btree_trans *trans, struct btree_iter *
1793
1894
if (ret && !bch2_err_matches (ret , ENOENT ))
1794
1895
return ret ;
1795
1896
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
+
1796
1918
if (fsck_err_on (ret , c , dirent_to_missing_parent_subvol ,
1797
1919
"dirent parent_subvol points to missing subvolume\n%s" ,
1798
1920
(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 *
1801
1923
"dirent not visible in parent_subvol (not an ancestor of subvol snap %u)\n%s" ,
1802
1924
parent_snapshot ,
1803
1925
(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
+ }
1808
1930
1809
1931
struct bkey_i_dirent * new_dirent = bch2_bkey_make_mut_typed (trans , iter , & d .s_c , 0 , dirent );
1810
1932
ret = PTR_ERR_OR_ZERO (new_dirent );
@@ -1850,23 +1972,30 @@ static int check_dirent_to_subvol(struct btree_trans *trans, struct btree_iter *
1850
1972
1851
1973
ret = lookup_inode (trans , target_inum , & subvol_root , & target_snapshot );
1852
1974
if (ret && !bch2_err_matches (ret , ENOENT ))
1853
- return ret ;
1975
+ goto err ;
1854
1976
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 ,
1856
1985
c , inode_bi_parent_wrong ,
1857
1986
"subvol root %llu has wrong bi_parent_subvol: got %u, should be %u" ,
1858
1987
target_inum ,
1859
1988
subvol_root .bi_parent_subvol , parent_subvol )) {
1860
1989
subvol_root .bi_parent_subvol = parent_subvol ;
1861
1990
ret = __bch2_fsck_write_inode (trans , & subvol_root , target_snapshot );
1862
1991
if (ret )
1863
- return ret ;
1992
+ goto err ;
1864
1993
}
1865
1994
1866
1995
ret = check_dirent_target (trans , iter , d , & subvol_root ,
1867
1996
target_snapshot );
1868
1997
if (ret )
1869
- return ret ;
1998
+ goto err ;
1870
1999
out :
1871
2000
err :
1872
2001
fsck_err :
0 commit comments