@@ -116,6 +116,30 @@ xfs_scrub_walk_agfl(
return 0;
}
+/* Does this AG extent cover the AG headers? */
+bool
+xfs_scrub_extent_covers_ag_head(
+ struct xfs_mount *mp,
+ xfs_agblock_t agbno,
+ xfs_extlen_t len)
+{
+ xfs_agblock_t bno;
+
+ bno = XFS_SB_BLOCK(mp);
+ if (bno >= agbno && bno < agbno + len)
+ return true;
+ bno = XFS_AGF_BLOCK(mp);
+ if (bno >= agbno && bno < agbno + len)
+ return true;
+ bno = XFS_AGFL_BLOCK(mp);
+ if (bno >= agbno && bno < agbno + len)
+ return true;
+ bno = XFS_AGI_BLOCK(mp);
+ if (bno >= agbno && bno < agbno + len)
+ return true;
+ return false;
+}
+
/* Superblock */
/* Scrub the filesystem superblock. */
@@ -595,6 +619,10 @@ xfs_scrub_agfl_block(
agbno < sagfl->eoag &&
XFS_AGB_TO_DADDR(mp, agno, agbno) < sagfl->eofs);
+ /* Cross-reference with the AG headers. */
+ xfs_scrub_block_xref_check_ok(sc, sc->sa.agfl_bp,
+ !xfs_scrub_extent_covers_ag_head(mp, agbno, 1));
+
/* Cross-reference with the bnobt. */
if (sc->sa.bno_cur) {
error = xfs_alloc_has_record(sc->sa.bno_cur, agbno,
@@ -81,6 +81,10 @@ xfs_scrub_allocbt_helper(
rec_end <= mp->m_sb.sb_agblocks &&
rec_end <= be32_to_cpu(agf->agf_length));
+ /* Cross-reference with the AG headers. */
+ xfs_scrub_btree_xref_check_ok(bs->sc, bs->cur, 0,
+ !xfs_scrub_extent_covers_ag_head(mp, bno, len));
+
psa = &bs->sc->sa;
/*
* Ensure there's a corresponding cntbt/bnobt record matching
@@ -183,6 +183,13 @@ xfs_scrub_bmap_extent(
goto out;
}
+ /* Cross-reference with the AG headers. */
+ if (!info->is_rt)
+ xfs_scrub_fblock_xref_check_ok(info->sc, info->whichfork,
+ irec->br_startoff,
+ !xfs_scrub_extent_covers_ag_head(mp,
+ bno, irec->br_blockcount));
+
/* Cross-reference with the bnobt. */
if (sa.bno_cur) {
error = xfs_alloc_has_record(sa.bno_cur, bno,
@@ -158,6 +158,8 @@ int xfs_scrub_walk_agfl(struct xfs_scrub_context *sc,
int (*fn)(struct xfs_scrub_context *, xfs_agblock_t bno,
void *),
void *priv);
+bool xfs_scrub_extent_covers_ag_head(struct xfs_mount *mp, xfs_agblock_t agbno,
+ xfs_extlen_t len);
int xfs_scrub_setup_ag_btree(struct xfs_scrub_context *sc,
struct xfs_inode *ip, bool force_log);
@@ -85,6 +85,10 @@ xfs_scrub_iallocbt_chunk(
rec_end <= mp->m_sb.sb_agblocks && rec_end <= eoag))
return false;
+ /* Cross-reference with the AG headers. */
+ xfs_scrub_btree_xref_check_ok(bs->sc, bs->cur, 0,
+ !xfs_scrub_extent_covers_ag_head(mp, bno, len));
+
psa = &bs->sc->sa;
/* Cross-reference with the bnobt. */
if (psa->bno_cur) {
@@ -86,6 +86,11 @@ xfs_scrub_refcountbt_helper(
rec_end <= eoag &&
irec.rc_refcount >= 1);
+ /* Cross-reference with the AG headers. */
+ xfs_scrub_btree_xref_check_ok(bs->sc, bs->cur, 0,
+ !xfs_scrub_extent_covers_ag_head(mp,
+ irec.rc_startblock, irec.rc_blockcount));
+
psa = &bs->sc->sa;
/* Cross-reference with the bnobt. */
if (psa->bno_cur) {
@@ -117,6 +117,12 @@ xfs_scrub_rmapbt_helper(
(irec.rm_owner > XFS_RMAP_OWN_MIN &&
irec.rm_owner <= XFS_RMAP_OWN_FS));
+ /* Cross-reference with the AG headers. */
+ xfs_scrub_btree_xref_check_ok(bs->sc, bs->cur, 0,
+ irec.rm_owner == XFS_RMAP_OWN_FS ||
+ !xfs_scrub_extent_covers_ag_head(mp, irec.rm_startblock,
+ irec.rm_blockcount));
+
psa = &bs->sc->sa;
/* Cross-reference with the bnobt. */
if (psa->bno_cur) {