mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-24 20:54:10 +08:00
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
@ -3196,13 +3196,13 @@ xfs_bmap_select_minlen(
|
||||
}
|
||||
}
|
||||
|
||||
STATIC int
|
||||
static int
|
||||
xfs_bmap_btalloc_select_lengths(
|
||||
struct xfs_bmalloca *ap,
|
||||
struct xfs_alloc_arg *args,
|
||||
xfs_extlen_t *blen)
|
||||
{
|
||||
struct xfs_mount *mp = ap->ip->i_mount;
|
||||
struct xfs_mount *mp = args->mp;
|
||||
struct xfs_perag *pag;
|
||||
xfs_agnumber_t agno, startag;
|
||||
int notinit = 0;
|
||||
@ -3216,7 +3216,7 @@ xfs_bmap_btalloc_select_lengths(
|
||||
}
|
||||
|
||||
args->total = ap->total;
|
||||
startag = XFS_FSB_TO_AGNO(mp, args->fsbno);
|
||||
startag = XFS_FSB_TO_AGNO(mp, ap->blkno);
|
||||
if (startag == NULLAGNUMBER)
|
||||
startag = 0;
|
||||
|
||||
@ -3258,7 +3258,7 @@ xfs_bmap_btalloc_filestreams(
|
||||
args->type = XFS_ALLOCTYPE_NEAR_BNO;
|
||||
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)
|
||||
start_agno = 0;
|
||||
|
||||
@ -3496,19 +3496,212 @@ xfs_bmap_exact_minlen_extent_alloc(
|
||||
|
||||
#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(
|
||||
struct xfs_bmalloca *ap)
|
||||
{
|
||||
struct xfs_mount *mp = ap->ip->i_mount;
|
||||
struct xfs_alloc_arg args = { .tp = ap->tp, .mp = mp };
|
||||
xfs_alloctype_t atype = 0;
|
||||
xfs_agnumber_t ag;
|
||||
struct xfs_alloc_arg args = {
|
||||
.tp = ap->tp,
|
||||
.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_extlen_t orig_length;
|
||||
xfs_extlen_t blen;
|
||||
xfs_extlen_t nextminlen = 0;
|
||||
int isaligned = 0;
|
||||
int error;
|
||||
int stripe_align;
|
||||
|
||||
@ -3518,148 +3711,14 @@ xfs_bmap_btalloc(
|
||||
|
||||
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. */
|
||||
args.maxlen = min(ap->length, mp->m_ag_max_usable);
|
||||
blen = 0;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
error = xfs_bmap_btalloc_best_length(ap, &args, stripe_align);
|
||||
if (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) {
|
||||
out_success:
|
||||
xfs_bmap_process_allocated_extent(ap, &args, orig_offset,
|
||||
orig_length);
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user