From: Darrick J. Wong <djwong@xxxxxxxxxx> To support future btree code, we need to be able to size btree cursors dynamically for very large btrees. Switch the maxlevels computation to use the precomputed values in the superblock, and create cursors that can handle a certain height. For now, we retain the btree cursor zone that can handle up to 9-level btrees, and create larger cursors (which shouldn't happen currently) from the heap as a failsafe. Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> --- fs/xfs/libxfs/xfs_btree.c | 40 +++++++++++++++++++++++++++++++++++++--- fs/xfs/libxfs/xfs_btree.h | 6 ++++++ fs/xfs/xfs_super.c | 4 ++-- 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c index 0c86209a54df..361063804af7 100644 --- a/fs/xfs/libxfs/xfs_btree.c +++ b/fs/xfs/libxfs/xfs_btree.c @@ -379,7 +379,10 @@ xfs_btree_del_cursor( kmem_free(cur->bc_ops); if (!(cur->bc_flags & XFS_BTREE_LONG_PTRS) && cur->bc_ag.pag) xfs_perag_put(cur->bc_ag.pag); - kmem_cache_free(xfs_btree_cur_zone, cur); + if (cur->bc_maxlevels > XFS_BTREE_CUR_ZONE_MAXLEVELS) + kmem_free(cur); + else + kmem_cache_free(xfs_btree_cur_zone, cur); } /* @@ -4931,6 +4934,32 @@ xfs_btree_has_more_records( return block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK); } +/* Compute the maximum allowed height for a given btree type. */ +static unsigned int +xfs_btree_maxlevels( + struct xfs_mount *mp, + xfs_btnum_t btnum) +{ + switch (btnum) { + case XFS_BTNUM_BNO: + case XFS_BTNUM_CNT: + return mp->m_ag_maxlevels; + case XFS_BTNUM_BMAP: + return max(mp->m_bm_maxlevels[XFS_DATA_FORK], + mp->m_bm_maxlevels[XFS_ATTR_FORK]); + case XFS_BTNUM_INO: + case XFS_BTNUM_FINO: + return M_IGEO(mp)->inobt_maxlevels; + case XFS_BTNUM_RMAP: + return mp->m_rmap_maxlevels; + case XFS_BTNUM_REFC: + return mp->m_refc_maxlevels; + default: + ASSERT(0); + return XFS_BTREE_MAXLEVELS; + } +} + /* Allocate a new btree cursor of the appropriate size. */ struct xfs_btree_cur * xfs_btree_alloc_cursor( @@ -4939,13 +4968,18 @@ xfs_btree_alloc_cursor( xfs_btnum_t btnum) { struct xfs_btree_cur *cur; + unsigned int maxlevels = xfs_btree_maxlevels(mp, btnum); - cur = kmem_cache_zalloc(xfs_btree_cur_zone, GFP_NOFS | __GFP_NOFAIL); + if (maxlevels > XFS_BTREE_CUR_ZONE_MAXLEVELS) + cur = kmem_zalloc(xfs_btree_cur_sizeof(maxlevels), KM_NOFS); + else + cur = kmem_cache_zalloc(xfs_btree_cur_zone, + GFP_NOFS | __GFP_NOFAIL); cur->bc_tp = tp; cur->bc_mp = mp; cur->bc_btnum = btnum; cur->bc_blocklog = mp->m_sb.sb_blocklog; - cur->bc_maxlevels = XFS_BTREE_MAXLEVELS; + cur->bc_maxlevels = maxlevels; return cur; } diff --git a/fs/xfs/libxfs/xfs_btree.h b/fs/xfs/libxfs/xfs_btree.h index 3b396edd1a4f..c9e60c1e1212 100644 --- a/fs/xfs/libxfs/xfs_btree.h +++ b/fs/xfs/libxfs/xfs_btree.h @@ -94,6 +94,12 @@ uint32_t xfs_btree_magic(int crc, xfs_btnum_t btnum); #define XFS_BTREE_MAXLEVELS 9 /* max of all btrees */ +/* + * The btree cursor zone hands out cursors that can handle up to this many + * levels. This is the known maximum for all btree types. + */ +#define XFS_BTREE_CUR_ZONE_MAXLEVELS (9) + struct xfs_btree_ops { /* size of the key and record structures */ size_t key_len; diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 30bae0657343..90c92a6a49e0 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -1966,8 +1966,8 @@ xfs_init_zones(void) goto out_destroy_log_ticket_zone; xfs_btree_cur_zone = kmem_cache_create("xfs_btree_cur", - xfs_btree_cur_sizeof(XFS_BTREE_MAXLEVELS), - 0, 0, NULL); + xfs_btree_cur_sizeof(XFS_BTREE_CUR_ZONE_MAXLEVELS), + 0, 0, NULL); if (!xfs_btree_cur_zone) goto out_destroy_bmap_free_item_zone;