xfs: limit extent length for allocation to AG size
Delayed allocation extents can be larger than AGs, so when trying to convert a large range we may scan every AG inside xfs_bmap_alloc_nullfb() trying to find an AG with a size larger than an AG. We should stop when we find the first AG with a maximum possible allocation size. This causes excessive CPU usage when there are lots of AGs. The same problem occurs when doing preallocation of a range larger than an AG. Fix the problem by limiting real allocation lengths to the maximum that an AG can support. This means if we have empty AGs, we'll stop the search at the first of them. If there are no empty AGs, we'll still scan them all, but that is a different problem.... Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Alex Elder <aelder@sgi.com>
This commit is contained in:
parent
b8fc82630a
commit
14b064ceaa
|
@ -74,6 +74,22 @@ typedef unsigned int xfs_alloctype_t;
|
|||
*/
|
||||
#define XFS_ALLOC_SET_ASIDE(mp) (4 + ((mp)->m_sb.sb_agcount * 4))
|
||||
|
||||
/*
|
||||
* When deciding how much space to allocate out of an AG, we limit the
|
||||
* allocation maximum size to the size the AG. However, we cannot use all the
|
||||
* blocks in the AG - some are permanently used by metadata. These
|
||||
* blocks are generally:
|
||||
* - the AG superblock, AGF, AGI and AGFL
|
||||
* - the AGF (bno and cnt) and AGI btree root blocks
|
||||
* - 4 blocks on the AGFL according to XFS_ALLOC_SET_ASIDE() limits
|
||||
*
|
||||
* The AG headers are sector sized, so the amount of space they take up is
|
||||
* dependent on filesystem geometry. The others are all single blocks.
|
||||
*/
|
||||
#define XFS_ALLOC_AG_MAX_USABLE(mp) \
|
||||
((mp)->m_sb.sb_agblocks - XFS_BB_TO_FSB(mp, XFS_FSS_TO_BB(mp, 4)) - 7)
|
||||
|
||||
|
||||
/*
|
||||
* Argument structure for xfs_alloc routines.
|
||||
* This is turned into a structure to avoid having 20 arguments passed
|
||||
|
|
|
@ -2430,7 +2430,7 @@ xfs_bmap_btalloc_nullfb(
|
|||
startag = ag = 0;
|
||||
|
||||
pag = xfs_perag_get(mp, ag);
|
||||
while (*blen < ap->alen) {
|
||||
while (*blen < args->maxlen) {
|
||||
if (!pag->pagf_init) {
|
||||
error = xfs_alloc_pagf_init(mp, args->tp, ag,
|
||||
XFS_ALLOC_FLAG_TRYLOCK);
|
||||
|
@ -2452,7 +2452,7 @@ xfs_bmap_btalloc_nullfb(
|
|||
notinit = 1;
|
||||
|
||||
if (xfs_inode_is_filestream(ap->ip)) {
|
||||
if (*blen >= ap->alen)
|
||||
if (*blen >= args->maxlen)
|
||||
break;
|
||||
|
||||
if (ap->userdata) {
|
||||
|
@ -2498,14 +2498,14 @@ xfs_bmap_btalloc_nullfb(
|
|||
* If the best seen length is less than the request
|
||||
* length, use the best as the minimum.
|
||||
*/
|
||||
else if (*blen < ap->alen)
|
||||
else if (*blen < args->maxlen)
|
||||
args->minlen = *blen;
|
||||
/*
|
||||
* Otherwise we've seen an extent as big as alen,
|
||||
* Otherwise we've seen an extent as big as maxlen,
|
||||
* use that as the minimum.
|
||||
*/
|
||||
else
|
||||
args->minlen = ap->alen;
|
||||
args->minlen = args->maxlen;
|
||||
|
||||
/*
|
||||
* set the failure fallback case to look in the selected
|
||||
|
@ -2573,7 +2573,9 @@ xfs_bmap_btalloc(
|
|||
args.tp = ap->tp;
|
||||
args.mp = mp;
|
||||
args.fsbno = ap->rval;
|
||||
args.maxlen = MIN(ap->alen, mp->m_sb.sb_agblocks);
|
||||
|
||||
/* Trim the allocation back to the maximum an AG can fit. */
|
||||
args.maxlen = MIN(ap->alen, XFS_ALLOC_AG_MAX_USABLE(mp));
|
||||
args.firstblock = ap->firstblock;
|
||||
blen = 0;
|
||||
if (nullfb) {
|
||||
|
@ -2621,7 +2623,7 @@ xfs_bmap_btalloc(
|
|||
/*
|
||||
* Adjust for alignment
|
||||
*/
|
||||
if (blen > args.alignment && blen <= ap->alen)
|
||||
if (blen > args.alignment && blen <= args.maxlen)
|
||||
args.minlen = blen - args.alignment;
|
||||
args.minalignslop = 0;
|
||||
} else {
|
||||
|
@ -2640,7 +2642,7 @@ xfs_bmap_btalloc(
|
|||
* of minlen+alignment+slop doesn't go up
|
||||
* between the calls.
|
||||
*/
|
||||
if (blen > mp->m_dalign && blen <= ap->alen)
|
||||
if (blen > mp->m_dalign && blen <= args.maxlen)
|
||||
nextminlen = blen - mp->m_dalign;
|
||||
else
|
||||
nextminlen = args.minlen;
|
||||
|
|
Loading…
Reference in a new issue