@@ -38,6 +38,7 @@ static const char * const bch2_inode_flag_strs[] = {
38
38
#undef x
39
39
40
40
static int delete_ancestor_snapshot_inodes (struct btree_trans * , struct bpos );
41
+ static int may_delete_deleted_inum (struct btree_trans * , subvol_inum );
41
42
42
43
static const u8 byte_table [8 ] = { 1 , 2 , 3 , 4 , 6 , 8 , 10 , 13 };
43
44
@@ -1130,19 +1131,23 @@ int bch2_inode_rm(struct bch_fs *c, subvol_inum inum)
1130
1131
u32 snapshot ;
1131
1132
int ret ;
1132
1133
1134
+ ret = lockrestart_do (trans , may_delete_deleted_inum (trans , inum ));
1135
+ if (ret )
1136
+ goto err2 ;
1137
+
1133
1138
/*
1134
1139
* If this was a directory, there shouldn't be any real dirents left -
1135
1140
* but there could be whiteouts (from hash collisions) that we should
1136
1141
* delete:
1137
1142
*
1138
- * XXX: the dirent could ideally would delete whiteouts when they're no
1143
+ * XXX: the dirent code ideally would delete whiteouts when they're no
1139
1144
* longer needed
1140
1145
*/
1141
1146
ret = bch2_inode_delete_keys (trans , inum , BTREE_ID_extents ) ?:
1142
1147
bch2_inode_delete_keys (trans , inum , BTREE_ID_xattrs ) ?:
1143
1148
bch2_inode_delete_keys (trans , inum , BTREE_ID_dirents );
1144
1149
if (ret )
1145
- goto err ;
1150
+ goto err2 ;
1146
1151
retry :
1147
1152
bch2_trans_begin (trans );
1148
1153
@@ -1392,7 +1397,8 @@ int bch2_inode_rm_snapshot(struct btree_trans *trans, u64 inum, u32 snapshot)
1392
1397
delete_ancestor_snapshot_inodes (trans , SPOS (0 , inum , snapshot ));
1393
1398
}
1394
1399
1395
- static int may_delete_deleted_inode (struct btree_trans * trans , struct bpos pos )
1400
+ static int may_delete_deleted_inode (struct btree_trans * trans , struct bpos pos ,
1401
+ bool from_deleted_inodes )
1396
1402
{
1397
1403
struct bch_fs * c = trans -> c ;
1398
1404
struct btree_iter inode_iter ;
@@ -1406,20 +1412,23 @@ static int may_delete_deleted_inode(struct btree_trans *trans, struct bpos pos)
1406
1412
if (ret )
1407
1413
return ret ;
1408
1414
1409
- ret = bkey_is_inode (k .k ) ? 0 : - BCH_ERR_ENOENT_inode ;
1410
- if (fsck_err_on (! bkey_is_inode ( k . k ) ,
1415
+ ret = bkey_is_inode (k .k ) ? 0 : bch_err_throw ( c , ENOENT_inode ) ;
1416
+ if (fsck_err_on (from_deleted_inodes && ret ,
1411
1417
trans , deleted_inode_missing ,
1412
1418
"nonexistent inode %llu:%u in deleted_inodes btree" ,
1413
1419
pos .offset , pos .snapshot ))
1414
1420
goto delete ;
1421
+ if (ret )
1422
+ goto out ;
1415
1423
1416
1424
ret = bch2_inode_unpack (k , & inode );
1417
1425
if (ret )
1418
1426
goto out ;
1419
1427
1420
1428
if (S_ISDIR (inode .bi_mode )) {
1421
1429
ret = bch2_empty_dir_snapshot (trans , pos .offset , 0 , pos .snapshot );
1422
- if (fsck_err_on (bch2_err_matches (ret , ENOTEMPTY ),
1430
+ if (fsck_err_on (from_deleted_inodes &&
1431
+ bch2_err_matches (ret , ENOTEMPTY ),
1423
1432
trans , deleted_inode_is_dir ,
1424
1433
"non empty directory %llu:%u in deleted_inodes btree" ,
1425
1434
pos .offset , pos .snapshot ))
@@ -1428,17 +1437,25 @@ static int may_delete_deleted_inode(struct btree_trans *trans, struct bpos pos)
1428
1437
goto out ;
1429
1438
}
1430
1439
1431
- if (fsck_err_on (!(inode .bi_flags & BCH_INODE_unlinked ),
1440
+ ret = inode .bi_flags & BCH_INODE_unlinked ? 0 : bch_err_throw (c , inode_not_unlinked );
1441
+ if (fsck_err_on (from_deleted_inodes && ret ,
1432
1442
trans , deleted_inode_not_unlinked ,
1433
1443
"non-deleted inode %llu:%u in deleted_inodes btree" ,
1434
1444
pos .offset , pos .snapshot ))
1435
1445
goto delete ;
1446
+ if (ret )
1447
+ goto out ;
1448
+
1449
+ ret = !(inode .bi_flags & BCH_INODE_has_child_snapshot )
1450
+ ? 0 : bch_err_throw (c , inode_has_child_snapshot );
1436
1451
1437
- if (fsck_err_on (inode . bi_flags & BCH_INODE_has_child_snapshot ,
1452
+ if (fsck_err_on (from_deleted_inodes && ret ,
1438
1453
trans , deleted_inode_has_child_snapshots ,
1439
1454
"inode with child snapshots %llu:%u in deleted_inodes btree" ,
1440
1455
pos .offset , pos .snapshot ))
1441
1456
goto delete ;
1457
+ if (ret )
1458
+ goto out ;
1442
1459
1443
1460
ret = bch2_inode_has_child_snapshots (trans , k .k -> p );
1444
1461
if (ret < 0 )
@@ -1455,19 +1472,28 @@ static int may_delete_deleted_inode(struct btree_trans *trans, struct bpos pos)
1455
1472
if (ret )
1456
1473
goto out ;
1457
1474
}
1475
+
1476
+ if (!from_deleted_inodes ) {
1477
+ ret = bch2_trans_commit (trans , NULL , NULL , BCH_TRANS_COMMIT_no_enospc ) ?:
1478
+ bch_err_throw (c , inode_has_child_snapshot );
1479
+ goto out ;
1480
+ }
1481
+
1458
1482
goto delete ;
1459
1483
1460
1484
}
1461
1485
1462
- if (test_bit (BCH_FS_clean_recovery , & c -> flags ) &&
1463
- !fsck_err (trans , deleted_inode_but_clean ,
1464
- "filesystem marked as clean but have deleted inode %llu:%u" ,
1465
- pos .offset , pos .snapshot )) {
1466
- ret = 0 ;
1467
- goto out ;
1468
- }
1486
+ if (from_deleted_inodes ) {
1487
+ if (test_bit (BCH_FS_clean_recovery , & c -> flags ) &&
1488
+ !fsck_err (trans , deleted_inode_but_clean ,
1489
+ "filesystem marked as clean but have deleted inode %llu:%u" ,
1490
+ pos .offset , pos .snapshot )) {
1491
+ ret = 0 ;
1492
+ goto out ;
1493
+ }
1469
1494
1470
- ret = 1 ;
1495
+ ret = 1 ;
1496
+ }
1471
1497
out :
1472
1498
fsck_err :
1473
1499
bch2_trans_iter_exit (trans , & inode_iter );
@@ -1478,6 +1504,14 @@ static int may_delete_deleted_inode(struct btree_trans *trans, struct bpos pos)
1478
1504
goto out ;
1479
1505
}
1480
1506
1507
+ static int may_delete_deleted_inum (struct btree_trans * trans , subvol_inum inum )
1508
+ {
1509
+ u32 snapshot ;
1510
+
1511
+ return bch2_subvolume_get_snapshot (trans , inum .subvol , & snapshot ) ?:
1512
+ may_delete_deleted_inode (trans , SPOS (0 , inum .inum , snapshot ), false);
1513
+ }
1514
+
1481
1515
int bch2_delete_dead_inodes (struct bch_fs * c )
1482
1516
{
1483
1517
struct btree_trans * trans = bch2_trans_get (c );
@@ -1501,7 +1535,7 @@ int bch2_delete_dead_inodes(struct bch_fs *c)
1501
1535
ret = for_each_btree_key_commit (trans , iter , BTREE_ID_deleted_inodes , POS_MIN ,
1502
1536
BTREE_ITER_prefetch |BTREE_ITER_all_snapshots , k ,
1503
1537
NULL , NULL , BCH_TRANS_COMMIT_no_enospc , ({
1504
- ret = may_delete_deleted_inode (trans , k .k -> p );
1538
+ ret = may_delete_deleted_inode (trans , k .k -> p , true );
1505
1539
if (ret > 0 ) {
1506
1540
bch_verbose_ratelimited (c , "deleting unlinked inode %llu:%u" ,
1507
1541
k .k -> p .offset , k .k -> p .snapshot );
0 commit comments