@@ -434,6 +434,30 @@ xfs_scrub_put_ag_headers(
*agi_bpp = *agf_bpp = NULL;
}
+/* Does this AG extent cover the AG headers? */
+STATIC 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;
+}
+
/*
* For scrub, grab the AGI and the AGF headers, in that order.
* Locking order requires us to get the AGI before the AGF.
@@ -1013,6 +1037,10 @@ xfs_scrub_agfl(
XFS_SCRUB_CHECK(mp, agfl_bp, "AGFL",
agbno < eoag);
+ /* Cross-reference with the AG headers. */
+ XFS_SCRUB_CHECK(mp, agfl_bp, "AGFL",
+ !xfs_scrub_extent_covers_ag_head(mp, agbno, 1));
+
/* Cross-reference with the bnobt. */
err2 = xfs_alloc_has_record(xcur, agbno, 1, &is_freesp);
if (!err2)
@@ -1117,6 +1145,10 @@ xfs_scrub_allocbt_helper(
XFS_BTREC_SCRUB_CHECK(bs, (unsigned long long)bno + len <=
be32_to_cpu(agf->agf_length));
+ /* Make sure we don't cover the AG headers. */
+ XFS_BTREC_SCRUB_CHECK(bs,
+ !xfs_scrub_extent_covers_ag_head(mp, bno, len));
+
/*
* Ensure there's a corresponding cntbt/bnobt record matching
* this bnobt/cntbt record, respectively.
@@ -1233,6 +1265,10 @@ xfs_scrub_iallocbt_helper(
XFS_BTREC_SCRUB_CHECK(bs, (unsigned long long)bno + len <=
eoag);
+ /* Make sure we don't cover the AG headers. */
+ XFS_BTREC_SCRUB_CHECK(bs,
+ !xfs_scrub_extent_covers_ag_head(mp, bno, len));
+
/* Cross-reference with the bnobt. */
err2 = xfs_alloc_has_record(bs->bno_cur, bno, len,
&is_freesp);
@@ -1267,6 +1303,10 @@ xfs_scrub_iallocbt_helper(
XFS_BTREC_SCRUB_CHECK(bs, (unsigned long long)bno + len <=
eoag);
+ /* Make sure we don't cover the AG headers. */
+ XFS_BTREC_SCRUB_CHECK(bs,
+ !xfs_scrub_extent_covers_ag_head(mp, bno, len));
+
/* Cross-reference with the bnobt. */
err2 = xfs_alloc_has_record(bs->bno_cur, bno, len,
&is_freesp);
@@ -1378,6 +1418,11 @@ xfs_scrub_rmapbt_helper(
XFS_BTREC_SCRUB_CHECK(bs, !non_inode || !(is_bmbt || is_unwritten ||
is_attr));
+ /* Make sure only the AG header owner maps to the AG header. */
+ XFS_BTREC_SCRUB_CHECK(bs, irec.rm_owner == XFS_RMAP_OWN_FS ||
+ !xfs_scrub_extent_covers_ag_head(mp, irec.rm_startblock,
+ irec.rm_blockcount));
+
/* check there's no record in freesp btrees */
err2 = xfs_alloc_has_record(bs->bno_cur, irec.rm_startblock,
irec.rm_blockcount, &is_freesp);
@@ -1452,6 +1497,10 @@ xfs_scrub_refcountbt_helper(
irec.rc_blockcount <= eoag);
XFS_BTREC_SCRUB_CHECK(bs, irec.rc_refcount >= 1);
+ /* Make sure we don't cover the AG headers. */
+ XFS_BTREC_SCRUB_CHECK(bs, !xfs_scrub_extent_covers_ag_head(mp,
+ irec.rc_startblock, irec.rc_blockcount));
+
/* Cross-reference with the bnobt. */
err2 = xfs_alloc_has_record(bs->bno_cur, irec.rc_startblock,
irec.rc_blockcount, &is_freesp);
@@ -1639,6 +1688,11 @@ xfs_scrub_bmap_extent(
if (error)
goto out;
+ /* Make sure we don't cover the AG headers. */
+ XFS_INO_SCRUB_CHECK(ip, bp, info->type, info->is_rt ||
+ !xfs_scrub_extent_covers_ag_head(mp, bno,
+ irec->br_blockcount));
+
/* Cross-reference with the bnobt. */
xcur = xfs_allocbt_init_cursor(mp, NULL, agf_bp, agno,
XFS_BTNUM_BNO);
Ensure that none of the AG btree records overlap the AG sb/agf/agfl/agi headers except for the XFS_RMAP_OWN_FS rmap. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> --- fs/xfs/xfs_scrub.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+)