Skip to content

Commit

Permalink
xfs: use the actual AG length when reserving blocks
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Darrick J. Wong <[email protected]>
Reviewed-by: Christoph Hellwig <[email protected]>
  • Loading branch information
djwong committed Jan 4, 2017
1 parent 7a21272 commit 20e73b0
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 12 deletions.
3 changes: 3 additions & 0 deletions fs/xfs/libxfs/xfs_ag_resv.c
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,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;
}
Expand Down
9 changes: 6 additions & 3 deletions fs/xfs/libxfs/xfs_refcount_btree.c
Original file line number Diff line number Diff line change
Expand Up @@ -409,13 +409,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);
}

/*
Expand All @@ -430,22 +431,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;
Expand Down
3 changes: 2 additions & 1 deletion fs/xfs/libxfs/xfs_refcount_btree.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
14 changes: 7 additions & 7 deletions fs/xfs/libxfs/xfs_rmap_btree.c
Original file line number Diff line number Diff line change
Expand Up @@ -550,13 +550,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);
}

/*
Expand All @@ -571,25 +572,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;
Expand Down
3 changes: 2 additions & 1 deletion fs/xfs/libxfs/xfs_rmap_btree.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
14 changes: 14 additions & 0 deletions fs/xfs/xfs_fsops.c
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,20 @@ xfs_growfs_data_private(
xfs_set_low_space_thresholds(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. */
error = xfs_fs_reserve_ag_blocks(mp);
if (error && error != -ENOSPC)
Expand Down

0 comments on commit 20e73b0

Please sign in to comment.