Skip to content

Commit

Permalink
xfs: limit extent length for allocation to AG size
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Dave Chinner authored and Alex Elder committed Jan 28, 2011
1 parent b8fc826 commit 14b064c
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 8 deletions.
16 changes: 16 additions & 0 deletions fs/xfs/xfs_alloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 10 additions & 8 deletions fs/xfs/xfs_bmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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) {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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 {
Expand All @@ -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;
Expand Down

0 comments on commit 14b064c

Please sign in to comment.