Commit 8bc763c2 authored by Darrick J. Wong's avatar Darrick J. Wong

xfs: don't continue scrub if already corrupt

If we've already decided that something is corrupt, we might as well
abort all the loops and exit as quickly as possible.
Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: default avatarBrian Foster <bfoster@redhat.com>
parent eac69e16
...@@ -126,8 +126,9 @@ xfs_scrub_xattr_listent( ...@@ -126,8 +126,9 @@ xfs_scrub_xattr_listent(
if (args.valuelen != valuelen) if (args.valuelen != valuelen)
xfs_scrub_fblock_set_corrupt(sx->sc, XFS_ATTR_FORK, xfs_scrub_fblock_set_corrupt(sx->sc, XFS_ATTR_FORK,
args.blkno); args.blkno);
fail_xref: fail_xref:
if (sx->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
context->seen_enough = 1;
return; return;
} }
......
...@@ -683,7 +683,8 @@ xfs_scrub_bmap( ...@@ -683,7 +683,8 @@ xfs_scrub_bmap(
info.lastoff = 0; info.lastoff = 0;
ifp = XFS_IFORK_PTR(ip, whichfork); ifp = XFS_IFORK_PTR(ip, whichfork);
for_each_xfs_iext(ifp, &icur, &irec) { for_each_xfs_iext(ifp, &icur, &irec) {
if (xfs_scrub_should_terminate(sc, &error)) if (xfs_scrub_should_terminate(sc, &error) ||
(sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
break; break;
if (isnullstartblock(irec.br_startblock)) if (isnullstartblock(irec.br_startblock))
continue; continue;
......
...@@ -172,7 +172,7 @@ xfs_scrub_dir_actor( ...@@ -172,7 +172,7 @@ xfs_scrub_dir_actor(
error = xfs_dir_lookup(sdc->sc->tp, ip, &xname, &lookup_ino, NULL); error = xfs_dir_lookup(sdc->sc->tp, ip, &xname, &lookup_ino, NULL);
if (!xfs_scrub_fblock_process_error(sdc->sc, XFS_DATA_FORK, offset, if (!xfs_scrub_fblock_process_error(sdc->sc, XFS_DATA_FORK, offset,
&error)) &error))
goto fail_xref; goto out;
if (lookup_ino != ino) { if (lookup_ino != ino) {
xfs_scrub_fblock_set_corrupt(sdc->sc, XFS_DATA_FORK, offset); xfs_scrub_fblock_set_corrupt(sdc->sc, XFS_DATA_FORK, offset);
goto out; goto out;
...@@ -183,8 +183,13 @@ xfs_scrub_dir_actor( ...@@ -183,8 +183,13 @@ xfs_scrub_dir_actor(
if (error) if (error)
goto out; goto out;
out: out:
return error; /*
fail_xref: * A negative error code returned here is supposed to cause the
* dir_emit caller (xfs_readdir) to abort the directory iteration
* and return zero to xfs_scrub_directory.
*/
if (error == 0 && sdc->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
return -EFSCORRUPTED;
return error; return error;
} }
...@@ -240,6 +245,9 @@ xfs_scrub_dir_rec( ...@@ -240,6 +245,9 @@ xfs_scrub_dir_rec(
} }
xfs_scrub_buffer_recheck(ds->sc, bp); xfs_scrub_buffer_recheck(ds->sc, bp);
if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
goto out_relse;
dent = (struct xfs_dir2_data_entry *)(((char *)bp->b_addr) + off); dent = (struct xfs_dir2_data_entry *)(((char *)bp->b_addr) + off);
/* Make sure we got a real directory entry. */ /* Make sure we got a real directory entry. */
...@@ -357,6 +365,9 @@ xfs_scrub_directory_data_bestfree( ...@@ -357,6 +365,9 @@ xfs_scrub_directory_data_bestfree(
/* XXX: Check xfs_dir3_data_hdr.pad is zero once we start setting it. */ /* XXX: Check xfs_dir3_data_hdr.pad is zero once we start setting it. */
if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
goto out_buf;
/* Do the bestfrees correspond to actual free space? */ /* Do the bestfrees correspond to actual free space? */
bf = d_ops->data_bestfree_p(bp->b_addr); bf = d_ops->data_bestfree_p(bp->b_addr);
smallest_bestfree = UINT_MAX; smallest_bestfree = UINT_MAX;
...@@ -413,14 +424,18 @@ xfs_scrub_directory_data_bestfree( ...@@ -413,14 +424,18 @@ xfs_scrub_directory_data_bestfree(
/* Spot check this free entry */ /* Spot check this free entry */
tag = be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)); tag = be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup));
if (tag != ((char *)dup - (char *)bp->b_addr)) if (tag != ((char *)dup - (char *)bp->b_addr)) {
xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk); xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
goto out_buf;
}
/* /*
* Either this entry is a bestfree or it's smaller than * Either this entry is a bestfree or it's smaller than
* any of the bestfrees. * any of the bestfrees.
*/ */
xfs_scrub_directory_check_free_entry(sc, lblk, bf, dup); xfs_scrub_directory_check_free_entry(sc, lblk, bf, dup);
if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
goto out_buf;
/* Move on. */ /* Move on. */
newlen = be16_to_cpu(dup->length); newlen = be16_to_cpu(dup->length);
...@@ -546,6 +561,8 @@ xfs_scrub_directory_leaf1_bestfree( ...@@ -546,6 +561,8 @@ xfs_scrub_directory_leaf1_bestfree(
} }
if (leafhdr.stale != stale) if (leafhdr.stale != stale)
xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk); xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
goto out;
/* Check all the bestfree entries. */ /* Check all the bestfree entries. */
for (i = 0; i < bestcount; i++, bestp++) { for (i = 0; i < bestcount; i++, bestp++) {
...@@ -556,9 +573,11 @@ xfs_scrub_directory_leaf1_bestfree( ...@@ -556,9 +573,11 @@ xfs_scrub_directory_leaf1_bestfree(
i * args->geo->fsbcount, -1, &dbp); i * args->geo->fsbcount, -1, &dbp);
if (!xfs_scrub_fblock_process_error(sc, XFS_DATA_FORK, lblk, if (!xfs_scrub_fblock_process_error(sc, XFS_DATA_FORK, lblk,
&error)) &error))
continue; break;
xfs_scrub_directory_check_freesp(sc, lblk, dbp, best); xfs_scrub_directory_check_freesp(sc, lblk, dbp, best);
xfs_trans_brelse(sc->tp, dbp); xfs_trans_brelse(sc->tp, dbp);
if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
goto out;
} }
out: out:
return error; return error;
...@@ -607,7 +626,7 @@ xfs_scrub_directory_free_bestfree( ...@@ -607,7 +626,7 @@ xfs_scrub_directory_free_bestfree(
-1, &dbp); -1, &dbp);
if (!xfs_scrub_fblock_process_error(sc, XFS_DATA_FORK, lblk, if (!xfs_scrub_fblock_process_error(sc, XFS_DATA_FORK, lblk,
&error)) &error))
continue; break;
xfs_scrub_directory_check_freesp(sc, lblk, dbp, best); xfs_scrub_directory_check_freesp(sc, lblk, dbp, best);
xfs_trans_brelse(sc->tp, dbp); xfs_trans_brelse(sc->tp, dbp);
} }
...@@ -656,7 +675,7 @@ xfs_scrub_directory_blocks( ...@@ -656,7 +675,7 @@ xfs_scrub_directory_blocks(
/* Iterate all the data extents in the directory... */ /* Iterate all the data extents in the directory... */
found = xfs_iext_lookup_extent(sc->ip, ifp, lblk, &icur, &got); found = xfs_iext_lookup_extent(sc->ip, ifp, lblk, &icur, &got);
while (found) { while (found && !(sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) {
/* Block directories only have a single block at offset 0. */ /* Block directories only have a single block at offset 0. */
if (is_block && if (is_block &&
(got.br_startoff > 0 || (got.br_startoff > 0 ||
...@@ -719,7 +738,7 @@ xfs_scrub_directory_blocks( ...@@ -719,7 +738,7 @@ xfs_scrub_directory_blocks(
/* Scan for free blocks */ /* Scan for free blocks */
lblk = free_lblk; lblk = free_lblk;
found = xfs_iext_lookup_extent(sc->ip, ifp, lblk, &icur, &got); found = xfs_iext_lookup_extent(sc->ip, ifp, lblk, &icur, &got);
while (found) { while (found && !(sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) {
/* /*
* Dirs can't have blocks mapped above 2^32. * Dirs can't have blocks mapped above 2^32.
* Single-block dirs shouldn't even be here. * Single-block dirs shouldn't even be here.
......
...@@ -147,6 +147,9 @@ xfs_scrub_parent_validate( ...@@ -147,6 +147,9 @@ xfs_scrub_parent_validate(
*try_again = false; *try_again = false;
if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
goto out;
/* '..' must not point to ourselves. */ /* '..' must not point to ourselves. */
if (sc->ip->i_ino == dnum) { if (sc->ip->i_ino == dnum) {
xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, 0); xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment