Skip to content

Commit b049962

Browse files
author
Darrick J. Wong
committed
xfs: simplify xchk_parent_validate
This function is unnecessarily long because it contains code to revalidate a dotdot entry after cycling locks to try to confirm a subdirectory parent pointer. Shorten the codebase by making the parent's lookup call do double duty as the revalidation code. This weakeans the efficacy of this scrub function temporarily, but the next patch will resolve this as part of fixing an unhandled race that is the result of the VFS rename locking model not working the way Darrick thought it did. Rename this stupid 'dnum' variable too. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Dave Chinner <dchinner@redhat.com>
1 parent cbab28f commit b049962

1 file changed

Lines changed: 23 additions & 77 deletions

File tree

fs/xfs/scrub/parent.c

Lines changed: 23 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ xchk_parent_actor(
7171
STATIC int
7272
xchk_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

204157
out_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

Comments
 (0)