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(
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 */
/*
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)
{
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 -
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",
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) {
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;
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,
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)) {
/*
* 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);
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);