xfs: xfs_alloc_fix_freelist() can use incore perag structures
At the moment, xfs_alloc_fix_freelist() uses a mix of per-ag based access and agf buffer based access to freelist and space usage information. However, once the AGF buffer is locked inside this function, it is guaranteed that both the in-memory and on-disk values are identical. xfs_alloc_fix_freelist() doesn't modify the values in the structures directly, so it is a read-only user of the infomration, and hence can use the per-ag structure exclusively for determining what it should do. This opens up an avenue for cleaning up a lot of duplicated logic whose only difference is the structure it gets the data from, and in doing so removes a lot of needless byte swapping overhead when fixing up the free list. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Brian Foster <bfoster@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
This commit is contained in:
parent
5ebe6afaf0
commit
50adbcb4c4
4 changed files with 37 additions and 46 deletions
|
@ -1825,11 +1825,11 @@ xfs_alloc_compute_maxlevels(
|
||||||
xfs_extlen_t
|
xfs_extlen_t
|
||||||
xfs_alloc_longest_free_extent(
|
xfs_alloc_longest_free_extent(
|
||||||
struct xfs_mount *mp,
|
struct xfs_mount *mp,
|
||||||
struct xfs_perag *pag)
|
struct xfs_perag *pag,
|
||||||
|
xfs_extlen_t need)
|
||||||
{
|
{
|
||||||
xfs_extlen_t need, delta = 0;
|
xfs_extlen_t delta = 0;
|
||||||
|
|
||||||
need = XFS_MIN_FREELIST_PAG(pag, mp);
|
|
||||||
if (need > pag->pagf_flcount)
|
if (need > pag->pagf_flcount)
|
||||||
delta = need - pag->pagf_flcount;
|
delta = need - pag->pagf_flcount;
|
||||||
|
|
||||||
|
@ -1848,10 +1848,8 @@ xfs_alloc_fix_freelist(
|
||||||
int flags) /* XFS_ALLOC_FLAG_... */
|
int flags) /* XFS_ALLOC_FLAG_... */
|
||||||
{
|
{
|
||||||
xfs_buf_t *agbp; /* agf buffer pointer */
|
xfs_buf_t *agbp; /* agf buffer pointer */
|
||||||
xfs_agf_t *agf; /* a.g. freespace structure pointer */
|
|
||||||
xfs_buf_t *agflbp;/* agfl buffer pointer */
|
xfs_buf_t *agflbp;/* agfl buffer pointer */
|
||||||
xfs_agblock_t bno; /* freelist block */
|
xfs_agblock_t bno; /* freelist block */
|
||||||
xfs_extlen_t delta; /* new blocks needed in freelist */
|
|
||||||
int error; /* error result code */
|
int error; /* error result code */
|
||||||
xfs_extlen_t longest;/* longest extent in allocation group */
|
xfs_extlen_t longest;/* longest extent in allocation group */
|
||||||
xfs_mount_t *mp; /* file system mount point structure */
|
xfs_mount_t *mp; /* file system mount point structure */
|
||||||
|
@ -1895,7 +1893,7 @@ xfs_alloc_fix_freelist(
|
||||||
* total blocks, reject it.
|
* total blocks, reject it.
|
||||||
*/
|
*/
|
||||||
need = XFS_MIN_FREELIST_PAG(pag, mp);
|
need = XFS_MIN_FREELIST_PAG(pag, mp);
|
||||||
longest = xfs_alloc_longest_free_extent(mp, pag);
|
longest = xfs_alloc_longest_free_extent(mp, pag, need);
|
||||||
if ((args->minlen + args->alignment + args->minalignslop - 1) >
|
if ((args->minlen + args->alignment + args->minalignslop - 1) >
|
||||||
longest ||
|
longest ||
|
||||||
((int)(pag->pagf_freeblks + pag->pagf_flcount -
|
((int)(pag->pagf_freeblks + pag->pagf_flcount -
|
||||||
|
@ -1922,25 +1920,16 @@ xfs_alloc_fix_freelist(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
* Figure out how many blocks we should have in the freelist.
|
|
||||||
*/
|
/* If there isn't enough total space or single-extent, reject it. */
|
||||||
agf = XFS_BUF_TO_AGF(agbp);
|
need = XFS_MIN_FREELIST_PAG(pag, mp);
|
||||||
need = XFS_MIN_FREELIST(agf, mp);
|
|
||||||
/*
|
|
||||||
* If there isn't enough total or single-extent, reject it.
|
|
||||||
*/
|
|
||||||
if (!(flags & XFS_ALLOC_FLAG_FREEING)) {
|
if (!(flags & XFS_ALLOC_FLAG_FREEING)) {
|
||||||
delta = need > be32_to_cpu(agf->agf_flcount) ?
|
longest = xfs_alloc_longest_free_extent(mp, pag, need);
|
||||||
(need - be32_to_cpu(agf->agf_flcount)) : 0;
|
|
||||||
longest = be32_to_cpu(agf->agf_longest);
|
|
||||||
longest = (longest > delta) ? (longest - delta) :
|
|
||||||
(be32_to_cpu(agf->agf_flcount) > 0 || longest > 0);
|
|
||||||
if ((args->minlen + args->alignment + args->minalignslop - 1) >
|
if ((args->minlen + args->alignment + args->minalignslop - 1) >
|
||||||
longest ||
|
longest ||
|
||||||
((int)(be32_to_cpu(agf->agf_freeblks) +
|
((int)(pag->pagf_freeblks + pag->pagf_flcount -
|
||||||
be32_to_cpu(agf->agf_flcount) - need - args->total) <
|
need - args->total) < (int)args->minleft)) {
|
||||||
(int)args->minleft)) {
|
|
||||||
xfs_trans_brelse(tp, agbp);
|
xfs_trans_brelse(tp, agbp);
|
||||||
args->agbp = NULL;
|
args->agbp = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1948,21 +1937,25 @@ xfs_alloc_fix_freelist(
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Make the freelist shorter if it's too long.
|
* Make the freelist shorter if it's too long.
|
||||||
|
*
|
||||||
|
* XXX (dgc): When we have lots of free space, does this buy us
|
||||||
|
* anything other than extra overhead when we need to put more blocks
|
||||||
|
* back on the free list? Maybe we should only do this when space is
|
||||||
|
* getting low or the AGFL is more than half full?
|
||||||
*/
|
*/
|
||||||
while (be32_to_cpu(agf->agf_flcount) > need) {
|
while (pag->pagf_flcount > need) {
|
||||||
xfs_buf_t *bp;
|
struct xfs_buf *bp;
|
||||||
|
|
||||||
error = xfs_alloc_get_freelist(tp, agbp, &bno, 0);
|
error = xfs_alloc_get_freelist(tp, agbp, &bno, 0);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
if ((error = xfs_free_ag_extent(tp, agbp, args->agno, bno, 1, 1)))
|
error = xfs_free_ag_extent(tp, agbp, args->agno, bno, 1, 1);
|
||||||
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
bp = xfs_btree_get_bufs(mp, tp, args->agno, bno, 0);
|
bp = xfs_btree_get_bufs(mp, tp, args->agno, bno, 0);
|
||||||
xfs_trans_binval(tp, bp);
|
xfs_trans_binval(tp, bp);
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
* Initialize the args structure.
|
|
||||||
*/
|
|
||||||
memset(&targs, 0, sizeof(targs));
|
memset(&targs, 0, sizeof(targs));
|
||||||
targs.tp = tp;
|
targs.tp = tp;
|
||||||
targs.mp = mp;
|
targs.mp = mp;
|
||||||
|
@ -1971,18 +1964,18 @@ xfs_alloc_fix_freelist(
|
||||||
targs.alignment = targs.minlen = targs.prod = targs.isfl = 1;
|
targs.alignment = targs.minlen = targs.prod = targs.isfl = 1;
|
||||||
targs.type = XFS_ALLOCTYPE_THIS_AG;
|
targs.type = XFS_ALLOCTYPE_THIS_AG;
|
||||||
targs.pag = pag;
|
targs.pag = pag;
|
||||||
if ((error = xfs_alloc_read_agfl(mp, tp, targs.agno, &agflbp)))
|
error = xfs_alloc_read_agfl(mp, tp, targs.agno, &agflbp);
|
||||||
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
/*
|
|
||||||
* Make the freelist longer if it's too short.
|
/* Make the freelist longer if it's too short. */
|
||||||
*/
|
while (pag->pagf_flcount < need) {
|
||||||
while (be32_to_cpu(agf->agf_flcount) < need) {
|
|
||||||
targs.agbno = 0;
|
targs.agbno = 0;
|
||||||
targs.maxlen = need - be32_to_cpu(agf->agf_flcount);
|
targs.maxlen = need - pag->pagf_flcount;
|
||||||
/*
|
|
||||||
* Allocate as many blocks as possible at once.
|
/* Allocate as many blocks as possible at once. */
|
||||||
*/
|
error = xfs_alloc_ag_vextent(&targs);
|
||||||
if ((error = xfs_alloc_ag_vextent(&targs))) {
|
if (error) {
|
||||||
xfs_trans_brelse(tp, agflbp);
|
xfs_trans_brelse(tp, agflbp);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,12 +128,8 @@ typedef struct xfs_alloc_arg {
|
||||||
#define XFS_ALLOC_USERDATA 1 /* allocation is for user data*/
|
#define XFS_ALLOC_USERDATA 1 /* allocation is for user data*/
|
||||||
#define XFS_ALLOC_INITIAL_USER_DATA 2 /* special case start of file */
|
#define XFS_ALLOC_INITIAL_USER_DATA 2 /* special case start of file */
|
||||||
|
|
||||||
/*
|
xfs_extlen_t xfs_alloc_longest_free_extent(struct xfs_mount *mp,
|
||||||
* Find the length of the longest extent in an AG.
|
struct xfs_perag *pag, xfs_extlen_t need);
|
||||||
*/
|
|
||||||
xfs_extlen_t
|
|
||||||
xfs_alloc_longest_free_extent(struct xfs_mount *mp,
|
|
||||||
struct xfs_perag *pag);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute and fill in value of m_ag_maxlevels.
|
* Compute and fill in value of m_ag_maxlevels.
|
||||||
|
|
|
@ -3507,7 +3507,8 @@ xfs_bmap_longest_free_extent(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
longest = xfs_alloc_longest_free_extent(mp, pag);
|
longest = xfs_alloc_longest_free_extent(mp, pag,
|
||||||
|
XFS_MIN_FREELIST_PAG(pag, mp));
|
||||||
if (*blen < longest)
|
if (*blen < longest)
|
||||||
*blen = longest;
|
*blen = longest;
|
||||||
|
|
||||||
|
|
|
@ -196,7 +196,8 @@ xfs_filestream_pick_ag(
|
||||||
goto next_ag;
|
goto next_ag;
|
||||||
}
|
}
|
||||||
|
|
||||||
longest = xfs_alloc_longest_free_extent(mp, pag);
|
longest = xfs_alloc_longest_free_extent(mp, pag,
|
||||||
|
XFS_MIN_FREELIST_PAG(pag, mp));
|
||||||
if (((minlen && longest >= minlen) ||
|
if (((minlen && longest >= minlen) ||
|
||||||
(!minlen && pag->pagf_freeblks >= minfree)) &&
|
(!minlen && pag->pagf_freeblks >= minfree)) &&
|
||||||
(!pag->pagf_metadata || !(flags & XFS_PICK_USERDATA) ||
|
(!pag->pagf_metadata || !(flags & XFS_PICK_USERDATA) ||
|
||||||
|
|
Loading…
Add table
Reference in a new issue