]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs: use the actual AG length when reserving blocks
authorDarrick J. Wong <darrick.wong@oracle.com>
Wed, 11 Jan 2017 02:06:43 +0000 (20:06 -0600)
committerEric Sandeen <sandeen@redhat.com>
Wed, 11 Jan 2017 02:06:43 +0000 (20:06 -0600)
Source kernel commit: 20e73b000bcded44a91b79429d8fa743247602ad

We need to use the actual AG length when making per-AG reservations,
since we could otherwise end up reserving more blocks out of the last
AG than there are actual blocks.

Complained-about-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
libxfs/xfs_ag_resv.c
libxfs/xfs_refcount_btree.c
libxfs/xfs_refcount_btree.h
libxfs/xfs_rmap_btree.c
libxfs/xfs_rmap_btree.h

index 57f01a74b8ac34df3abf136078f79ab63e131266..3b82fcd862afe36b3a1b3f7475eeeffee81347bb 100644 (file)
@@ -255,6 +255,9 @@ xfs_ag_resv_init(
                        goto out;
        }
 
+       ASSERT(xfs_perag_resv(pag, XFS_AG_RESV_METADATA)->ar_reserved +
+              xfs_perag_resv(pag, XFS_AG_RESV_AGFL)->ar_reserved <=
+              pag->pagf_freeblks + pag->pagf_flcount);
 out:
        return error;
 }
index 7c066257b6c6f972fa981fa8c3a4ba0dc72558ba..2814f94f7ce6bde4d75ab961178ffafff903cd51 100644 (file)
@@ -408,13 +408,14 @@ xfs_refcountbt_calc_size(
  */
 xfs_extlen_t
 xfs_refcountbt_max_size(
-       struct xfs_mount        *mp)
+       struct xfs_mount        *mp,
+       xfs_agblock_t           agblocks)
 {
        /* Bail out if we're uninitialized, which can happen in mkfs. */
        if (mp->m_refc_mxr[0] == 0)
                return 0;
 
-       return xfs_refcountbt_calc_size(mp, mp->m_sb.sb_agblocks);
+       return xfs_refcountbt_calc_size(mp, agblocks);
 }
 
 /*
@@ -429,22 +430,24 @@ xfs_refcountbt_calc_reserves(
 {
        struct xfs_buf          *agbp;
        struct xfs_agf          *agf;
+       xfs_agblock_t           agblocks;
        xfs_extlen_t            tree_len;
        int                     error;
 
        if (!xfs_sb_version_hasreflink(&mp->m_sb))
                return 0;
 
-       *ask += xfs_refcountbt_max_size(mp);
 
        error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp);
        if (error)
                return error;
 
        agf = XFS_BUF_TO_AGF(agbp);
+       agblocks = be32_to_cpu(agf->agf_length);
        tree_len = be32_to_cpu(agf->agf_refcount_blocks);
        xfs_buf_relse(agbp);
 
+       *ask += xfs_refcountbt_max_size(mp, agblocks);
        *used += tree_len;
 
        return error;
index 3be7768bd51a1c0ebd8c2ccc6e930a730bd39b54..9db008b955b7ed68bb62d8654073da0302668171 100644 (file)
@@ -66,7 +66,8 @@ extern void xfs_refcountbt_compute_maxlevels(struct xfs_mount *mp);
 
 extern xfs_extlen_t xfs_refcountbt_calc_size(struct xfs_mount *mp,
                unsigned long long len);
-extern xfs_extlen_t xfs_refcountbt_max_size(struct xfs_mount *mp);
+extern xfs_extlen_t xfs_refcountbt_max_size(struct xfs_mount *mp,
+               xfs_agblock_t agblocks);
 
 extern int xfs_refcountbt_calc_reserves(struct xfs_mount *mp,
                xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used);
index 30ddcda4e9a86fcc24b98451e625cee545e83d62..a186c872eac6aece65362cb2ef3cbdc48d2cb3b5 100644 (file)
@@ -548,13 +548,14 @@ xfs_rmapbt_calc_size(
  */
 xfs_extlen_t
 xfs_rmapbt_max_size(
-       struct xfs_mount        *mp)
+       struct xfs_mount        *mp,
+       xfs_agblock_t           agblocks)
 {
        /* Bail out if we're uninitialized, which can happen in mkfs. */
        if (mp->m_rmap_mxr[0] == 0)
                return 0;
 
-       return xfs_rmapbt_calc_size(mp, mp->m_sb.sb_agblocks);
+       return xfs_rmapbt_calc_size(mp, agblocks);
 }
 
 /*
@@ -569,25 +570,24 @@ xfs_rmapbt_calc_reserves(
 {
        struct xfs_buf          *agbp;
        struct xfs_agf          *agf;
-       xfs_extlen_t            pool_len;
+       xfs_agblock_t           agblocks;
        xfs_extlen_t            tree_len;
        int                     error;
 
        if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
                return 0;
 
-       /* Reserve 1% of the AG or enough for 1 block per record. */
-       pool_len = max(mp->m_sb.sb_agblocks / 100, xfs_rmapbt_max_size(mp));
-       *ask += pool_len;
-
        error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp);
        if (error)
                return error;
 
        agf = XFS_BUF_TO_AGF(agbp);
+       agblocks = be32_to_cpu(agf->agf_length);
        tree_len = be32_to_cpu(agf->agf_rmap_blocks);
        xfs_buf_relse(agbp);
 
+       /* Reserve 1% of the AG or enough for 1 block per record. */
+       *ask += max(agblocks / 100, xfs_rmapbt_max_size(mp, agblocks));
        *used += tree_len;
 
        return error;
index f3137a3118532595c883c0c434e399dbdb8f5a77..6b8edcf2ca16eda1384a02c0639c88a43eb90579 100644 (file)
@@ -60,7 +60,8 @@ extern void xfs_rmapbt_compute_maxlevels(struct xfs_mount *mp);
 
 extern xfs_extlen_t xfs_rmapbt_calc_size(struct xfs_mount *mp,
                unsigned long long len);
-extern xfs_extlen_t xfs_rmapbt_max_size(struct xfs_mount *mp);
+extern xfs_extlen_t xfs_rmapbt_max_size(struct xfs_mount *mp,
+               xfs_agblock_t agblocks);
 
 extern int xfs_rmapbt_calc_reserves(struct xfs_mount *mp,
                xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used);