@@ -659,17 +659,10 @@ int bch2_inum_to_path(struct btree_trans *trans, subvol_inum inum, struct printb
659659
660660/* fsck */
661661
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-
669662static 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 )
673666{
674667 struct bch_fs * c = trans -> c ;
675668 struct printbuf buf = PRINTBUF ;
@@ -725,52 +718,65 @@ static int bch2_check_dirent_inode_dirent(struct btree_trans *trans,
725718 bool backpointer_exists = !ret ;
726719 ret = 0 ;
727720
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 );
747738 bch2_bkey_val_to_text (& buf , c , bp_dirent .s_c );
748739
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+ }
774780 }
775781out :
776782err :
@@ -781,16 +787,17 @@ static int bch2_check_dirent_inode_dirent(struct btree_trans *trans,
781787 return ret ;
782788}
783789
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 )
788795{
789796 struct bch_fs * c = trans -> c ;
790797 struct printbuf buf = PRINTBUF ;
791798 int ret = 0 ;
792799
793- ret = bch2_check_dirent_inode_dirent (trans , iter , d , target );
800+ ret = bch2_check_dirent_inode_dirent (trans , d , target , in_fsck );
794801 if (ret )
795802 goto err ;
796803
@@ -815,11 +822,9 @@ int bch2_check_dirent_target(struct btree_trans *trans,
815822 n -> v .d_inum = cpu_to_le64 (target -> bi_inum );
816823 }
817824
818- ret = bch2_trans_update (trans , iter , & n -> k_i , 0 );
825+ ret = bch2_trans_update (trans , dirent_iter , & n -> k_i , 0 );
819826 if (ret )
820827 goto err ;
821-
822- d = dirent_i_to_s_c (n );
823828 }
824829err :
825830fsck_err :
0 commit comments