xfs: refactor btree maxlevels computation
authorDarrick J. Wong <darrick.wong@oracle.com>
Tue, 21 Jun 2016 01:53:28 +0000 (11:53 +1000)
committerDave Chinner <david@fromorbit.com>
Tue, 21 Jun 2016 01:53:28 +0000 (11:53 +1000)
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 <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
fs/xfs/libxfs/xfs_alloc.c
fs/xfs/libxfs/xfs_btree.c
fs/xfs/libxfs/xfs_btree.h
fs/xfs/libxfs/xfs_ialloc.c

index 638657a..e56991d 100644 (file)
@@ -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);
 }
 
 /*
index 1f88e1c..a6779b3 100644 (file)
@@ -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;
+}
index 2e874be..785a996 100644 (file)
@@ -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__ */
index e3c0af7..4b1e408 100644 (file)
@@ -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);
 }
 
 /*