@@ -71,7 +71,7 @@ xchk_parent_actor(
7171STATIC int
7272xchk_parent_validate (
7373 struct xfs_scrub * sc ,
74- xfs_ino_t dnum ,
74+ xfs_ino_t parent_ino ,
7575 bool * try_again )
7676{
7777 struct xchk_parent_ctx spc = {
@@ -86,11 +86,16 @@ xchk_parent_validate(
8686
8787 * try_again = false;
8888
89- if (sc -> sm -> sm_flags & XFS_SCRUB_OFLAG_CORRUPT )
89+ /* Is this the root dir? Then '..' must point to itself. */
90+ if (sc -> ip == mp -> m_rootip ) {
91+ if (sc -> ip -> i_ino != mp -> m_sb .sb_rootino ||
92+ sc -> ip -> i_ino != parent_ino )
93+ xchk_fblock_set_corrupt (sc , XFS_DATA_FORK , 0 );
9094 goto out ;
95+ }
9196
9297 /* '..' must not point to ourselves. */
93- if (sc -> ip -> i_ino == dnum ) {
98+ if (sc -> ip -> i_ino == parent_ino ) {
9499 xchk_fblock_set_corrupt (sc , XFS_DATA_FORK , 0 );
95100 goto out ;
96101 }
@@ -115,7 +120,7 @@ xchk_parent_validate(
115120 * -EFSCORRUPTED or -EFSBADCRC then the parent is corrupt which is a
116121 * cross referencing error. Any other error is an operational error.
117122 */
118- error = xfs_iget (mp , sc -> tp , dnum , XFS_IGET_UNTRUSTED , 0 , & dp );
123+ error = xfs_iget (mp , sc -> tp , parent_ino , XFS_IGET_UNTRUSTED , 0 , & dp );
119124 if (error == - EINVAL || error == - ENOENT ) {
120125 error = - EFSCORRUPTED ;
121126 xchk_fblock_process_error (sc , XFS_DATA_FORK , 0 , & error );
@@ -135,71 +140,19 @@ xchk_parent_validate(
135140 * use nowait here to avoid an ABBA deadlock on the parent and
136141 * the child inodes.
137142 */
138- if (xfs_ilock_nowait (dp , XFS_IOLOCK_SHARED )) {
139- lock_mode = xfs_ilock_data_map_shared (dp );
140- error = xchk_dir_walk (sc , dp , xchk_parent_actor , & spc );
141- xfs_iunlock (dp , lock_mode );
142- if (!xchk_fblock_xref_process_error (sc , XFS_DATA_FORK , 0 ,
143- & error ))
144- goto out_unlock ;
145- if (spc .nlink != expected_nlink )
146- xchk_fblock_set_corrupt (sc , XFS_DATA_FORK , 0 );
147- goto out_unlock ;
148- }
149-
150- /*
151- * The game changes if we get here. We failed to lock the parent,
152- * so we're going to try to verify both pointers while only holding
153- * one lock so as to avoid deadlocking with something that's actually
154- * trying to traverse down the directory tree.
155- */
156- xfs_iunlock (sc -> ip , sc -> ilock_flags );
157- sc -> ilock_flags = 0 ;
158- error = xchk_ilock_inverted (dp , XFS_IOLOCK_SHARED );
159- if (error )
143+ if (!xfs_ilock_nowait (dp , XFS_IOLOCK_SHARED )) {
144+ * try_again = true;
160145 goto out_rele ;
146+ }
161147
162- /* Go looking for our dentry. */
163148 lock_mode = xfs_ilock_data_map_shared (dp );
164149 error = xchk_dir_walk (sc , dp , xchk_parent_actor , & spc );
165150 xfs_iunlock (dp , lock_mode );
166151 if (!xchk_fblock_xref_process_error (sc , XFS_DATA_FORK , 0 , & error ))
167152 goto out_unlock ;
168153
169- /* Drop the parent lock, relock this inode. */
170- xfs_iunlock (dp , XFS_IOLOCK_SHARED );
171- error = xchk_ilock_inverted (sc -> ip , XFS_IOLOCK_EXCL );
172- if (error )
173- goto out_rele ;
174- sc -> ilock_flags = XFS_IOLOCK_EXCL ;
175-
176- /*
177- * If we're an unlinked directory, the parent /won't/ have a link
178- * to us. Otherwise, it should have one link. We have to re-set
179- * it here because we dropped the lock on sc->ip.
180- */
181- expected_nlink = VFS_I (sc -> ip )-> i_nlink == 0 ? 0 : 1 ;
182-
183- /* Look up '..' to see if the inode changed. */
184- error = xfs_dir_lookup (sc -> tp , sc -> ip , & xfs_name_dotdot , & dnum , NULL );
185- if (!xchk_fblock_process_error (sc , XFS_DATA_FORK , 0 , & error ))
186- goto out_rele ;
187-
188- /* Drat, parent changed. Try again! */
189- if (dnum != dp -> i_ino ) {
190- xfs_irele (dp );
191- * try_again = true;
192- return 0 ;
193- }
194- xfs_irele (dp );
195-
196- /*
197- * '..' didn't change, so check that there was only one entry
198- * for us in the parent.
199- */
200154 if (spc .nlink != expected_nlink )
201155 xchk_fblock_set_corrupt (sc , XFS_DATA_FORK , 0 );
202- return error ;
203156
204157out_unlock :
205158 xfs_iunlock (dp , XFS_IOLOCK_SHARED );
@@ -215,7 +168,7 @@ xchk_parent(
215168 struct xfs_scrub * sc )
216169{
217170 struct xfs_mount * mp = sc -> mp ;
218- xfs_ino_t dnum ;
171+ xfs_ino_t parent_ino ;
219172 bool try_again ;
220173 int tries = 0 ;
221174 int error = 0 ;
@@ -243,25 +196,18 @@ xchk_parent(
243196 sc -> ilock_flags &= ~(XFS_ILOCK_EXCL | XFS_MMAPLOCK_EXCL );
244197 xfs_iunlock (sc -> ip , XFS_ILOCK_EXCL | XFS_MMAPLOCK_EXCL );
245198
246- /* Look up '..' */
247- error = xfs_dir_lookup (sc -> tp , sc -> ip , & xfs_name_dotdot , & dnum , NULL );
248- if (!xchk_fblock_process_error (sc , XFS_DATA_FORK , 0 , & error ))
249- goto out ;
250- if (!xfs_verify_dir_ino (mp , dnum )) {
251- xchk_fblock_set_corrupt (sc , XFS_DATA_FORK , 0 );
252- goto out ;
253- }
254-
255- /* Is this the root dir? Then '..' must point to itself. */
256- if (sc -> ip == mp -> m_rootip ) {
257- if (sc -> ip -> i_ino != mp -> m_sb .sb_rootino ||
258- sc -> ip -> i_ino != dnum )
199+ do {
200+ /* Look up '..' */
201+ error = xfs_dir_lookup (sc -> tp , sc -> ip , & xfs_name_dotdot ,
202+ & parent_ino , NULL );
203+ if (!xchk_fblock_process_error (sc , XFS_DATA_FORK , 0 , & error ))
204+ goto out ;
205+ if (!xfs_verify_dir_ino (mp , parent_ino )) {
259206 xchk_fblock_set_corrupt (sc , XFS_DATA_FORK , 0 );
260- goto out ;
261- }
207+ goto out ;
208+ }
262209
263- do {
264- error = xchk_parent_validate (sc , dnum , & try_again );
210+ error = xchk_parent_validate (sc , parent_ino , & try_again );
265211 if (error )
266212 goto out ;
267213 } while (try_again && ++ tries < 20 );
0 commit comments