]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_repair: rebuild reverse mapping btrees with bulk loader
authorDarrick J. Wong <darrick.wong@oracle.com>
Fri, 10 Jul 2020 19:35:46 +0000 (15:35 -0400)
committerEric Sandeen <sandeen@sandeen.net>
Fri, 10 Jul 2020 19:35:46 +0000 (15:35 -0400)
Use the btree bulk loading functions to rebuild the reverse mapping
btrees and drop the open-coded implementation.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
[sandeen: adjust for prior inclusion of "fix rebuilding btree block..."]
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
libxfs/libxfs_api_defs.h
repair/agbtree.c
repair/agbtree.h
repair/phase5.c

index 5d0868c2a712ac3beb22066116d3c3ee8eeb337e..0026ca45d6d6936cc1d7b6b5b9510d62f46f0355 100644 (file)
 #define xfs_rmapbt_calc_reserves       libxfs_rmapbt_calc_reserves
 #define xfs_rmapbt_init_cursor         libxfs_rmapbt_init_cursor
 #define xfs_rmapbt_maxrecs             libxfs_rmapbt_maxrecs
+#define xfs_rmapbt_stage_cursor                libxfs_rmapbt_stage_cursor
 #define xfs_rmap_compare               libxfs_rmap_compare
 #define xfs_rmap_get_rec               libxfs_rmap_get_rec
 #define xfs_rmap_irec_offset_pack      libxfs_rmap_irec_offset_pack
index 874e6ff92f1879543fc6e9fbeb447f0636419133..1f07b63c9cd5f370fc0432e91dcc52581bd2bb4a 100644 (file)
@@ -515,3 +515,73 @@ _("Error %d while creating finobt btree for AG %u.\n"), error, agno);
        /* Since we're not writing the AGI yet, no need to commit the cursor */
        libxfs_btree_del_cursor(btr_fino->cur, 0);
 }
+
+/* rebuild the rmap tree */
+
+/* Grab one rmap record. */
+static int
+get_rmapbt_record(
+       struct xfs_btree_cur            *cur,
+       void                            *priv)
+{
+       struct xfs_rmap_irec            *rec;
+       struct bt_rebuild               *btr = priv;
+
+       rec = pop_slab_cursor(btr->slab_cursor);
+       memcpy(&cur->bc_rec.r, rec, sizeof(struct xfs_rmap_irec));
+       return 0;
+}
+
+/* Set up the rmap rebuild parameters. */
+void
+init_rmapbt_cursor(
+       struct repair_ctx       *sc,
+       xfs_agnumber_t          agno,
+       unsigned int            free_space,
+       struct bt_rebuild       *btr)
+{
+       int                     error;
+
+       if (!xfs_sb_version_hasrmapbt(&sc->mp->m_sb))
+               return;
+
+       init_rebuild(sc, &XFS_RMAP_OINFO_AG, free_space, btr);
+       btr->cur = libxfs_rmapbt_stage_cursor(sc->mp, &btr->newbt.afake, agno);
+
+       btr->bload.get_record = get_rmapbt_record;
+       btr->bload.claim_block = rebuild_claim_block;
+
+       /* Compute how many blocks we'll need. */
+       error = -libxfs_btree_bload_compute_geometry(btr->cur, &btr->bload,
+                       rmap_record_count(sc->mp, agno));
+       if (error)
+               do_error(
+_("Unable to compute rmap btree geometry, error %d.\n"), error);
+
+       reserve_btblocks(sc->mp, agno, btr, btr->bload.nr_blocks);
+}
+
+/* Rebuild a rmap btree. */
+void
+build_rmap_tree(
+       struct repair_ctx       *sc,
+       xfs_agnumber_t          agno,
+       struct bt_rebuild       *btr)
+{
+       int                     error;
+
+       error = rmap_init_cursor(agno, &btr->slab_cursor);
+       if (error)
+               do_error(
+_("Insufficient memory to construct rmap cursor.\n"));
+
+       /* Add all observed rmap records. */
+       error = -libxfs_btree_bload(btr->cur, &btr->bload, btr);
+       if (error)
+               do_error(
+_("Error %d while creating rmap btree for AG %u.\n"), error, agno);
+
+       /* Since we're not writing the AGF yet, no need to commit the cursor */
+       libxfs_btree_del_cursor(btr->cur, 0);
+       free_slab_cursor(&btr->slab_cursor);
+}
index 3cad2a8e91868c8f23a9c214f90023a2e7637c88..ca6e70de964327f5b4dd92dccb659b5b0e29963b 100644 (file)
@@ -49,4 +49,9 @@ void init_ino_cursors(struct repair_ctx *sc, xfs_agnumber_t agno,
 void build_inode_btrees(struct repair_ctx *sc, xfs_agnumber_t agno,
                struct bt_rebuild *btr_ino, struct bt_rebuild *btr_fino);
 
+void init_rmapbt_cursor(struct repair_ctx *sc, xfs_agnumber_t agno,
+               unsigned int free_space, struct bt_rebuild *btr);
+void build_rmap_tree(struct repair_ctx *sc, xfs_agnumber_t agno,
+               struct bt_rebuild *btr);
+
 #endif /* __XFS_REPAIR_AG_BTREE_H__ */
index 82b430ee4417ec45130dc24d83a99f2e1c94ad15..1c6448f4b033f6ffb52ae74f8f31214c7aa77b16 100644 (file)
@@ -336,45 +336,6 @@ finish_cursor(bt_status_t *curs)
        free(curs->btree_blocks);
 }
 
