]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs: refactor btree maxlevels computation
authorDarrick J. Wong <darrick.wong@oracle.com>
Wed, 10 Aug 2016 01:29:36 +0000 (11:29 +1000)
committerDave Chinner <david@fromorbit.com>
Wed, 10 Aug 2016 01:29:36 +0000 (11:29 +1000)
Source kernel commit: 19b54ee66c4c5de8f8db74d5914d9a97161460bf

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>
libxfs/xfs_alloc.c
libxfs/xfs_btree.c
libxfs/xfs_btree.h
libxfs/xfs_ialloc.c

index 38287a9c8a0591754945f539d17603cac5f01af7..8814763af3e9448a6db82ed58510d6d439005fbe 100644 (file)
@@ -1835,19 +1835,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 a736cb5d09df91ccec4c583a61eac5c9eb16ab3f..18fb165775d603992863e3ac0be141a77f198d3b 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 9a888398b9bd9077d82904c22735e397bf3c4170..618c7e01d3c43ea6835ff27738c6c4d4e0dab08d 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 b06407213b585a09a015c609bc397707e4572285..4db42a694d7c37a6f96752f7123d76d08706e2c7 100644 (file)
@@ -2389,20 +2389,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);
 }
 
 /*