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 638657a91335e4c0dc19c71244400ef680cb06e6..e56991d1a9709b6637ba252abf200c53b5f6dce6 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 1f88e1ce770f35442f0161466632c68fe0e46153..a6779b3e873c3d9304563ff1608ac43dce351bcd 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 2e874be702093f1409fb7428efc5a1bdbc0e3bcd..785a996821591c89e9a74cea413789225c7ba890 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 e3c0af73cf94092440923a9cb3392a8b80d6bccf..4b1e408169a83de0c03825a8167bc8a678dd7124 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);
 }
 
 /*