Skip to content

Commit

Permalink
xfs: refactor btree maxlevels computation
Browse files Browse the repository at this point in the history
Create a common function to calculate the maximum height of a per-AG
btree.  This will eventually be used by the rmapbt and refcountbt
code to calculate appropriate maxlevels values for each.  This is
important because the verifiers and the transaction block
reservations depend on accurate estimates of how many blocks are
needed to satisfy a btree split.

We were mistakenly using the max bnobt height for all the btrees,
which creates a dangerous situation since the larger records and
keys in an rmapbt make it very possible that the rmapbt will be
taller than the bnobt and so we can run out of transaction block
reservation.

Signed-off-by: Darrick J. Wong <[email protected]>
Reviewed-by: Brian Foster <[email protected]>
Signed-off-by: Dave Chinner <[email protected]>
  • Loading branch information
djwong authored and dchinner committed Jun 21, 2016
1 parent e66a4c6 commit 19b54ee
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 27 deletions.
15 changes: 2 additions & 13 deletions fs/xfs/libxfs/xfs_alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1839,19 +1839,8 @@ void
xfs_alloc_compute_maxlevels(
xfs_mount_t *mp) /* file system mount structure */
{
int level;
uint maxblocks;
uint maxleafents;
int minleafrecs;
int minnoderecs;

maxleafents = (mp->m_sb.sb_agblocks + 1) / 2;
minleafrecs = mp->m_alloc_mnr[0];
minnoderecs = mp->m_alloc_mnr[1];
maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs;
for (level = 1; maxblocks > 1; level++)
maxblocks = (maxblocks + minnoderecs - 1) / minnoderecs;
mp->m_ag_maxlevels = level;
mp->m_ag_maxlevels = xfs_btree_compute_maxlevels(mp, mp->m_alloc_mnr,
(mp->m_sb.sb_agblocks + 1) / 2);
}

/*
Expand Down
19 changes: 19 additions & 0 deletions fs/xfs/libxfs/xfs_btree.c
Original file line number Diff line number Diff line change
Expand Up @@ -4152,3 +4152,22 @@ xfs_btree_sblock_verify(

return true;
}

/*
* Calculate the number of btree levels needed to store a given number of
* records in a short-format btree.
*/
uint
xfs_btree_compute_maxlevels(
struct xfs_mount *mp,
uint *limits,
unsigned long len)
{
uint level;
unsigned long maxblocks;

maxblocks = (len + limits[0] - 1) / limits[0];
for (level = 1; maxblocks > 1; level++)
maxblocks = (maxblocks + limits[1] - 1) / limits[1];
return level;
}
2 changes: 2 additions & 0 deletions fs/xfs/libxfs/xfs_btree.h
Original file line number Diff line number Diff line change
Expand Up @@ -474,5 +474,7 @@ static inline int xfs_btree_get_level(struct xfs_btree_block *block)

bool xfs_btree_sblock_v5hdr_verify(struct xfs_buf *bp);
bool xfs_btree_sblock_verify(struct xfs_buf *bp, unsigned int max_recs);
uint xfs_btree_compute_maxlevels(struct xfs_mount *mp, uint *limits,
unsigned long len);

#endif /* __XFS_BTREE_H__ */
19 changes: 5 additions & 14 deletions fs/xfs/libxfs/xfs_ialloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -2394,20 +2394,11 @@ void
xfs_ialloc_compute_maxlevels(
xfs_mount_t *mp) /* file system mount structure */
{
int level;
uint maxblocks;
uint maxleafents;
int minleafrecs;
int minnoderecs;

maxleafents = (1LL << XFS_INO_AGINO_BITS(mp)) >>
XFS_INODES_PER_CHUNK_LOG;
minleafrecs = mp->m_inobt_mnr[0];
minnoderecs = mp->m_inobt_mnr[1];
maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs;
for (level = 1; maxblocks > 1; level++)
maxblocks = (maxblocks + minnoderecs - 1) / minnoderecs;
mp->m_in_maxlevels = level;
uint inodes;

inodes = (1LL << XFS_INO_AGINO_BITS(mp)) >> XFS_INODES_PER_CHUNK_LOG;
mp->m_in_maxlevels = xfs_btree_compute_maxlevels(mp, mp->m_inobt_mnr,
inodes);
}

/*
Expand Down

0 comments on commit 19b54ee

Please sign in to comment.