xfs: use the actual AG length when reserving blocks
commit 20e73b000b
upstream.
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>
Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
d9c7c9fa60
commit
b96e4e87d2
|
@ -256,6 +256,9 @@ xfs_ag_resv_init(
|
||||||
goto out;
|
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:
|
out:
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
|
@ -408,13 +408,14 @@ xfs_refcountbt_calc_size(
|
||||||
*/
|
*/
|
||||||
xfs_extlen_t
|
xfs_extlen_t
|
||||||
xfs_refcountbt_max_size(
|
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. */
|
/* Bail out if we're uninitialized, which can happen in mkfs. */
|
||||||
if (mp->m_refc_mxr[0] == 0)
|
if (mp->m_refc_mxr[0] == 0)
|
||||||
return 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_buf *agbp;
|
||||||
struct xfs_agf *agf;
|
struct xfs_agf *agf;
|
||||||
|
xfs_agblock_t agblocks;
|
||||||
xfs_extlen_t tree_len;
|
xfs_extlen_t tree_len;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (!xfs_sb_version_hasreflink(&mp->m_sb))
|
if (!xfs_sb_version_hasreflink(&mp->m_sb))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
*ask += xfs_refcountbt_max_size(mp);
|
|
||||||
|
|
||||||
error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp);
|
error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
agf = XFS_BUF_TO_AGF(agbp);
|
agf = XFS_BUF_TO_AGF(agbp);
|
||||||
|
agblocks = be32_to_cpu(agf->agf_length);
|
||||||
tree_len = be32_to_cpu(agf->agf_refcount_blocks);
|
tree_len = be32_to_cpu(agf->agf_refcount_blocks);
|
||||||
xfs_buf_relse(agbp);
|
xfs_buf_relse(agbp);
|
||||||
|
|
||||||
|
*ask += xfs_refcountbt_max_size(mp, agblocks);
|
||||||
*used += tree_len;
|
*used += tree_len;
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
|
|
|
@ -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,
|
extern xfs_extlen_t xfs_refcountbt_calc_size(struct xfs_mount *mp,
|
||||||
unsigned long long len);
|
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,
|
extern int xfs_refcountbt_calc_reserves(struct xfs_mount *mp,
|
||||||
xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used);
|
xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used);
|
||||||
|
|
|
@ -549,13 +549,14 @@ xfs_rmapbt_calc_size(
|
||||||
*/
|
*/
|
||||||
xfs_extlen_t
|
xfs_extlen_t
|
||||||
xfs_rmapbt_max_size(
|
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. */
|
/* Bail out if we're uninitialized, which can happen in mkfs. */
|
||||||
if (mp->m_rmap_mxr[0] == 0)
|
if (mp->m_rmap_mxr[0] == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return xfs_rmapbt_calc_size(mp, mp->m_sb.sb_agblocks);
|
return xfs_rmapbt_calc_size(mp, agblocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -570,25 +571,24 @@ xfs_rmapbt_calc_reserves(
|
||||||
{
|
{
|
||||||
struct xfs_buf *agbp;
|
struct xfs_buf *agbp;
|
||||||
struct xfs_agf *agf;
|
struct xfs_agf *agf;
|
||||||
xfs_extlen_t pool_len;
|
xfs_agblock_t agblocks;
|
||||||
xfs_extlen_t tree_len;
|
xfs_extlen_t tree_len;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
|
if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
|
||||||
return 0;
|
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);
|
error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
agf = XFS_BUF_TO_AGF(agbp);
|
agf = XFS_BUF_TO_AGF(agbp);
|
||||||
|
agblocks = be32_to_cpu(agf->agf_length);
|
||||||
tree_len = be32_to_cpu(agf->agf_rmap_blocks);
|
tree_len = be32_to_cpu(agf->agf_rmap_blocks);
|
||||||
xfs_buf_relse(agbp);
|
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;
|
*used += tree_len;
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
|
|
|
@ -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,
|
extern xfs_extlen_t xfs_rmapbt_calc_size(struct xfs_mount *mp,
|
||||||
unsigned long long len);
|
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,
|
extern int xfs_rmapbt_calc_reserves(struct xfs_mount *mp,
|
||||||
xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used);
|
xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used);
|
||||||
|
|
|
@ -631,6 +631,20 @@ xfs_growfs_data_private(
|
||||||
xfs_set_low_space_thresholds(mp);
|
xfs_set_low_space_thresholds(mp);
|
||||||
mp->m_alloc_set_aside = xfs_alloc_set_aside(mp);
|
mp->m_alloc_set_aside = xfs_alloc_set_aside(mp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we expanded the last AG, free the per-AG reservation
|
||||||
|
* so we can reinitialize it with the new size.
|
||||||
|
*/
|
||||||
|
if (new) {
|
||||||
|
struct xfs_perag *pag;
|
||||||
|
|
||||||
|
pag = xfs_perag_get(mp, agno);
|
||||||
|
error = xfs_ag_resv_free(pag);
|
||||||
|
xfs_perag_put(pag);
|
||||||
|
if (error)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* Reserve AG metadata blocks. */
|
/* Reserve AG metadata blocks. */
|
||||||
error = xfs_fs_reserve_ag_blocks(mp);
|
error = xfs_fs_reserve_ag_blocks(mp);
|
||||||
if (error && error != -ENOSPC)
|
if (error && error != -ENOSPC)
|
||||||
|
|
Loading…
Reference in a new issue