Commit 519e5869 authored by Darrick J. Wong's avatar Darrick J. Wong

xfs: bmap scrub should only scrub records once

The inode block mapping scrub function does more work for btree format
extent maps than is absolutely necessary -- first it will walk the bmbt
and check all the entries, and then it will load the incore tree and
check every entry in that tree, possibly for a second time.

Simplify the code and decrease check runtime by separating the two
responsibilities.  The bmbt walk will make sure the incore extent
mappings are loaded, check the shape of the bmap btree (via xchk_btree)
and check that every bmbt record has a corresponding incore extent map;
and the incore extent map walk takes all the responsibility for checking
the mapping records and cross referencing them with other AG metadata.

This enables us to clean up some messy parameter handling and reduce
redundant code.  Rename a few functions to make the split of
responsibilities clearer.
Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarBrian Foster <bfoster@redhat.com>
parent 71912e08
...@@ -75,6 +75,7 @@ struct xchk_bmap_info { ...@@ -75,6 +75,7 @@ struct xchk_bmap_info {
xfs_fileoff_t lastoff; xfs_fileoff_t lastoff;
bool is_rt; bool is_rt;
bool is_shared; bool is_shared;
bool was_loaded;
int whichfork; int whichfork;
}; };
...@@ -213,25 +214,20 @@ xchk_bmap_xref_rmap( ...@@ -213,25 +214,20 @@ xchk_bmap_xref_rmap(
/* Cross-reference a single rtdev extent record. */ /* Cross-reference a single rtdev extent record. */
STATIC void STATIC void
xchk_bmap_rt_extent_xref( xchk_bmap_rt_iextent_xref(
struct xchk_bmap_info *info,
struct xfs_inode *ip, struct xfs_inode *ip,
struct xfs_btree_cur *cur, struct xchk_bmap_info *info,
struct xfs_bmbt_irec *irec) struct xfs_bmbt_irec *irec)
{ {
if (info->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
return;
xchk_xref_is_used_rt_space(info->sc, irec->br_startblock, xchk_xref_is_used_rt_space(info->sc, irec->br_startblock,
irec->br_blockcount); irec->br_blockcount);
} }
/* Cross-reference a single datadev extent record. */ /* Cross-reference a single datadev extent record. */
STATIC void STATIC void
xchk_bmap_extent_xref( xchk_bmap_iextent_xref(
struct xchk_bmap_info *info,
struct xfs_inode *ip, struct xfs_inode *ip,
struct xfs_btree_cur *cur, struct xchk_bmap_info *info,
struct xfs_bmbt_irec *irec) struct xfs_bmbt_irec *irec)
{ {
struct xfs_mount *mp = info->sc->mp; struct xfs_mount *mp = info->sc->mp;
...@@ -240,9 +236,6 @@ xchk_bmap_extent_xref( ...@@ -240,9 +236,6 @@ xchk_bmap_extent_xref(
xfs_extlen_t len; xfs_extlen_t len;
int error; int error;
if (info->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
return;
agno = XFS_FSB_TO_AGNO(mp, irec->br_startblock); agno = XFS_FSB_TO_AGNO(mp, irec->br_startblock);
agbno = XFS_FSB_TO_AGBNO(mp, irec->br_startblock); agbno = XFS_FSB_TO_AGBNO(mp, irec->br_startblock);
len = irec->br_blockcount; len = irec->br_blockcount;
...@@ -300,20 +293,15 @@ xchk_bmap_dirattr_extent( ...@@ -300,20 +293,15 @@ xchk_bmap_dirattr_extent(
/* Scrub a single extent record. */ /* Scrub a single extent record. */
STATIC int STATIC int
xchk_bmap_extent( xchk_bmap_iextent(
struct xfs_inode *ip, struct xfs_inode *ip,
struct xfs_btree_cur *cur,
struct xchk_bmap_info *info, struct xchk_bmap_info *info,
struct xfs_bmbt_irec *irec) struct xfs_bmbt_irec *irec)
{ {
struct xfs_mount *mp = info->sc->mp; struct xfs_mount *mp = info->sc->mp;
struct xfs_buf *bp = NULL;
xfs_filblks_t end; xfs_filblks_t end;
int error = 0; int error = 0;
if (cur)
xfs_btree_get_block(cur, 0, &bp);
/* /*
* Check for out-of-order extents. This record could have come * Check for out-of-order extents. This record could have come
* from the incore list, for which there is no ordering check. * from the incore list, for which there is no ordering check.
...@@ -364,10 +352,13 @@ xchk_bmap_extent( ...@@ -364,10 +352,13 @@ xchk_bmap_extent(
xchk_fblock_set_corrupt(info->sc, info->whichfork, xchk_fblock_set_corrupt(info->sc, info->whichfork,
irec->br_startoff); irec->br_startoff);
if (info->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
return 0;
if (info->is_rt) if (info->is_rt)
xchk_bmap_rt_extent_xref(info, ip, cur, irec); xchk_bmap_rt_iextent_xref(ip, info, irec);
else else
xchk_bmap_extent_xref(info, ip, cur, irec); xchk_bmap_iextent_xref(ip, info, irec);
info->lastoff = irec->br_startoff + irec->br_blockcount; info->lastoff = irec->br_startoff + irec->br_blockcount;
return error; return error;
...@@ -380,10 +371,13 @@ xchk_bmapbt_rec( ...@@ -380,10 +371,13 @@ xchk_bmapbt_rec(
union xfs_btree_rec *rec) union xfs_btree_rec *rec)
{ {
struct xfs_bmbt_irec irec; struct xfs_bmbt_irec irec;
struct xfs_bmbt_irec iext_irec;
struct xfs_iext_cursor icur;
struct xchk_bmap_info *info = bs->private; struct xchk_bmap_info *info = bs->private;
struct xfs_inode *ip = bs->cur->bc_private.b.ip; struct xfs_inode *ip = bs->cur->bc_private.b.ip;
struct xfs_buf *bp = NULL; struct xfs_buf *bp = NULL;
struct xfs_btree_block *block; struct xfs_btree_block *block;
struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, info->whichfork);
uint64_t owner; uint64_t owner;
int i; int i;
...@@ -402,9 +396,26 @@ xchk_bmapbt_rec( ...@@ -402,9 +396,26 @@ xchk_bmapbt_rec(
} }
} }
/* Set up the in-core record and scrub it. */ /*
* Check that the incore extent tree contains an extent that matches
* this one exactly. We validate those cached bmaps later, so we don't
* need to check them here. If the incore extent tree was just loaded
* from disk by the scrubber, we assume that its contents match what's
* on disk (we still hold the ILOCK) and skip the equivalence check.
*/
if (!info->was_loaded)
return 0;
xfs_bmbt_disk_get_all(&rec->bmbt, &irec); xfs_bmbt_disk_get_all(&rec->bmbt, &irec);
return xchk_bmap_extent(ip, bs->cur, info, &irec); if (!xfs_iext_lookup_extent(ip, ifp, irec.br_startoff, &icur,
&iext_irec) ||
irec.br_startoff != iext_irec.br_startoff ||
irec.br_startblock != iext_irec.br_startblock ||
irec.br_blockcount != iext_irec.br_blockcount ||
irec.br_state != iext_irec.br_state)
xchk_fblock_set_corrupt(bs->sc, info->whichfork,
irec.br_startoff);
return 0;
} }
/* Scan the btree records. */ /* Scan the btree records. */
...@@ -415,15 +426,26 @@ xchk_bmap_btree( ...@@ -415,15 +426,26 @@ xchk_bmap_btree(
struct xchk_bmap_info *info) struct xchk_bmap_info *info)
{ {
struct xfs_owner_info oinfo; struct xfs_owner_info oinfo;
struct xfs_ifork *ifp = XFS_IFORK_PTR(sc->ip, whichfork);
struct xfs_mount *mp = sc->mp; struct xfs_mount *mp = sc->mp;
struct xfs_inode *ip = sc->ip; struct xfs_inode *ip = sc->ip;
struct xfs_btree_cur *cur; struct xfs_btree_cur *cur;
int error; int error;
/* Load the incore bmap cache if it's not loaded. */
info->was_loaded = ifp->if_flags & XFS_IFEXTENTS;
if (!info->was_loaded) {
error = xfs_iread_extents(sc->tp, ip, whichfork);
if (!xchk_fblock_process_error(sc, whichfork, 0, &error))
goto out;
}
/* Check the btree structure. */
cur = xfs_bmbt_init_cursor(mp, sc->tp, ip, whichfork); cur = xfs_bmbt_init_cursor(mp, sc->tp, ip, whichfork);
xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, whichfork); xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, whichfork);
error = xchk_btree(sc, cur, xchk_bmapbt_rec, &oinfo, info); error = xchk_btree(sc, cur, xchk_bmapbt_rec, &oinfo, info);
xfs_btree_del_cursor(cur, error); xfs_btree_del_cursor(cur, error);
out:
return error; return error;
} }
...@@ -671,13 +693,6 @@ xchk_bmap( ...@@ -671,13 +693,6 @@ xchk_bmap(
if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
goto out; goto out;
/* Now try to scrub the in-memory extent list. */
if (!(ifp->if_flags & XFS_IFEXTENTS)) {
error = xfs_iread_extents(sc->tp, ip, whichfork);
if (!xchk_fblock_process_error(sc, whichfork, 0, &error))
goto out;
}
/* Find the offset of the last extent in the mapping. */ /* Find the offset of the last extent in the mapping. */
error = xfs_bmap_last_offset(ip, &endoff, whichfork); error = xfs_bmap_last_offset(ip, &endoff, whichfork);
if (!xchk_fblock_process_error(sc, whichfork, 0, &error)) if (!xchk_fblock_process_error(sc, whichfork, 0, &error))
...@@ -689,7 +704,7 @@ xchk_bmap( ...@@ -689,7 +704,7 @@ xchk_bmap(
for_each_xfs_iext(ifp, &icur, &irec) { for_each_xfs_iext(ifp, &icur, &irec) {
if (xchk_should_terminate(sc, &error) || if (xchk_should_terminate(sc, &error) ||
(sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
break; goto out;
if (isnullstartblock(irec.br_startblock)) if (isnullstartblock(irec.br_startblock))
continue; continue;
if (irec.br_startoff >= endoff) { if (irec.br_startoff >= endoff) {
...@@ -697,7 +712,7 @@ xchk_bmap( ...@@ -697,7 +712,7 @@ xchk_bmap(
irec.br_startoff); irec.br_startoff);
goto out; goto out;
} }
error = xchk_bmap_extent(ip, NULL, &info, &irec); error = xchk_bmap_iextent(ip, &info, &irec);
if (error) if (error)
goto out; goto out;
} }
......
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