-/*
- * We need to leave some free records in the tree for the corner case of
- * setting up the AGFL. This may require allocation of blocks, and as
- * such can require insertion of new records into the tree (e.g. moving
- * a record in the by-count tree when a long extent is shortened). If we
- * pack the records into the leaves with no slack space, this requires a
- * leaf split to occur and a block to be allocated from the free list.
- * If we don't have any blocks on the free list (because we are setting
- * it up!), then we fail, and the filesystem will fail with the same
- * failure at runtime. Hence leave a couple of records slack space in
- * each block to allow immediate modification of the tree without
- * requiring splits to be done.
- */
-static void
-compute_level_geometry(
-       struct xfs_mount        *mp,
-       struct bt_stat_level    *lptr,
-       uint64_t                nr_this_level,
-       int                     slack,
-       bool                    leaf)
-{
-       unsigned int            maxrecs = mp->m_alloc_mxr[!leaf];
-       unsigned int            desired_npb;
-
-       desired_npb = max(mp->m_alloc_mnr[!leaf], maxrecs - slack);
-       lptr->num_recs_tot = nr_this_level;
-       lptr->num_blocks = max(1ULL, nr_this_level / desired_npb);
-
-       lptr->num_recs_pb = nr_this_level / lptr->num_blocks;
-       lptr->modulo = nr_this_level % lptr->num_blocks;
-       if (lptr->num_recs_pb > maxrecs ||
-           (lptr->num_recs_pb == maxrecs && lptr->modulo)) {
-               lptr->num_blocks++;
-
-               lptr->num_recs_pb = nr_this_level / lptr->num_blocks;
-               lptr->modulo = nr_this_level % lptr->num_blocks;
-       }
-}
-
 /* Map btnum to buffer ops for the types that need it. */
 static const struct xfs_buf_ops *
 btnum_to_ops(
@@ -456,364 +417,6 @@ build_agi(
        libxfs_buf_relse(agi_buf);
 }
 
-/* rebuild the rmap tree */
-
-/*
- * we don't have to worry here about how chewing up free extents
- * may perturb things because rmap tree building happens before
- * freespace tree building.
- */
-static void
-init_rmapbt_cursor(
-       struct xfs_mount        *mp,
-       xfs_agnumber_t          agno,
-       struct bt_status        *btree_curs)
-{
-       size_t                  num_recs;
-       int                     level;
-       struct bt_stat_level    *lptr;
-       struct bt_stat_level    *p_lptr;
-       xfs_extlen_t            blocks_allocated;
-
-       if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) {
-               memset(btree_curs, 0, sizeof(struct bt_status));
-               return;
-       }
-
-       lptr = &btree_curs->level[0];
-       btree_curs->init = 1;
-       btree_curs->owner = XFS_RMAP_OWN_AG;
-
-       /*
-        * build up statistics
-        */
-       num_recs = rmap_record_count(mp, agno);
-       if (num_recs == 0) {
-               /*
-                * easy corner-case -- no rmap records
-                */
-               lptr->num_blocks = 1;
-               lptr->modulo = 0;
-               lptr->num_recs_pb = 0;
-               lptr->num_recs_tot = 0;
-
-               btree_curs->num_levels = 1;
-               btree_curs->num_tot_blocks = btree_curs->num_free_blocks = 1;
-
-               setup_cursor(mp, agno, btree_curs);
-
-               return;
-       }
-
-       /*
-        * Leave enough slack in the rmapbt that we can insert the
-        * metadata AG entries without too many splits.
-        */
-       compute_level_geometry(mp, lptr, num_recs,
-                       num_recs > mp->m_rmap_mxr[0] ? 10 : 0, true);
-       blocks_allocated = lptr->num_blocks;
-       level = 1;
-
-       while (lptr->num_blocks > 1) {
-               p_lptr = lptr;
-               lptr = &btree_curs->level[level++];
-
-               compute_level_geometry(mp, lptr,
-                               p_lptr->num_blocks, 0, false);
-               blocks_allocated += lptr->num_blocks;
-       }
-       ASSERT(level < XFS_BTREE_MAXLEVELS);
-       ASSERT(lptr->num_blocks == 1);
-       btree_curs->num_levels = level;
-
-       btree_curs->num_tot_blocks = btree_curs->num_free_blocks
-                       = blocks_allocated;
-
-       setup_cursor(mp, agno, btree_curs);
-}
-
-static void
-prop_rmap_cursor(
-       struct xfs_mount        *mp,
-       xfs_agnumber_t          agno,
-       struct bt_status        *btree_curs,
-       struct xfs_rmap_irec    *rm_rec,
-       int                     level)
-{
-       struct xfs_btree_block  *bt_hdr;
-       struct xfs_rmap_key     *bt_key;
-       xfs_rmap_ptr_t          *bt_ptr;
-       xfs_agblock_t           agbno;
-       struct bt_stat_level    *lptr;
-       const struct xfs_buf_ops *ops = btnum_to_ops(XFS_BTNUM_RMAP);
-       int                     error;
-
-       level++;
-
-       if (level >= btree_curs->num_levels)
-               return;
-
-       lptr = &btree_curs->level[level];
-       bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p);
-
-       if (be16_to_cpu(bt_hdr->bb_numrecs) == 0)  {
-               /*
-                * this only happens once to initialize the
-                * first path up the left side of the tree
-                * where the agbno's are already set up
-                */
-               prop_rmap_cursor(mp, agno, btree_curs, rm_rec, level);
-       }
-
-       if (be16_to_cpu(bt_hdr->bb_numrecs) ==
-                               lptr->num_recs_pb + (lptr->modulo > 0))  {
-               /*
-                * write out current prev block, grab us a new block,
-                * and set the rightsib pointer of current block
-                */
-#ifdef XR_BLD_INO_TRACE
-               fprintf(stderr, " rmap prop agbno %d ", lptr->prev_agbno);
-#endif
-               if (lptr->prev_agbno != NULLAGBLOCK)  {
-                       ASSERT(lptr->prev_buf_p != NULL);
-                       libxfs_buf_mark_dirty(lptr->prev_buf_p);
-                       libxfs_buf_relse(lptr->prev_buf_p);
-               }
-               lptr->prev_agbno = lptr->agbno;
-               lptr->prev_buf_p = lptr->buf_p;
-               agbno = get_next_blockaddr(agno, level, btree_curs);
-
-               bt_hdr->bb_u.s.bb_rightsib = cpu_to_be32(agbno);
-
-               error = -libxfs_buf_get(mp->m_dev,
-                               XFS_AGB_TO_DADDR(mp, agno, agbno),
-                               XFS_FSB_TO_BB(mp, 1), &lptr->buf_p);
-               if (error)
-                       do_error(_("Cannot grab rmapbt buffer, err=%d"),
-                                       error);
-               lptr->agbno = agbno;
-
-               if (lptr->modulo)
-                       lptr->modulo--;
-
-               /*
-                * initialize block header
-                */
-               lptr->buf_p->b_ops = ops;
-               bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p);
-               memset(bt_hdr, 0, mp->m_sb.sb_blocksize);
-               libxfs_btree_init_block(mp, lptr->buf_p, XFS_BTNUM_RMAP,
-                                       level, 0, agno);
-
-               bt_hdr->bb_u.s.bb_leftsib = cpu_to_be32(lptr->prev_agbno);
-
-               /*
-                * propagate extent record for first extent in new block up
-                */
-               prop_rmap_cursor(mp, agno, btree_curs, rm_rec, level);
-       }
-       /*
-        * add rmap info to current block
-        */
-       be16_add_cpu(&bt_hdr->bb_numrecs, 1);
-
-       bt_key = XFS_RMAP_KEY_ADDR(bt_hdr,
-                                   be16_to_cpu(bt_hdr->bb_numrecs));
-       bt_ptr = XFS_RMAP_PTR_ADDR(bt_hdr,
-                                   be16_to_cpu(bt_hdr->bb_numrecs),
-                                   mp->m_rmap_mxr[1]);
-
-       bt_key->rm_startblock = cpu_to_be32(rm_rec->rm_startblock);
-       bt_key->rm_owner = cpu_to_be64(rm_rec->rm_owner);
-       bt_key->rm_offset = cpu_to_be64(rm_rec->rm_offset);
-
-       *bt_ptr = cpu_to_be32(btree_curs->level[level-1].agbno);
-}
-
-static void
-prop_rmap_highkey(
-       struct xfs_mount        *mp,
-       xfs_agnumber_t          agno,
-       struct bt_status        *btree_curs,
-       struct xfs_rmap_irec    *rm_highkey)
-{
-       struct xfs_btree_block  *bt_hdr;
-       struct xfs_rmap_key     *bt_key;
-       struct bt_stat_level    *lptr;
-       struct xfs_rmap_irec    key = {0};
-       struct xfs_rmap_irec    high_key;
-       int                     level;
-       int                     i;
-       int                     numrecs;
-
-       high_key = *rm_highkey;
-       for (level = 1; level < btree_curs->num_levels; level++) {
-               lptr = &btree_curs->level[level];
-               bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p);
-               numrecs = be16_to_cpu(bt_hdr->bb_numrecs);
-               bt_key = XFS_RMAP_HIGH_KEY_ADDR(bt_hdr, numrecs);
-
-               bt_key->rm_startblock = cpu_to_be32(high_key.rm_startblock);
-               bt_key->rm_owner = cpu_to_be64(high_key.rm_owner);
-               bt_key->rm_offset = cpu_to_be64(
-                               libxfs_rmap_irec_offset_pack(&high_key));
-
-               for (i = 1; i <= numrecs; i++) {
-                       bt_key = XFS_RMAP_HIGH_KEY_ADDR(bt_hdr, i);
-                       key.rm_startblock = be32_to_cpu(bt_key->rm_startblock);
-                       key.rm_owner = be64_to_cpu(bt_key->rm_owner);
-                       key.rm_offset = be64_to_cpu(bt_key->rm_offset);
-                       if (rmap_diffkeys(&key, &high_key) > 0)
-                               high_key = key;
-               }
-       }
-}
-
-/*
- * rebuilds a rmap btree given a cursor.
- */
-static void
-build_rmap_tree(
-       struct xfs_mount        *mp,
-       xfs_agnumber_t          agno,
-       struct bt_status        *btree_curs)
-{
-       xfs_agnumber_t          i;
-       xfs_agblock_t           j;
-       xfs_agblock_t           agbno;
-       struct xfs_btree_block  *bt_hdr;
-       struct xfs_rmap_irec    *rm_rec;
-       struct xfs_slab_cursor  *rmap_cur;
-       struct xfs_rmap_rec     *bt_rec;
-       struct xfs_rmap_irec    highest_key = {0};
-       struct xfs_rmap_irec    hi_key = {0};
-       struct bt_stat_level    *lptr;
-       const struct xfs_buf_ops *ops = btnum_to_ops(XFS_BTNUM_RMAP);
-       int                     numrecs;
-       int                     level = btree_curs->num_levels;
-       int                     error;
-
-       highest_key.rm_flags = 0;
-       for (i = 0; i < level; i++)  {
-               lptr = &btree_curs->level[i];
-
-               agbno = get_next_blockaddr(agno, i, btree_curs);
-               error = -libxfs_buf_get(mp->m_dev,
-                               XFS_AGB_TO_DADDR(mp, agno, agbno),
-                               XFS_FSB_TO_BB(mp, 1), &lptr->buf_p);
-               if (error)
-                       do_error(_("Cannot grab rmapbt buffer, err=%d"),
-                                       error);
-
-               if (i == btree_curs->num_levels - 1)
-                       btree_curs->root = agbno;
-
-               lptr->agbno = agbno;
-               lptr->prev_agbno = NULLAGBLOCK;
-               lptr->prev_buf_p = NULL;
-               /*
-                * initialize block header
-                */
-
-               lptr->buf_p->b_ops = ops;
-               bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p);
-               memset(bt_hdr, 0, mp->m_sb.sb_blocksize);
-               libxfs_btree_init_block(mp, lptr->buf_p, XFS_BTNUM_RMAP,
-                                       i, 0, agno);
-       }
-
-       /*
-        * run along leaf, setting up records.  as we have to switch
-        * blocks, call the prop_rmap_cursor routine to set up the new
-        * pointers for the parent.  that can recurse up to the root
-        * if required.  set the sibling pointers for leaf level here.
-        */
-       error = rmap_init_cursor(agno, &rmap_cur);
-       if (error)
-               do_error(
-_("Insufficient memory to construct reverse-map cursor."));
-       rm_rec = pop_slab_cursor(rmap_cur);
-       lptr = &btree_curs->level[0];
-
-       for (i = 0; i < lptr->num_blocks; i++)  {
-               numrecs = lptr->num_recs_pb + (lptr->modulo > 0);
-               ASSERT(rm_rec != NULL || numrecs == 0);
-
-               /*
-                * block initialization, lay in block header
-                */
-               lptr->buf_p->b_ops = ops;
-               bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p);
-               memset(bt_hdr, 0, mp->m_sb.sb_blocksize);
-               libxfs_btree_init_block(mp, lptr->buf_p, XFS_BTNUM_RMAP,
-                                       0, 0, agno);
-
-               bt_hdr->bb_u.s.bb_leftsib = cpu_to_be32(lptr->prev_agbno);
-               bt_hdr->bb_numrecs = cpu_to_be16(numrecs);
-
-               if (lptr->modulo > 0)
-                       lptr->modulo--;
-
-               if (lptr->num_recs_pb > 0) {
-                       ASSERT(rm_rec != NULL);
-                       prop_rmap_cursor(mp, agno, btree_curs, rm_rec, 0);
-               }
-
-               bt_rec = (struct xfs_rmap_rec *)
-                         ((char *)bt_hdr + XFS_RMAP_BLOCK_LEN);
-               highest_key.rm_startblock = 0;
-               highest_key.rm_owner = 0;
-               highest_key.rm_offset = 0;
-               for (j = 0; j < be16_to_cpu(bt_hdr->bb_numrecs); j++) {
-                       ASSERT(rm_rec != NULL);
-                       bt_rec[j].rm_startblock =
-                                       cpu_to_be32(rm_rec->rm_startblock);
-                       bt_rec[j].rm_blockcount =
-                                       cpu_to_be32(rm_rec->rm_blockcount);
-                       bt_rec[j].rm_owner = cpu_to_be64(rm_rec->rm_owner);
-                       bt_rec[j].rm_offset = cpu_to_be64(
-                                       libxfs_rmap_irec_offset_pack(rm_rec));
-                       rmap_high_key_from_rec(rm_rec, &hi_key);
-                       if (rmap_diffkeys(&hi_key, &highest_key) > 0)
-                               highest_key = hi_key;
-
-                       rm_rec = pop_slab_cursor(rmap_cur);
-               }
-
-               /* Now go set the parent key */
-               prop_rmap_highkey(mp, agno, btree_curs, &highest_key);
-
-               if (rm_rec != NULL)  {
-                       /*
-                        * get next leaf level block
-                        */
-                       if (lptr->prev_buf_p != NULL)  {
-#ifdef XR_BLD_RL_TRACE
-                               fprintf(stderr, "writing rmapbt agbno %u\n",
-                                       lptr->prev_agbno);
-#endif
-                               ASSERT(lptr->prev_agbno != NULLAGBLOCK);
-                               libxfs_buf_mark_dirty(lptr->prev_buf_p);
-                               libxfs_buf_relse(lptr->prev_buf_p);
-                       }
-                       lptr->prev_buf_p = lptr->buf_p;
-                       lptr->prev_agbno = lptr->agbno;
-                       lptr->agbno = get_next_blockaddr(agno, 0, btree_curs);
-                       bt_hdr->bb_u.s.bb_rightsib = cpu_to_be32(lptr->agbno);
-
-                       error = -libxfs_buf_get(mp->m_dev,
-                                       XFS_AGB_TO_DADDR(mp, agno, lptr->agbno),
-                                       XFS_FSB_TO_BB(mp, 1),
-                                       &lptr->buf_p);
-                       if (error)
-                               do_error(
-       _("Cannot grab rmapbt buffer, err=%d"),
-                                               error);
-               }
-       }
-       free_slab_cursor(&rmap_cur);
-}
-
 /* rebuild the refcount tree */
 
 /*
@@ -1155,7 +758,7 @@ build_agf_agfl(
        xfs_agnumber_t          agno,
        struct bt_rebuild       *btr_bno,
        struct bt_rebuild       *btr_cnt,
-       struct bt_status        *rmap_bt,
+       struct bt_rebuild       *btr_rmap,
        struct bt_status        *refcnt_bt,
        struct xfs_slab         *lost_fsb)
 {
@@ -1203,11 +806,17 @@ build_agf_agfl(
                        cpu_to_be32(btr_cnt->newbt.afake.af_root);
        agf->agf_levels[XFS_BTNUM_CNT] =
                        cpu_to_be32(btr_cnt->newbt.afake.af_levels);
-       agf->agf_roots[XFS_BTNUM_RMAP] = cpu_to_be32(rmap_bt->root);
-       agf->agf_levels[XFS_BTNUM_RMAP] = cpu_to_be32(rmap_bt->num_levels);
        agf->agf_freeblks = cpu_to_be32(btr_bno->freeblks);
-       agf->agf_rmap_blocks = cpu_to_be32(rmap_bt->num_tot_blocks -
-                       rmap_bt->num_free_blocks);
+
+       if (xfs_sb_version_hasrmapbt(&mp->m_sb)) {
+               agf->agf_roots[XFS_BTNUM_RMAP] =
+                               cpu_to_be32(btr_rmap->newbt.afake.af_root);
+               agf->agf_levels[XFS_BTNUM_RMAP] =
+                               cpu_to_be32(btr_rmap->newbt.afake.af_levels);
+               agf->agf_rmap_blocks =
+                               cpu_to_be32(btr_rmap->newbt.afake.af_blocks);
+       }
+
        agf->agf_refcount_root = cpu_to_be32(refcnt_bt->root);
        agf->agf_refcount_level = cpu_to_be32(refcnt_bt->num_levels);
        agf->agf_refcount_blocks = cpu_to_be32(refcnt_bt->num_tot_blocks -
@@ -1225,7 +834,7 @@ build_agf_agfl(
                blks = btr_bno->newbt.afake.af_blocks +
                        btr_cnt->newbt.afake.af_blocks - 2;
                if (xfs_sb_version_hasrmapbt(&mp->m_sb))
-                       blks += rmap_bt->num_tot_blocks - rmap_bt->num_free_blocks - 1;
+                       blks += btr_rmap->newbt.afake.af_blocks - 1;
                agf->agf_btreeblks = cpu_to_be32(blks);
 #ifdef XR_BLD_FREE_TRACE
                fprintf(stderr, "agf->agf_btreeblks = %u\n",
@@ -1270,6 +879,8 @@ build_agf_agfl(
        freelist = xfs_buf_to_agfl_bno(agfl_buf);
        fill_agfl(btr_bno, freelist, &agfl_idx);
        fill_agfl(btr_cnt, freelist, &agfl_idx);
+       if (xfs_sb_version_hasrmapbt(&mp->m_sb))
+               fill_agfl(btr_rmap, freelist, &agfl_idx);
 
        /* Set the AGF counters for the AGFL. */
        if (agfl_idx > 0) {
@@ -1369,7 +980,7 @@ phase5_func(
        struct bt_rebuild       btr_cnt;
        struct bt_rebuild       btr_ino;
        struct bt_rebuild       btr_fino;
-       bt_status_t             rmap_btree_curs;
+       struct bt_rebuild       btr_rmap;
        bt_status_t             refcnt_btree_curs;
        int                     extra_blocks = 0;
        uint                    num_freeblocks;
@@ -1404,11 +1015,7 @@ _("unable to rebuild AG %u.  Not enough free space in on-disk AG.\n"),
        init_ino_cursors(&sc, agno, num_freeblocks, &sb_icount_ag[agno],
                        &sb_ifree_ag[agno], &btr_ino, &btr_fino);
 
-       /*
-        * Set up the btree cursors for the on-disk rmap btrees, which includes
-        * pre-allocating all required blocks.
-        */
-       init_rmapbt_cursor(mp, agno, &rmap_btree_curs);
+       init_rmapbt_cursor(&sc, agno, num_freeblocks, &btr_rmap);
 
        /*
         * Set up the btree cursors for the on-disk refcount btrees,
@@ -1474,10 +1081,8 @@ _("unable to rebuild AG %u.  Not enough free space in on-disk AG.\n"),
        ASSERT(btr_bno.freeblks == btr_cnt.freeblks);
 
        if (xfs_sb_version_hasrmapbt(&mp->m_sb)) {
-               build_rmap_tree(mp, agno, &rmap_btree_curs);
-               write_cursor(&rmap_btree_curs);
-               sb_fdblocks_ag[agno] += (rmap_btree_curs.num_tot_blocks -
-                               rmap_btree_curs.num_free_blocks) - 1;
+               build_rmap_tree(&sc, agno, &btr_rmap);
+               sb_fdblocks_ag[agno] += btr_rmap.newbt.afake.af_blocks - 1;
        }
 
        if (xfs_sb_version_hasreflink(&mp->m_sb)) {
@@ -1488,7 +1093,7 @@ _("unable to rebuild AG %u.  Not enough free space in on-disk AG.\n"),
        /*
         * set up agf and agfl
         */
-       build_agf_agfl(mp, agno, &btr_bno, &btr_cnt, &rmap_btree_curs,
+       build_agf_agfl(mp, agno, &btr_bno, &btr_cnt, &btr_rmap,
                        &refcnt_btree_curs, lost_fsb);
 
        build_inode_btrees(&sc, agno, &btr_ino, &btr_fino);
@@ -1505,7 +1110,7 @@ _("unable to rebuild AG %u.  Not enough free space in on-disk AG.\n"),
        if (xfs_sb_version_hasfinobt(&mp->m_sb))
                finish_rebuild(mp, &btr_fino, lost_fsb);
        if (xfs_sb_version_hasrmapbt(&mp->m_sb))
-               finish_cursor(&rmap_btree_curs);
+               finish_rebuild(mp, &btr_rmap, lost_fsb);
        if (xfs_sb_version_hasreflink(&mp->m_sb))
                finish_cursor(&refcnt_btree_curs);