]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs: Pre-calculate per-AG agbno geometry
authorDave Chinner <dchinner@redhat.com>
Mon, 22 Aug 2022 14:02:59 +0000 (16:02 +0200)
committerCarlos Maiolino <cem@kernel.org>
Tue, 30 Aug 2022 08:06:44 +0000 (10:06 +0200)
Source kernel commit: 0800169e3e2c97a033e8b7f3d1e6c689e0d71a19

There is a lot of overhead in functions like xfs_verify_agbno() that
repeatedly calculate the geometry limits of an AG. These can be
pre-calculated as they are static and the verification context has
a per-ag context it can quickly reference.

In the case of xfs_verify_agbno(), we now always have a perag
context handy, so we can store the AG length and the minimum valid
block in the AG in the perag. This means we don't have to calculate
it on every call and it can be inlined in callers if we move it
to xfs_ag.h.

Move xfs_ag_block_count() to xfs_ag.c because it's really a
per-ag function and not an XFS type function. We need a little
bit of rework that is specific to xfs_initialise_perag() to allow
growfs to calculate the new perag sizes before we've updated the
primary superblock during the grow (chicken/egg situation).

Note that we leave the original xfs_verify_agbno in place in
xfs_types.c as a static function as other callers in that file do
not have per-ag contexts so still need to go the long way. It's been
renamed to xfs_verify_agno_agbno() to indicate it takes both an agno
and an agbno to differentiate it from new function.

Future commits will make similar changes for other per-ag geometry
validation functions.

Further:

$ size --totals fs/xfs/built-in.a
text    data     bss     dec     hex filename
before  1483006  329588     572 1813166  1baaae (TOTALS)
after   1482185  329588     572 1812345  1ba779 (TOTALS)

This rework reduces the binary size by ~820 bytes, indicating
that much less work is being done to bounds check the agbno values
against on per-ag geometry information.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
libxfs/init.c
libxfs/xfs_ag.c
libxfs/xfs_ag.h
libxfs/xfs_alloc.c
libxfs/xfs_btree.c
libxfs/xfs_refcount.c
libxfs/xfs_rmap.c
libxfs/xfs_types.c
libxfs/xfs_types.h
repair/scan.c

index 15052696c537395cf0498a632c2e4175b12568b6..93dc1f1c599a5b4499c250549985838a0fa6be68 100644 (file)
@@ -892,7 +892,8 @@ libxfs_mount(
                        libxfs_buf_relse(bp);
        }
 
-       error = libxfs_initialize_perag(mp, sbp->sb_agcount, &mp->m_maxagi);
+       error = libxfs_initialize_perag(mp, sbp->sb_agcount, sbp->sb_dblocks,
+                       &mp->m_maxagi);
        if (error) {
                fprintf(stderr, _("%s: perag init failed\n"),
                        progname);
index 9e43820dfe6171266264cc70f87c6dfa199b69cc..4762d7138951362503a54219336c8124e441bea2 100644 (file)
@@ -199,10 +199,35 @@ xfs_free_perag(
        }
 }
 
