@@ -38,6 +38,7 @@ static const char * const bch2_inode_flag_strs[] = {
3838#undef x
3939
4040static int delete_ancestor_snapshot_inodes (struct btree_trans * , struct bpos );
41+ static int may_delete_deleted_inum (struct btree_trans * , subvol_inum );
4142
4243static const u8 byte_table [8 ] = { 1 , 2 , 3 , 4 , 6 , 8 , 10 , 13 };
4344
@@ -1130,19 +1131,23 @@ int bch2_inode_rm(struct bch_fs *c, subvol_inum inum)
11301131 u32 snapshot ;
11311132 int ret ;
11321133
1134+ ret = lockrestart_do (trans , may_delete_deleted_inum (trans , inum ));
1135+ if (ret )
1136+ goto err2 ;
1137+
11331138 /*
11341139 * If this was a directory, there shouldn't be any real dirents left -
11351140 * but there could be whiteouts (from hash collisions) that we should
11361141 * delete:
11371142 *
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
11391144 * longer needed
11401145 */
11411146 ret = bch2_inode_delete_keys (trans , inum , BTREE_ID_extents ) ?:
11421147 bch2_inode_delete_keys (trans , inum , BTREE_ID_xattrs ) ?:
11431148 bch2_inode_delete_keys (trans , inum , BTREE_ID_dirents );
11441149 if (ret )
1145- goto err ;
1150+ goto err2 ;
11461151retry :
11471152 bch2_trans_begin (trans );
11481153
@@ -1392,7 +1397,8 @@ int bch2_inode_rm_snapshot(struct btree_trans *trans, u64 inum, u32 snapshot)
13921397 delete_ancestor_snapshot_inodes (trans , SPOS (0 , inum , snapshot ));
13931398}
13941399
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 )
13961402{
13971403 struct bch_fs * c = trans -> c ;
13981404 struct btree_iter inode_iter ;
@@ -1406,20 +1412,23 @@ static int may_delete_deleted_inode(struct btree_trans *trans, struct bpos pos)
14061412 if (ret )
14071413 return ret ;
14081414
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 ,
14111417 trans , deleted_inode_missing ,
14121418 "nonexistent inode %llu:%u in deleted_inodes btree" ,
14131419 pos .offset , pos .snapshot ))
14141420 goto delete ;
1421+ if (ret )
1422+ goto out ;
14151423
14161424 ret = bch2_inode_unpack (k , & inode );
14171425 if (ret )
14181426 goto out ;
14191427
14201428 if (S_ISDIR (inode .bi_mode )) {
14211429 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 ),
14231432 trans , deleted_inode_is_dir ,
14241433 "non empty directory %llu:%u in deleted_inodes btree" ,
14251434 pos .offset , pos .snapshot ))
@@ -1428,17 +1437,25 @@ static int may_delete_deleted_inode(struct btree_trans *trans, struct bpos pos)
14281437 goto out ;
14291438 }
14301439
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 ,
14321442 trans , deleted_inode_not_unlinked ,
14331443 "non-deleted inode %llu:%u in deleted_inodes btree" ,
14341444 pos .offset , pos .snapshot ))
14351445 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 );
14361451
1437- if (fsck_err_on (inode . bi_flags & BCH_INODE_has_child_snapshot ,
1452+ if (fsck_err_on (from_deleted_inodes && ret ,
14381453 trans , deleted_inode_has_child_snapshots ,
14391454 "inode with child snapshots %llu:%u in deleted_inodes btree" ,
14401455 pos .offset , pos .snapshot ))
14411456 goto delete ;
1457+ if (ret )
1458+ goto out ;
14421459
14431460 ret = bch2_inode_has_child_snapshots (trans , k .k -> p );
14441461 if (ret < 0 )
@@ -1455,19 +1472,28 @@ static int may_delete_deleted_inode(struct btree_trans *trans, struct bpos pos)
14551472 if (ret )
14561473 goto out ;
14571474 }
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+
14581482 goto delete ;
14591483
14601484 }
14611485
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+ }
14691494
1470- ret = 1 ;
1495+ ret = 1 ;
1496+ }
14711497out :
14721498fsck_err :
14731499 bch2_trans_iter_exit (trans , & inode_iter );
@@ -1478,6 +1504,14 @@ static int may_delete_deleted_inode(struct btree_trans *trans, struct bpos pos)
14781504 goto out ;
14791505}
14801506
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+
14811515int bch2_delete_dead_inodes (struct bch_fs * c )
14821516{
14831517 struct btree_trans * trans = bch2_trans_get (c );
@@ -1501,7 +1535,7 @@ int bch2_delete_dead_inodes(struct bch_fs *c)
15011535 ret = for_each_btree_key_commit (trans , iter , BTREE_ID_deleted_inodes , POS_MIN ,
15021536 BTREE_ITER_prefetch |BTREE_ITER_all_snapshots , k ,
15031537 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 );
15051539 if (ret > 0 ) {
15061540 bch_verbose_ratelimited (c , "deleting unlinked inode %llu:%u" ,
15071541 k .k -> p .offset , k .k -> p .snapshot );
0 commit comments