@@ -659,17 +659,10 @@ int bch2_inum_to_path(struct btree_trans *trans, subvol_inum inum, struct printb
659
659
660
660
/* fsck */
661
661
662
- static bool inode_points_to_dirent (struct bch_inode_unpacked * inode ,
663
- struct bkey_s_c_dirent d )
664
- {
665
- return inode -> bi_dir == d .k -> p .inode &&
666
- inode -> bi_dir_offset == d .k -> p .offset ;
667
- }
668
-
669
662
static int bch2_check_dirent_inode_dirent (struct btree_trans * trans ,
670
- struct btree_iter * iter ,
671
- struct bkey_s_c_dirent d ,
672
- struct bch_inode_unpacked * target )
663
+ struct bkey_s_c_dirent d ,
664
+ struct bch_inode_unpacked * target ,
665
+ bool in_fsck )
673
666
{
674
667
struct bch_fs * c = trans -> c ;
675
668
struct printbuf buf = PRINTBUF ;
@@ -725,52 +718,65 @@ static int bch2_check_dirent_inode_dirent(struct btree_trans *trans,
725
718
bool backpointer_exists = !ret ;
726
719
ret = 0 ;
727
720
728
- if (fsck_err_on (!backpointer_exists ,
729
- trans , inode_wrong_backpointer ,
730
- "inode %llu:%u has wrong backpointer:\n"
731
- "got %llu:%llu\n"
732
- "should be %llu:%llu" ,
733
- target -> bi_inum , target -> bi_snapshot ,
734
- target -> bi_dir ,
735
- target -> bi_dir_offset ,
736
- d .k -> p .inode ,
737
- d .k -> p .offset )) {
738
- target -> bi_dir = d .k -> p .inode ;
739
- target -> bi_dir_offset = d .k -> p .offset ;
740
- ret = __bch2_fsck_write_inode (trans , target );
741
- goto out ;
742
- }
743
-
744
- bch2_bkey_val_to_text (& buf , c , d .s_c );
745
- prt_newline (& buf );
746
- if (backpointer_exists )
721
+ if (!backpointer_exists ) {
722
+ if (fsck_err (trans , inode_wrong_backpointer ,
723
+ "inode %llu:%u has wrong backpointer:\n"
724
+ "got %llu:%llu\n"
725
+ "should be %llu:%llu" ,
726
+ target -> bi_inum , target -> bi_snapshot ,
727
+ target -> bi_dir ,
728
+ target -> bi_dir_offset ,
729
+ d .k -> p .inode ,
730
+ d .k -> p .offset )) {
731
+ target -> bi_dir = d .k -> p .inode ;
732
+ target -> bi_dir_offset = d .k -> p .offset ;
733
+ ret = __bch2_fsck_write_inode (trans , target );
734
+ }
735
+ } else {
736
+ bch2_bkey_val_to_text (& buf , c , d .s_c );
737
+ prt_newline (& buf );
747
738
bch2_bkey_val_to_text (& buf , c , bp_dirent .s_c );
748
739
749
- if (fsck_err_on (backpointer_exists &&
750
- (S_ISDIR (target -> bi_mode ) ||
751
- target -> bi_subvol ),
752
- trans , inode_dir_multiple_links ,
753
- "%s %llu:%u with multiple links\n%s" ,
754
- S_ISDIR (target -> bi_mode ) ? "directory" : "subvolume" ,
755
- target -> bi_inum , target -> bi_snapshot , buf .buf )) {
756
- ret = bch2_fsck_remove_dirent (trans , d .k -> p );
757
- goto out ;
758
- }
759
-
760
- /*
761
- * hardlinked file with nlink 0:
762
- * We're just adjusting nlink here so check_nlinks() will pick
763
- * it up, it ignores inodes with nlink 0
764
- */
765
- if (fsck_err_on (backpointer_exists && !target -> bi_nlink ,
766
- trans , inode_multiple_links_but_nlink_0 ,
767
- "inode %llu:%u type %s has multiple links but i_nlink 0\n%s" ,
768
- target -> bi_inum , target -> bi_snapshot , bch2_d_types [d .v -> d_type ], buf .buf )) {
769
- target -> bi_nlink ++ ;
770
- target -> bi_flags &= ~BCH_INODE_unlinked ;
771
- ret = __bch2_fsck_write_inode (trans , target );
772
- if (ret )
773
- goto err ;
740
+ if (S_ISDIR (target -> bi_mode ) || target -> bi_subvol ) {
741
+ /*
742
+ * XXX: verify connectivity of the other dirent
743
+ * up to the root before removing this one
744
+ *
745
+ * Additionally, bch2_lookup would need to cope with the
746
+ * dirent it found being removed - or should we remove
747
+ * the other one, even though the inode points to it?
748
+ */
749
+ if (in_fsck ) {
750
+ if (fsck_err (trans , inode_dir_multiple_links ,
751
+ "%s %llu:%u with multiple links\n%s" ,
752
+ S_ISDIR (target -> bi_mode ) ? "directory" : "subvolume" ,
753
+ target -> bi_inum , target -> bi_snapshot , buf .buf ))
754
+ ret = bch2_fsck_remove_dirent (trans , d .k -> p );
755
+ } else {
756
+ bch2_fs_inconsistent (c ,
757
+ "%s %llu:%u with multiple links\n%s" ,
758
+ S_ISDIR (target -> bi_mode ) ? "directory" : "subvolume" ,
759
+ target -> bi_inum , target -> bi_snapshot , buf .buf );
760
+ }
761
+
762
+ goto out ;
763
+ } else {
764
+ /*
765
+ * hardlinked file with nlink 0:
766
+ * We're just adjusting nlink here so check_nlinks() will pick
767
+ * it up, it ignores inodes with nlink 0
768
+ */
769
+ if (fsck_err_on (!target -> bi_nlink ,
770
+ trans , inode_multiple_links_but_nlink_0 ,
771
+ "inode %llu:%u type %s has multiple links but i_nlink 0\n%s" ,
772
+ target -> bi_inum , target -> bi_snapshot , bch2_d_types [d .v -> d_type ], buf .buf )) {
773
+ target -> bi_nlink ++ ;
774
+ target -> bi_flags &= ~BCH_INODE_unlinked ;
775
+ ret = __bch2_fsck_write_inode (trans , target );
776
+ if (ret )
777
+ goto err ;
778
+ }
779
+ }
774
780
}
775
781
out :
776
782
err :
@@ -781,16 +787,17 @@ static int bch2_check_dirent_inode_dirent(struct btree_trans *trans,
781
787
return ret ;
782
788
}
783
789
784
- int bch2_check_dirent_target (struct btree_trans * trans ,
785
- struct btree_iter * iter ,
786
- struct bkey_s_c_dirent d ,
787
- struct bch_inode_unpacked * target )
790
+ int __bch2_check_dirent_target (struct btree_trans * trans ,
791
+ struct btree_iter * dirent_iter ,
792
+ struct bkey_s_c_dirent d ,
793
+ struct bch_inode_unpacked * target ,
794
+ bool in_fsck )
788
795
{
789
796
struct bch_fs * c = trans -> c ;
790
797
struct printbuf buf = PRINTBUF ;
791
798
int ret = 0 ;
792
799
793
- ret = bch2_check_dirent_inode_dirent (trans , iter , d , target );
800
+ ret = bch2_check_dirent_inode_dirent (trans , d , target , in_fsck );
794
801
if (ret )
795
802
goto err ;
796
803
@@ -815,11 +822,9 @@ int bch2_check_dirent_target(struct btree_trans *trans,
815
822
n -> v .d_inum = cpu_to_le64 (target -> bi_inum );
816
823
}
817
824
818
- ret = bch2_trans_update (trans , iter , & n -> k_i , 0 );
825
+ ret = bch2_trans_update (trans , dirent_iter , & n -> k_i , 0 );
819
826
if (ret )
820
827
goto err ;
821
-
822
- d = dirent_i_to_s_c (n );
823
828
}
824
829
err :
825
830
fsck_err :
0 commit comments