xfs: factor xfs_bmap_btalloc()
There are several different contexts xfs_bmap_btalloc() handles, and large chunks of the code execute independent allocation contexts. Try to untangle this mess a bit. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Darrick J. Wong <djwong@kernel.org>
This commit is contained in:
parent
74c36a8689
commit
8584332709
1 changed files with 205 additions and 146 deletions
|
@ -3196,13 +3196,13 @@ xfs_bmap_select_minlen(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC int
|
static int
|
||||||
xfs_bmap_btalloc_select_lengths(
|
xfs_bmap_btalloc_select_lengths(
|
||||||
struct xfs_bmalloca *ap,
|
struct xfs_bmalloca *ap,
|
||||||
struct xfs_alloc_arg *args,
|
struct xfs_alloc_arg *args,
|
||||||
xfs_extlen_t *blen)
|
xfs_extlen_t *blen)
|
||||||
{
|
{
|
||||||
struct xfs_mount *mp = ap->ip->i_mount;
|
struct xfs_mount *mp = args->mp;
|
||||||
struct xfs_perag *pag;
|
struct xfs_perag *pag;
|
||||||
xfs_agnumber_t agno, startag;
|
xfs_agnumber_t agno, startag;
|
||||||
int notinit = 0;
|
int notinit = 0;
|
||||||
|
@ -3216,7 +3216,7 @@ xfs_bmap_btalloc_select_lengths(
|
||||||
}
|
}
|
||||||
|
|
||||||
args->total = ap->total;
|
args->total = ap->total;
|
||||||
startag = XFS_FSB_TO_AGNO(mp, args->fsbno);
|
startag = XFS_FSB_TO_AGNO(mp, ap->blkno);
|
||||||
if (startag == NULLAGNUMBER)
|
if (startag == NULLAGNUMBER)
|
||||||
startag = 0;
|
startag = 0;
|
||||||
|
|
||||||
|
@ -3258,7 +3258,7 @@ xfs_bmap_btalloc_filestreams(
|
||||||
args->type = XFS_ALLOCTYPE_NEAR_BNO;
|
args->type = XFS_ALLOCTYPE_NEAR_BNO;
|
||||||
args->total = ap->total;
|
args->total = ap->total;
|
||||||
|
|
||||||
start_agno = XFS_FSB_TO_AGNO(mp, args->fsbno);
|
start_agno = XFS_FSB_TO_AGNO(mp, ap->blkno);
|
||||||
if (start_agno == NULLAGNUMBER)
|
if (start_agno == NULLAGNUMBER)
|
||||||
start_agno = 0;
|
start_agno = 0;
|
||||||
|
|
||||||
|
@ -3496,19 +3496,212 @@ xfs_bmap_exact_minlen_extent_alloc(
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
STATIC int
|
/*
|
||||||
|
* If we are not low on available data blocks and we are allocating at
|
||||||
|
* EOF, optimise allocation for contiguous file extension and/or stripe
|
||||||
|
* alignment of the new extent.
|
||||||
|
*
|
||||||
|
* NOTE: ap->aeof is only set if the allocation length is >= the
|
||||||
|
* stripe unit and the allocation offset is at the end of file.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
xfs_bmap_btalloc_at_eof(
|
||||||
|
struct xfs_bmalloca *ap,
|
||||||
|
struct xfs_alloc_arg *args,
|
||||||
|
xfs_extlen_t blen,
|
||||||
|
int stripe_align)
|
||||||
|
{
|
||||||
|
struct xfs_mount *mp = args->mp;
|
||||||
|
xfs_alloctype_t atype;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there are already extents in the file, try an exact EOF block
|
||||||
|
* allocation to extend the file as a contiguous extent. If that fails,
|
||||||
|
* or it's the first allocation in a file, just try for a stripe aligned
|
||||||
|
* allocation.
|
||||||
|
*/
|
||||||
|
if (ap->offset) {
|
||||||
|
xfs_extlen_t nextminlen = 0;
|
||||||
|
|
||||||
|
atype = args->type;
|
||||||
|
args->type = XFS_ALLOCTYPE_THIS_BNO;
|
||||||
|
args->alignment = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute the minlen+alignment for the next case. Set slop so
|
||||||
|
* that the value of minlen+alignment+slop doesn't go up between
|
||||||
|
* the calls.
|
||||||
|
*/
|
||||||
|
if (blen > stripe_align && blen <= args->maxlen)
|
||||||
|
nextminlen = blen - stripe_align;
|
||||||
|
else
|
||||||
|
nextminlen = args->minlen;
|
||||||
|
if (nextminlen + stripe_align > args->minlen + 1)
|
||||||
|
args->minalignslop = nextminlen + stripe_align -
|
||||||
|
args->minlen - 1;
|
||||||
|
else
|
||||||
|
args->minalignslop = 0;
|
||||||
|
|
||||||
|
args->pag = xfs_perag_get(mp, XFS_FSB_TO_AGNO(mp, args->fsbno));
|
||||||
|
error = xfs_alloc_vextent_this_ag(args);
|
||||||
|
xfs_perag_put(args->pag);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
if (args->fsbno != NULLFSBLOCK)
|
||||||
|
return 0;
|
||||||
|
/*
|
||||||
|
* Exact allocation failed. Reset to try an aligned allocation
|
||||||
|
* according to the original allocation specification.
|
||||||
|
*/
|
||||||
|
args->pag = NULL;
|
||||||
|
args->type = atype;
|
||||||
|
args->fsbno = ap->blkno;
|
||||||
|
args->alignment = stripe_align;
|
||||||
|
args->minlen = nextminlen;
|
||||||
|
args->minalignslop = 0;
|
||||||
|
} else {
|
||||||
|
args->alignment = stripe_align;
|
||||||
|
atype = args->type;
|
||||||
|
/*
|
||||||
|
* Adjust minlen to try and preserve alignment if we
|
||||||
|
* can't guarantee an aligned maxlen extent.
|
||||||
|
*/
|
||||||
|
if (blen > args->alignment &&
|
||||||
|
blen <= args->maxlen + args->alignment)
|
||||||
|
args->minlen = blen - args->alignment;
|
||||||
|
args->minalignslop = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = xfs_alloc_vextent(args);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
if (args->fsbno != NULLFSBLOCK)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocation failed, so turn return the allocation args to their
|
||||||
|
* original non-aligned state so the caller can proceed on allocation
|
||||||
|
* failure as if this function was never called.
|
||||||
|
*/
|
||||||
|
args->type = atype;
|
||||||
|
args->fsbno = ap->blkno;
|
||||||
|
args->alignment = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xfs_bmap_btalloc_best_length(
|
||||||
|
struct xfs_bmalloca *ap,
|
||||||
|
struct xfs_alloc_arg *args,
|
||||||
|
int stripe_align)
|
||||||
|
{
|
||||||
|
struct xfs_mount *mp = args->mp;
|
||||||
|
xfs_extlen_t blen = 0;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine the initial block number we will target for allocation.
|
||||||
|
*/
|
||||||
|
if ((ap->datatype & XFS_ALLOC_USERDATA) &&
|
||||||
|
xfs_inode_is_filestream(ap->ip)) {
|
||||||
|
xfs_agnumber_t agno = xfs_filestream_lookup_ag(ap->ip);
|
||||||
|
if (agno == NULLAGNUMBER)
|
||||||
|
agno = 0;
|
||||||
|
ap->blkno = XFS_AGB_TO_FSB(mp, agno, 0);
|
||||||
|
} else {
|
||||||
|
ap->blkno = XFS_INO_TO_FSB(mp, ap->ip->i_ino);
|
||||||
|
}
|
||||||
|
xfs_bmap_adjacent(ap);
|
||||||
|
args->fsbno = ap->blkno;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Search for an allocation group with a single extent large enough for
|
||||||
|
* the request. If one isn't found, then adjust the minimum allocation
|
||||||
|
* size to the largest space found.
|
||||||
|
*/
|
||||||
|
if ((ap->datatype & XFS_ALLOC_USERDATA) &&
|
||||||
|
xfs_inode_is_filestream(ap->ip))
|
||||||
|
error = xfs_bmap_btalloc_filestreams(ap, args, &blen);
|
||||||
|
else
|
||||||
|
error = xfs_bmap_btalloc_select_lengths(ap, args, &blen);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Don't attempt optimal EOF allocation if previous allocations barely
|
||||||
|
* succeeded due to being near ENOSPC. It is highly unlikely we'll get
|
||||||
|
* optimal or even aligned allocations in this case, so don't waste time
|
||||||
|
* trying.
|
||||||
|
*/
|
||||||
|
if (ap->aeof && !(ap->tp->t_flags & XFS_TRANS_LOWMODE)) {
|
||||||
|
error = xfs_bmap_btalloc_at_eof(ap, args, blen, stripe_align);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
if (args->fsbno != NULLFSBLOCK)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = xfs_alloc_vextent(args);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
if (args->fsbno != NULLFSBLOCK)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try a locality first full filesystem minimum length allocation whilst
|
||||||
|
* still maintaining necessary total block reservation requirements.
|
||||||
|
*/
|
||||||
|
if (args->minlen > ap->minlen) {
|
||||||
|
args->minlen = ap->minlen;
|
||||||
|
args->type = XFS_ALLOCTYPE_START_BNO;
|
||||||
|
args->fsbno = ap->blkno;
|
||||||
|
error = xfs_alloc_vextent(args);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
if (args->fsbno != NULLFSBLOCK)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We are now critically low on space, so this is a last resort
|
||||||
|
* allocation attempt: no reserve, no locality, blocking, minimum
|
||||||
|
* length, full filesystem free space scan. We also indicate to future
|
||||||
|
* allocations in this transaction that we are critically low on space
|
||||||
|
* so they don't waste time on allocation modes that are unlikely to
|
||||||
|
* succeed.
|
||||||
|
*/
|
||||||
|
args->fsbno = 0;
|
||||||
|
args->type = XFS_ALLOCTYPE_FIRST_AG;
|
||||||
|
args->total = ap->minlen;
|
||||||
|
error = xfs_alloc_vextent(args);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
ap->tp->t_flags |= XFS_TRANS_LOWMODE;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
xfs_bmap_btalloc(
|
xfs_bmap_btalloc(
|
||||||
struct xfs_bmalloca *ap)
|
struct xfs_bmalloca *ap)
|
||||||
{
|
{
|
||||||
struct xfs_mount *mp = ap->ip->i_mount;
|
struct xfs_mount *mp = ap->ip->i_mount;
|
||||||
struct xfs_alloc_arg args = { .tp = ap->tp, .mp = mp };
|
struct xfs_alloc_arg args = {
|
||||||
xfs_alloctype_t atype = 0;
|
.tp = ap->tp,
|
||||||
xfs_agnumber_t ag;
|
.mp = mp,
|
||||||
|
.fsbno = NULLFSBLOCK,
|
||||||
|
.oinfo = XFS_RMAP_OINFO_SKIP_UPDATE,
|
||||||
|
.minleft = ap->minleft,
|
||||||
|
.wasdel = ap->wasdel,
|
||||||
|
.resv = XFS_AG_RESV_NONE,
|
||||||
|
.datatype = ap->datatype,
|
||||||
|
.alignment = 1,
|
||||||
|
.minalignslop = 0,
|
||||||
|
};
|
||||||
xfs_fileoff_t orig_offset;
|
xfs_fileoff_t orig_offset;
|
||||||
xfs_extlen_t orig_length;
|
xfs_extlen_t orig_length;
|
||||||
xfs_extlen_t blen;
|
|
||||||
xfs_extlen_t nextminlen = 0;
|
|
||||||
int isaligned = 0;
|
|
||||||
int error;
|
int error;
|
||||||
int stripe_align;
|
int stripe_align;
|
||||||
|
|
||||||
|
@ -3518,148 +3711,14 @@ xfs_bmap_btalloc(
|
||||||
|
|
||||||
stripe_align = xfs_bmap_compute_alignments(ap, &args);
|
stripe_align = xfs_bmap_compute_alignments(ap, &args);
|
||||||
|
|
||||||
if ((ap->datatype & XFS_ALLOC_USERDATA) &&
|
|
||||||
xfs_inode_is_filestream(ap->ip)) {
|
|
||||||
ag = xfs_filestream_lookup_ag(ap->ip);
|
|
||||||
ag = (ag != NULLAGNUMBER) ? ag : 0;
|
|
||||||
ap->blkno = XFS_AGB_TO_FSB(mp, ag, 0);
|
|
||||||
} else {
|
|
||||||
ap->blkno = XFS_INO_TO_FSB(mp, ap->ip->i_ino);
|
|
||||||
}
|
|
||||||
|
|
||||||
xfs_bmap_adjacent(ap);
|
|
||||||
|
|
||||||
args.fsbno = ap->blkno;
|
|
||||||
args.oinfo = XFS_RMAP_OINFO_SKIP_UPDATE;
|
|
||||||
|
|
||||||
/* Trim the allocation back to the maximum an AG can fit. */
|
/* Trim the allocation back to the maximum an AG can fit. */
|
||||||
args.maxlen = min(ap->length, mp->m_ag_max_usable);
|
args.maxlen = min(ap->length, mp->m_ag_max_usable);
|
||||||
blen = 0;
|
|
||||||
|
|
||||||
/*
|
error = xfs_bmap_btalloc_best_length(ap, &args, stripe_align);
|
||||||
* Search for an allocation group with a single extent large
|
|
||||||
* enough for the request. If one isn't found, then adjust
|
|
||||||
* the minimum allocation size to the largest space found.
|
|
||||||
*/
|
|
||||||
if ((ap->datatype & XFS_ALLOC_USERDATA) &&
|
|
||||||
xfs_inode_is_filestream(ap->ip))
|
|
||||||
error = xfs_bmap_btalloc_filestreams(ap, &args, &blen);
|
|
||||||
else
|
|
||||||
error = xfs_bmap_btalloc_select_lengths(ap, &args, &blen);
|
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
/*
|
|
||||||
* If we are not low on available data blocks, and the underlying
|
|
||||||
* logical volume manager is a stripe, and the file offset is zero then
|
|
||||||
* try to allocate data blocks on stripe unit boundary. NOTE: ap->aeof
|
|
||||||
* is only set if the allocation length is >= the stripe unit and the
|
|
||||||
* allocation offset is at the end of file.
|
|
||||||
*/
|
|
||||||
if (!(ap->tp->t_flags & XFS_TRANS_LOWMODE) && ap->aeof) {
|
|
||||||
if (!ap->offset) {
|
|
||||||
args.alignment = stripe_align;
|
|
||||||
atype = args.type;
|
|
||||||
isaligned = 1;
|
|
||||||
/*
|
|
||||||
* Adjust minlen to try and preserve alignment if we
|
|
||||||
* can't guarantee an aligned maxlen extent.
|
|
||||||
*/
|
|
||||||
if (blen > args.alignment &&
|
|
||||||
blen <= args.maxlen + args.alignment)
|
|
||||||
args.minlen = blen - args.alignment;
|
|
||||||
args.minalignslop = 0;
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* First try an exact bno allocation.
|
|
||||||
* If it fails then do a near or start bno
|
|
||||||
* allocation with alignment turned on.
|
|
||||||
*/
|
|
||||||
atype = args.type;
|
|
||||||
args.type = XFS_ALLOCTYPE_THIS_BNO;
|
|
||||||
args.alignment = 1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Compute the minlen+alignment for the
|
|
||||||
* next case. Set slop so that the value
|
|
||||||
* of minlen+alignment+slop doesn't go up
|
|
||||||
* between the calls.
|
|
||||||
*/
|
|
||||||
if (blen > stripe_align && blen <= args.maxlen)
|
|
||||||
nextminlen = blen - stripe_align;
|
|
||||||
else
|
|
||||||
nextminlen = args.minlen;
|
|
||||||
if (nextminlen + stripe_align > args.minlen + 1)
|
|
||||||
args.minalignslop =
|
|
||||||
nextminlen + stripe_align -
|
|
||||||
args.minlen - 1;
|
|
||||||
else
|
|
||||||
args.minalignslop = 0;
|
|
||||||
|
|
||||||
args.pag = xfs_perag_get(mp,
|
|
||||||
XFS_FSB_TO_AGNO(mp, args.fsbno));
|
|
||||||
error = xfs_alloc_vextent_this_ag(&args);
|
|
||||||
xfs_perag_put(args.pag);
|
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
|
|
||||||
if (args.fsbno != NULLFSBLOCK)
|
|
||||||
goto out_success;
|
|
||||||
/*
|
|
||||||
* Exact allocation failed. Now try with alignment
|
|
||||||
* turned on.
|
|
||||||
*/
|
|
||||||
args.pag = NULL;
|
|
||||||
args.type = atype;
|
|
||||||
args.fsbno = ap->blkno;
|
|
||||||
args.alignment = stripe_align;
|
|
||||||
args.minlen = nextminlen;
|
|
||||||
args.minalignslop = 0;
|
|
||||||
isaligned = 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
args.alignment = 1;
|
|
||||||
args.minalignslop = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
error = xfs_alloc_vextent(&args);
|
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
|
|
||||||
if (isaligned && args.fsbno == NULLFSBLOCK) {
|
|
||||||
/*
|
|
||||||
* allocation failed, so turn off alignment and
|
|
||||||
* try again.
|
|
||||||
*/
|
|
||||||
args.type = atype;
|
|
||||||
args.fsbno = ap->blkno;
|
|
||||||
args.alignment = 0;
|
|
||||||
if ((error = xfs_alloc_vextent(&args)))
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
if (args.fsbno == NULLFSBLOCK &&
|
|
||||||
args.minlen > ap->minlen) {
|
|
||||||
args.minlen = ap->minlen;
|
|
||||||
args.type = XFS_ALLOCTYPE_START_BNO;
|
|
||||||
args.fsbno = ap->blkno;
|
|
||||||
if ((error = xfs_alloc_vextent(&args)))
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
if (args.fsbno == NULLFSBLOCK) {
|
|
||||||
args.fsbno = 0;
|
|
||||||
args.type = XFS_ALLOCTYPE_FIRST_AG;
|
|
||||||
args.total = ap->minlen;
|
|
||||||
if ((error = xfs_alloc_vextent(&args)))
|
|
||||||
return error;
|
|
||||||
ap->tp->t_flags |= XFS_TRANS_LOWMODE;
|
|
||||||
}
|
|
||||||
args.minleft = ap->minleft;
|
|
||||||
args.wasdel = ap->wasdel;
|
|
||||||
args.resv = XFS_AG_RESV_NONE;
|
|
||||||
args.datatype = ap->datatype;
|
|
||||||
|
|
||||||
if (args.fsbno != NULLFSBLOCK) {
|
if (args.fsbno != NULLFSBLOCK) {
|
||||||
out_success:
|
|
||||||
xfs_bmap_process_allocated_extent(ap, &args, orig_offset,
|
xfs_bmap_process_allocated_extent(ap, &args, orig_offset,
|
||||||
orig_length);
|
orig_length);
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Add table
Reference in a new issue