+/* Find the size of the AG, in blocks. */
+static xfs_agblock_t
+__xfs_ag_block_count(
+       struct xfs_mount        *mp,
+       xfs_agnumber_t          agno,
+       xfs_agnumber_t          agcount,
+       xfs_rfsblock_t          dblocks)
+{
+       ASSERT(agno < agcount);
+
+       if (agno < agcount - 1)
+               return mp->m_sb.sb_agblocks;
+       return dblocks - (agno * mp->m_sb.sb_agblocks);
+}
+
+xfs_agblock_t
+xfs_ag_block_count(
+       struct xfs_mount        *mp,
+       xfs_agnumber_t          agno)
+{
+       return __xfs_ag_block_count(mp, agno, mp->m_sb.sb_agcount,
+                       mp->m_sb.sb_dblocks);
+}
+
 int
 xfs_initialize_perag(
        struct xfs_mount        *mp,
        xfs_agnumber_t          agcount,
+       xfs_rfsblock_t          dblocks,
        xfs_agnumber_t          *maxagi)
 {
        struct xfs_perag        *pag;
@@ -268,6 +293,13 @@ xfs_initialize_perag(
                /* first new pag is fully initialized */
                if (first_initialised == NULLAGNUMBER)
                        first_initialised = index;
+
+               /*
+                * Pre-calculated geometry
+                */
+               pag->block_count = __xfs_ag_block_count(mp, index, agcount,
+                               dblocks);
+               pag->min_block = XFS_AGFL_BLOCK(mp);
        }
 
        index = xfs_set_inode_alloc(mp, agcount);
@@ -925,10 +957,16 @@ xfs_ag_extend_space(
        if (error)
                return error;
 
-       return  xfs_free_extent(tp, XFS_AGB_TO_FSB(pag->pag_mount, pag->pag_agno,
+       error = xfs_free_extent(tp, XFS_AGB_TO_FSB(pag->pag_mount, pag->pag_agno,
                                        be32_to_cpu(agf->agf_length) - len),
                                len, &XFS_RMAP_OINFO_SKIP_UPDATE,
                                XFS_AG_RESV_NONE);
+       if (error)
+               return error;
+
+       /* Update perag geometry */
+       pag->block_count = be32_to_cpu(agf->agf_length);
+       return 0;
 }
 
 /* Retrieve AG geometry. */
index 1132cda9a92fe5d44df6589b11a506ba12288643..77640f1409fd5ab04debd65268c1ab00d79f09fe 100644 (file)
@@ -67,6 +67,10 @@ struct xfs_perag {
        /* for rcu-safe freeing */
        struct rcu_head rcu_head;
 
+       /* Precalculated geometry info */
+       xfs_agblock_t           block_count;
+       xfs_agblock_t           min_block;
+
 #ifdef __KERNEL__
        /* -- kernel only structures below this line -- */
 
@@ -107,7 +111,7 @@ struct xfs_perag {
 };
 
 int xfs_initialize_perag(struct xfs_mount *mp, xfs_agnumber_t agcount,
-                       xfs_agnumber_t *maxagi);
+                       xfs_rfsblock_t dcount, xfs_agnumber_t *maxagi);
 int xfs_initialize_perag_data(struct xfs_mount *mp, xfs_agnumber_t agno);
 void xfs_free_perag(struct xfs_mount *mp);
 
@@ -116,6 +120,21 @@ struct xfs_perag *xfs_perag_get_tag(struct xfs_mount *mp, xfs_agnumber_t agno,
                unsigned int tag);
 void xfs_perag_put(struct xfs_perag *pag);
 
+/*
+ * Per-ag geometry infomation and validation
+ */
+xfs_agblock_t xfs_ag_block_count(struct xfs_mount *mp, xfs_agnumber_t agno);
+
+static inline bool
+xfs_verify_agbno(struct xfs_perag *pag, xfs_agblock_t agbno)
+{
+       if (agbno >= pag->block_count)
+               return false;
+       if (agbno <= pag->min_block)
+               return false;
+       return true;
+}
+
 /*
  * Perag iteration APIs
  */
index 5cb0b331d1a73b115a95f1f87b376b1265386ce6..91f5761a9a8d077dc4eb43ed3bd37b66476d6183 100644 (file)
@@ -244,7 +244,7 @@ xfs_alloc_get_rec(
        int                     *stat)  /* output: success/failure */
 {
        struct xfs_mount        *mp = cur->bc_mp;
-       xfs_agnumber_t          agno = cur->bc_ag.pag->pag_agno;
+       struct xfs_perag        *pag = cur->bc_ag.pag;
        union xfs_btree_rec     *rec;
        int                     error;
 
@@ -259,11 +259,11 @@ xfs_alloc_get_rec(
                goto out_bad_rec;
 
        /* check for valid extent range, including overflow */
-       if (!xfs_verify_agbno(mp, agno, *bno))
+       if (!xfs_verify_agbno(pag, *bno))
                goto out_bad_rec;
        if (*bno > *bno + *len)
                goto out_bad_rec;
-       if (!xfs_verify_agbno(mp, agno, *bno + *len - 1))
+       if (!xfs_verify_agbno(pag, *bno + *len - 1))
                goto out_bad_rec;
 
        return 0;
@@ -271,7 +271,8 @@ xfs_alloc_get_rec(
 out_bad_rec:
        xfs_warn(mp,
                "%s Freespace BTree record corruption in AG %d detected!",
-               cur->bc_btnum == XFS_BTNUM_BNO ? "Block" : "Size", agno);
+               cur->bc_btnum == XFS_BTNUM_BNO ? "Block" : "Size",
+               pag->pag_agno);
        xfs_warn(mp,
                "start block 0x%x block count 0x%x", *bno, *len);
        return -EFSCORRUPTED;
index 77a639208e62647dac8a17512a0c37eb2fad058f..4048cd9ff56bfb26e94e03a3c9013e73a05bdd7e 100644 (file)
@@ -88,10 +88,9 @@ xfs_btree_check_lblock_siblings(
 
 static inline xfs_failaddr_t
 xfs_btree_check_sblock_siblings(
-       struct xfs_mount        *mp,
+       struct xfs_perag        *pag,
        struct xfs_btree_cur    *cur,
        int                     level,
-       xfs_agnumber_t          agno,
        xfs_agblock_t           agbno,
        __be32                  dsibling)
 {
@@ -107,7 +106,7 @@ xfs_btree_check_sblock_siblings(
                if (!xfs_btree_check_sptr(cur, sibling, level + 1))
                        return __this_address;
        } else {
-               if (!xfs_verify_agbno(mp, agno, sibling))
+               if (!xfs_verify_agbno(pag, sibling))
                        return __this_address;
        }
        return NULL;
@@ -192,11 +191,11 @@ __xfs_btree_check_sblock(
        struct xfs_buf          *bp)
 {
        struct xfs_mount        *mp = cur->bc_mp;
+       struct xfs_perag        *pag = cur->bc_ag.pag;
        xfs_btnum_t             btnum = cur->bc_btnum;
        int                     crc = xfs_has_crc(mp);
        xfs_failaddr_t          fa;
        xfs_agblock_t           agbno = NULLAGBLOCK;
-       xfs_agnumber_t          agno = NULLAGNUMBER;
 
        if (crc) {
                if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
@@ -214,16 +213,14 @@ __xfs_btree_check_sblock(
            cur->bc_ops->get_maxrecs(cur, level))
                return __this_address;
 
-       if (bp) {
+       if (bp)
                agbno = xfs_daddr_to_agbno(mp, xfs_buf_daddr(bp));
-               agno = xfs_daddr_to_agno(mp, xfs_buf_daddr(bp));
-       }
 
-       fa = xfs_btree_check_sblock_siblings(mp, cur, level, agno, agbno,
+       fa = xfs_btree_check_sblock_siblings(pag, cur, level, agbno,
                        block->bb_u.s.bb_leftsib);
        if (!fa)
-               fa = xfs_btree_check_sblock_siblings(mp, cur, level, agno,
-                                agbno, block->bb_u.s.bb_rightsib);
+               fa = xfs_btree_check_sblock_siblings(pag, cur, level, agbno,
+                               block->bb_u.s.bb_rightsib);
        return fa;
 }
 
@@ -285,7 +282,7 @@ xfs_btree_check_sptr(
 {
        if (level <= 0)
                return false;
-       return xfs_verify_agbno(cur->bc_mp, cur->bc_ag.pag->pag_agno, agbno);
+       return xfs_verify_agbno(cur->bc_ag.pag, agbno);
 }
 
 /*
@@ -4592,7 +4589,6 @@ xfs_btree_sblock_verify(
 {
        struct xfs_mount        *mp = bp->b_mount;
        struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
-       xfs_agnumber_t          agno;
        xfs_agblock_t           agbno;
        xfs_failaddr_t          fa;
 
@@ -4601,12 +4597,11 @@ xfs_btree_sblock_verify(
                return __this_address;
 
        /* sibling pointer verification */
-       agno = xfs_daddr_to_agno(mp, xfs_buf_daddr(bp));
        agbno = xfs_daddr_to_agbno(mp, xfs_buf_daddr(bp));
-       fa = xfs_btree_check_sblock_siblings(mp, NULL, -1, agno, agbno,
+       fa = xfs_btree_check_sblock_siblings(bp->b_pag, NULL, -1, agbno,
                        block->bb_u.s.bb_leftsib);
        if (!fa)
-               fa = xfs_btree_check_sblock_siblings(mp, NULL, -1, agno, agbno,
+               fa = xfs_btree_check_sblock_siblings(bp->b_pag, NULL, -1, agbno,
                                block->bb_u.s.bb_rightsib);
        return fa;
 }
index f287cdea59c91641fe954d36341e86508e3153b2..bcd760fe12be76424532d04404fba9d248ea7be9 100644 (file)
@@ -110,7 +110,7 @@ xfs_refcount_get_rec(
        int                             *stat)
 {
        struct xfs_mount                *mp = cur->bc_mp;
-       xfs_agnumber_t                  agno = cur->bc_ag.pag->pag_agno;
+       struct xfs_perag                *pag = cur->bc_ag.pag;
        union xfs_btree_rec             *rec;
        int                             error;
        xfs_agblock_t                   realstart;
@@ -120,8 +120,6 @@ xfs_refcount_get_rec(
                return error;
 
        xfs_refcount_btrec_to_irec(rec, irec);
-
-       agno = cur->bc_ag.pag->pag_agno;
        if (irec->rc_blockcount == 0 || irec->rc_blockcount > MAXREFCEXTLEN)
                goto out_bad_rec;
 
@@ -136,22 +134,23 @@ xfs_refcount_get_rec(
        }
 
        /* check for valid extent range, including overflow */
-       if (!xfs_verify_agbno(mp, agno, realstart))
+       if (!xfs_verify_agbno(pag, realstart))
                goto out_bad_rec;
        if (realstart > realstart + irec->rc_blockcount)
                goto out_bad_rec;
-       if (!xfs_verify_agbno(mp, agno, realstart + irec->rc_blockcount - 1))
+       if (!xfs_verify_agbno(pag, realstart + irec->rc_blockcount - 1))
                goto out_bad_rec;
 
        if (irec->rc_refcount == 0 || irec->rc_refcount > MAXREFCOUNT)
                goto out_bad_rec;
 
-       trace_xfs_refcount_get(cur->bc_mp, cur->bc_ag.pag->pag_agno, irec);
+       trace_xfs_refcount_get(cur->bc_mp, pag->pag_agno, irec);
        return 0;
 
 out_bad_rec:
        xfs_warn(mp,
-               "Refcount BTree record corruption in AG %d detected!", agno);
+               "Refcount BTree record corruption in AG %d detected!",
+               pag->pag_agno);
        xfs_warn(mp,
                "Start block 0x%x, block count 0x%x, references 0x%x",
                irec->rc_startblock, irec->rc_blockcount, irec->rc_refcount);
index 9ea2227db9bd6ba3fe414489146651e2a8b2e181..fa4ae8fca382da6b035aeb17d79457ef174724c0 100644 (file)
@@ -214,7 +214,7 @@ xfs_rmap_get_rec(
        int                     *stat)
 {
        struct xfs_mount        *mp = cur->bc_mp;
-       xfs_agnumber_t          agno = cur->bc_ag.pag->pag_agno;
+       struct xfs_perag        *pag = cur->bc_ag.pag;
        union xfs_btree_rec     *rec;
        int                     error;
 
@@ -234,12 +234,12 @@ xfs_rmap_get_rec(
                        goto out_bad_rec;
        } else {
                /* check for valid extent range, including overflow */
-               if (!xfs_verify_agbno(mp, agno, irec->rm_startblock))
+               if (!xfs_verify_agbno(pag, irec->rm_startblock))
                        goto out_bad_rec;
                if (irec->rm_startblock >
                                irec->rm_startblock + irec->rm_blockcount)
                        goto out_bad_rec;
-               if (!xfs_verify_agbno(mp, agno,
+               if (!xfs_verify_agbno(pag,
                                irec->rm_startblock + irec->rm_blockcount - 1))
                        goto out_bad_rec;
        }
@@ -253,7 +253,7 @@ xfs_rmap_get_rec(
 out_bad_rec:
        xfs_warn(mp,
                "Reverse Mapping BTree record corruption in AG %d detected!",
-               agno);
+               pag->pag_agno);
        xfs_warn(mp,
                "Owner 0x%llx, flags 0x%x, start block 0x%x block count 0x%x",
                irec->rm_owner, irec->rm_flags, irec->rm_startblock,
index c4cc5ce5a14ea256c79db2f14257a71fd3f6b733..bbc86aeb45c60fd249f282bb1b74e86f9901677c 100644 (file)
 #include "xfs_mount.h"
 #include "xfs_ag.h"
 
-/* Find the size of the AG, in blocks. */
-inline xfs_agblock_t
-xfs_ag_block_count(
-       struct xfs_mount        *mp,
-       xfs_agnumber_t          agno)
-{
-       ASSERT(agno < mp->m_sb.sb_agcount);
-
-       if (agno < mp->m_sb.sb_agcount - 1)
-               return mp->m_sb.sb_agblocks;
-       return mp->m_sb.sb_dblocks - (agno * mp->m_sb.sb_agblocks);
-}
 
 /*
  * Verify that an AG block number pointer neither points outside the AG
  * nor points at static metadata.
  */
-inline bool
-xfs_verify_agbno(
+static inline bool
+xfs_verify_agno_agbno(
        struct xfs_mount        *mp,
        xfs_agnumber_t          agno,
        xfs_agblock_t           agbno)
@@ -59,7 +47,7 @@ xfs_verify_fsbno(
 
        if (agno >= mp->m_sb.sb_agcount)
                return false;
-       return xfs_verify_agbno(mp, agno, XFS_FSB_TO_AGBNO(mp, fsbno));
+       return xfs_verify_agno_agbno(mp, agno, XFS_FSB_TO_AGBNO(mp, fsbno));
 }
 
 /*
index 373f64a492a4feb044a67880aefa26bfad271a27..ccf61afb959df74ba10b437dd12cea5898ffbdf5 100644 (file)
@@ -179,9 +179,6 @@ enum xfs_ag_resv_type {
  */
 struct xfs_mount;
 
-xfs_agblock_t xfs_ag_block_count(struct xfs_mount *mp, xfs_agnumber_t agno);
-bool xfs_verify_agbno(struct xfs_mount *mp, xfs_agnumber_t agno,
-               xfs_agblock_t agbno);
 bool xfs_verify_fsbno(struct xfs_mount *mp, xfs_fsblock_t fsbno);
 bool xfs_verify_fsbext(struct xfs_mount *mp, xfs_fsblock_t fsbno,
                xfs_fsblock_t len);
index 020fb02f34f3580be05534d0e8969d5ea3e26ad1..a8c5cc5dd166c62f733d85b2a9b0e1584672cafd 100644 (file)
@@ -584,6 +584,7 @@ scan_allocbt(
        const struct xfs_buf_ops *ops)
 {
        struct aghdr_cnts       *agcnts = priv;
+       struct xfs_perag        *pag;
        const char              *name;
        int                     i;
        xfs_alloc_ptr_t         *pp;
@@ -670,6 +671,8 @@ _("%s freespace btree block claimed (state %d), agno %d, bno %d, suspect %d\n"),
                }
 
                rp = XFS_ALLOC_REC_ADDR(mp, block, 1);
+               pag = libxfs_perag_get(mp, agno);
+
                for (i = 0; i < numrecs; i++) {
                        xfs_agblock_t           b, end;
                        xfs_extlen_t            len, blen;
@@ -678,14 +681,14 @@ _("%s freespace btree block claimed (state %d), agno %d, bno %d, suspect %d\n"),
                        len = be32_to_cpu(rp[i].ar_blockcount);
                        end = b + len;
 
-                       if (!libxfs_verify_agbno(mp, agno, b)) {
+                       if (!libxfs_verify_agbno(pag, b)) {
                                do_warn(
        _("invalid start block %u in record %u of %s btree block %u/%u\n"),
                                        b, i, name, agno, bno);
                                continue;
                        }
                        if (len == 0 || end <= b ||
-                           !libxfs_verify_agbno(mp, agno, end - 1)) {
+                           !libxfs_verify_agbno(pag, end - 1)) {
                                do_warn(
        _("invalid length %u in record %u of %s btree block %u/%u\n"),
                                        len, i, name, agno, bno);
@@ -742,6 +745,7 @@ _("%s freespace btree block claimed (state %d), agno %d, bno %d, suspect %d\n"),
                                }
                        }
                }
+               libxfs_perag_put(pag);
                return;
        }
 
@@ -776,14 +780,16 @@ _("%s freespace btree block claimed (state %d), agno %d, bno %d, suspect %d\n"),
                suspect = 0;
        }
 
+       pag = libxfs_perag_get(mp, agno);
        for (i = 0; i < numrecs; i++)  {
                xfs_agblock_t           agbno = be32_to_cpu(pp[i]);
 
-               if (!libxfs_verify_agbno(mp, agno, agbno)) {
+               if (!libxfs_verify_agbno(pag, agbno)) {
                        do_warn(
        _("bad btree pointer (%u) in %sbt block %u/%u\n"),
                                agbno, name, agno, bno);
                        suspect++;
+                       libxfs_perag_put(pag);
                        return;
                }
 
@@ -799,6 +805,7 @@ _("%s freespace btree block claimed (state %d), agno %d, bno %d, suspect %d\n"),
                scan_sbtree(agbno, level, agno, suspect, scan_allocbt, 0,
                                magic, priv, ops);
        }
+       libxfs_perag_put(pag);
 }
 
 static bool
@@ -986,6 +993,7 @@ scan_rmapbt(
        uint64_t                lastoffset = 0;
        struct xfs_rmap_key     *kp;
        struct xfs_rmap_irec    key = {0};
+       struct xfs_perag        *pag;
 
        if (magic != XFS_RMAP_CRC_MAGIC) {
                name = "(unknown)";
@@ -1223,6 +1231,7 @@ advance:
                                i, agno, bno, name);
        }
 
+       pag = libxfs_perag_get(mp, agno);
        for (i = 0; i < numrecs; i++)  {
                xfs_agblock_t           agbno = be32_to_cpu(pp[i]);
 
@@ -1250,17 +1259,19 @@ advance:
                        continue;
                }
 
-               if (!libxfs_verify_agbno(mp, agno, agbno)) {
+               if (!libxfs_verify_agbno(pag, agbno)) {
                        do_warn(
        _("bad btree pointer (%u) in %sbt block %u/%u\n"),
                                agbno, name, agno, bno);
                        suspect++;
+                       libxfs_perag_put(pag);
                        return;
                }
 
                scan_sbtree(agbno, level, agno, suspect, scan_rmapbt, 0, magic,
                                priv, ops);
        }
+       libxfs_perag_put(pag);
 
 out:
        if (suspect)
@@ -1294,6 +1305,7 @@ scan_refcbt(
        int                     state;
        xfs_agblock_t           lastblock = 0;
        struct refc_priv        *refc_priv = priv;
+       struct xfs_perag        *pag;
 
        if (magic != XFS_REFC_CRC_MAGIC) {
                name = "(unknown)";
@@ -1352,6 +1364,8 @@ _("%s btree block claimed (state %d), agno %d, bno %d, suspect %d\n"),
                }
 
                rp = XFS_REFCOUNT_REC_ADDR(block, 1);
+               pag = libxfs_perag_get(mp, agno);
+
                for (i = 0; i < numrecs; i++) {
                        xfs_agblock_t           b, agb, end;
                        xfs_extlen_t            len;
@@ -1373,14 +1387,14 @@ _("leftover CoW extent has invalid startblock in record %u of %s btree block %u/
                        }
                        end = agb + len;
 
-                       if (!libxfs_verify_agbno(mp, agno, agb)) {
+                       if (!libxfs_verify_agbno(pag, agb)) {
                                do_warn(
        _("invalid start block %u in record %u of %s btree block %u/%u\n"),
                                        b, i, name, agno, bno);
                                continue;
                        }
                        if (len == 0 || end <= agb ||
-                           !libxfs_verify_agbno(mp, agno, end - 1)) {
+                           !libxfs_verify_agbno(pag, end - 1)) {
                                do_warn(
        _("invalid length %u in record %u of %s btree block %u/%u\n"),
                                        len, i, name, agno, bno);
@@ -1439,6 +1453,7 @@ _("extent (%u/%u) len %u claimed, state is %d\n"),
 
                        /* XXX: probably want to mark the reflinked areas? */
                }
+               libxfs_perag_put(pag);
                goto out;
        }
 
@@ -1473,20 +1488,23 @@ _("extent (%u/%u) len %u claimed, state is %d\n"),
                suspect = 0;
        }
 
+       pag = libxfs_perag_get(mp, agno);
        for (i = 0; i < numrecs; i++)  {
                xfs_agblock_t           agbno = be32_to_cpu(pp[i]);
 
-               if (!libxfs_verify_agbno(mp, agno, agbno)) {
+               if (!libxfs_verify_agbno(pag, agbno)) {
                        do_warn(
        _("bad btree pointer (%u) in %sbt block %u/%u\n"),
                                agbno, name, agno, bno);
                        suspect++;
+                       libxfs_perag_put(pag);
                        return;
                }
 
                scan_sbtree(agbno, level, agno, suspect, scan_refcbt, 0, magic,
                                priv, ops);
        }
+       libxfs_perag_put(pag);
 out:
        if (suspect)
                refcount_avoid_check();
@@ -1994,6 +2012,7 @@ scan_inobt(
        int                     hdr_errors;
        int                     freecount;
        struct xfs_ino_geometry *igeo = M_IGEO(mp);
+       struct xfs_perag        *pag;
 
        hdr_errors = 0;
 
@@ -2161,20 +2180,23 @@ _("%sbt btree block claimed (state %d), agno %d, bno %d, suspect %d\n"),
                else suspect++;
        }
 
+       pag = libxfs_perag_get(mp, agno);
        for (i = 0; i < numrecs; i++)  {
                xfs_agblock_t   agbno = be32_to_cpu(pp[i]);
 
-               if (!libxfs_verify_agbno(mp, agno, agbno)) {
+               if (!libxfs_verify_agbno(pag, agbno)) {
                        do_warn(
        _("bad btree pointer (%u) in %sbt block %u/%u\n"),
                                agbno, name, agno, bno);
                        suspect++;
+                       libxfs_perag_put(pag);
                        return;
                }
 
                scan_sbtree(be32_to_cpu(pp[i]), level, agno, suspect,
                                scan_inobt, 0, magic, priv, ops);
        }
+       libxfs_perag_put(pag);
 }
 
 struct agfl_state {
@@ -2189,12 +2211,16 @@ scan_agfl(
        void                    *priv)
 {
        struct agfl_state       *as = priv;
+       struct xfs_perag        *pag;
 
-       if (libxfs_verify_agbno(mp, as->agno, bno))
+       pag = libxfs_perag_get(mp, as->agno);
+       if (libxfs_verify_agbno(pag, bno))
                set_bmap(as->agno, bno, XR_E_FREE);
        else
                do_warn(_("bad agbno %u in agfl, agno %d\n"),
                        bno, as->agno);
+
+       libxfs_perag_put(pag);
        as->count++;
        return 0;
 }
@@ -2262,6 +2288,7 @@ validate_agf(
        xfs_agblock_t           bno;
        uint32_t                magic;
        unsigned int            levels;
+       struct xfs_perag        *pag = libxfs_perag_get(mp, agno);
 
        levels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]);
        if (levels == 0 || levels > mp->m_alloc_maxlevels) {
@@ -2270,7 +2297,7 @@ validate_agf(
        }
 
        bno = be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNO]);
-       if (libxfs_verify_agbno(mp, agno, bno)) {
+       if (libxfs_verify_agbno(pag, bno)) {
                magic = xfs_has_crc(mp) ? XFS_ABTB_CRC_MAGIC
                                                         : XFS_ABTB_MAGIC;
                scan_sbtree(bno, be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]),
@@ -2288,7 +2315,7 @@ validate_agf(
        }
 
        bno = be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNT]);
-       if (libxfs_verify_agbno(mp, agno, bno)) {
+       if (libxfs_verify_agbno(pag, bno)) {
                magic = xfs_has_crc(mp) ? XFS_ABTC_CRC_MAGIC
                                                         : XFS_ABTC_MAGIC;
                scan_sbtree(bno, be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]),
@@ -2316,7 +2343,7 @@ validate_agf(
                }
 
                bno = be32_to_cpu(agf->agf_roots[XFS_BTNUM_RMAP]);
-               if (libxfs_verify_agbno(mp, agno, bno)) {
+               if (libxfs_verify_agbno(pag, bno)) {
                        scan_sbtree(bno, levels, agno, 0, scan_rmapbt, 1,
                                        XFS_RMAP_CRC_MAGIC, &priv,
                                        &xfs_rmapbt_buf_ops);
@@ -2340,7 +2367,7 @@ validate_agf(
                }
 
                bno = be32_to_cpu(agf->agf_refcount_root);
-               if (libxfs_verify_agbno(mp, agno, bno)) {
+               if (libxfs_verify_agbno(pag, bno)) {
                        struct refc_priv        priv;
 
                        memset(&priv, 0, sizeof(priv));
@@ -2373,6 +2400,7 @@ validate_agf(
                do_warn(_("agf_btreeblks %u, counted %" PRIu64 " in ag %u\n"),
                        be32_to_cpu(agf->agf_btreeblks), agcnts->agfbtreeblks, agno);
        }
+       libxfs_perag_put(pag);
 
 }
 
@@ -2389,6 +2417,7 @@ validate_agi(
        int                     i;
        uint32_t                magic;
        unsigned int            levels;
+       struct xfs_perag        *pag = libxfs_perag_get(mp, agno);
 
        levels = be32_to_cpu(agi->agi_level);
        if (levels == 0 || levels > M_IGEO(mp)->inobt_maxlevels) {
@@ -2397,7 +2426,7 @@ validate_agi(
        }
 
        bno = be32_to_cpu(agi->agi_root);
-       if (libxfs_verify_agbno(mp, agno, bno)) {
+       if (libxfs_verify_agbno(pag, bno)) {
                magic = xfs_has_crc(mp) ? XFS_IBT_CRC_MAGIC
                                                         : XFS_IBT_MAGIC;
                scan_sbtree(bno, be32_to_cpu(agi->agi_level),
@@ -2416,7 +2445,7 @@ validate_agi(
                }
 
                bno = be32_to_cpu(agi->agi_free_root);
-               if (libxfs_verify_agbno(mp, agno, bno)) {
+               if (libxfs_verify_agbno(pag, bno)) {
                        magic = xfs_has_crc(mp) ?
                                        XFS_FIBT_CRC_MAGIC : XFS_FIBT_MAGIC;
                        scan_sbtree(bno, be32_to_cpu(agi->agi_free_level),
@@ -2466,6 +2495,7 @@ validate_agi(
                                XFS_AGINO_TO_INO(mp, agno, agino));
                }
        }
+       libxfs_perag_put(pag);
 }
 
 /*