xfs: factor extent allocation out of xfs_bmapi

To further improve the readability of xfs_bmapi(), factor the extent
allocation out into a separate function. This removes a large block
of logic from the xfs_bmapi() code loop and makes it easier to see
the operational logic flow for xfs_bmapi().

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Alex Elder <aelder@sgi.com>
This commit is contained in:
Dave Chinner 2011-09-18 20:40:50 +00:00 committed by Alex Elder
parent 1fd044d9c6
commit 7e47a4efde

View File

@ -4605,6 +4605,147 @@ xfs_bmapi_delay(
}
STATIC int
xfs_bmapi_allocate(
struct xfs_bmalloca *bma,
xfs_extnum_t *lastx,
struct xfs_btree_cur **cur,
xfs_fsblock_t *firstblock,
struct xfs_bmap_free *flist,
int flags,
int *nallocs,
int *logflags)
{
struct xfs_mount *mp = bma->ip->i_mount;
int whichfork = (flags & XFS_BMAPI_ATTRFORK) ?
XFS_ATTR_FORK : XFS_DATA_FORK;
struct xfs_ifork *ifp = XFS_IFORK_PTR(bma->ip, whichfork);
xfs_fsblock_t abno;
xfs_extlen_t alen;
xfs_fileoff_t aoff;
int error;
int rt;
rt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(bma->ip);
/*
* For the wasdelay case, we could also just allocate the stuff asked
* for in this bmap call but that wouldn't be as good.
*/
if (bma->wasdel) {
alen = (xfs_extlen_t)bma->gotp->br_blockcount;
aoff = bma->gotp->br_startoff;
if (*lastx != NULLEXTNUM && *lastx) {
xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *lastx - 1),
bma->prevp);
}
} else {
alen = (xfs_extlen_t)XFS_FILBLKS_MIN(bma->alen, MAXEXTLEN);
if (!bma->eof)
alen = (xfs_extlen_t)XFS_FILBLKS_MIN(alen,
bma->gotp->br_startoff - bma->off);
aoff = bma->off;
}
/*
* Indicate if this is the first user data in the file, or just any
* user data.
*/
if (!(flags & XFS_BMAPI_METADATA)) {
bma->userdata = (aoff == 0) ?
XFS_ALLOC_INITIAL_USER_DATA : XFS_ALLOC_USERDATA;
}
/*
* Fill in changeable bma fields.
*/
bma->alen = alen;
bma->off = aoff;
bma->firstblock = *firstblock;
bma->minlen = (flags & XFS_BMAPI_CONTIG) ? alen : 1;
bma->low = flist->xbf_low;
bma->aeof = 0;
/*
* Only want to do the alignment at the eof if it is userdata and
* allocation length is larger than a stripe unit.
*/
if (mp->m_dalign && alen >= mp->m_dalign &&
!(flags & XFS_BMAPI_METADATA) && whichfork == XFS_DATA_FORK) {
error = xfs_bmap_isaeof(bma->ip, aoff, whichfork, &bma->aeof);
if (error)
return error;
}
error = xfs_bmap_alloc(bma);
if (error)
return error;
/*
* Copy out result fields.
*/
abno = bma->rval;
flist->xbf_low = bma->low;
alen = bma->alen;
aoff = bma->off;
ASSERT(*firstblock == NULLFSBLOCK ||
XFS_FSB_TO_AGNO(mp, *firstblock) ==
XFS_FSB_TO_AGNO(mp, bma->firstblock) ||
(flist->xbf_low &&
XFS_FSB_TO_AGNO(mp, *firstblock) <
XFS_FSB_TO_AGNO(mp, bma->firstblock)));
*firstblock = bma->firstblock;
if (*cur)
(*cur)->bc_private.b.firstblock = *firstblock;
if (abno == NULLFSBLOCK)
return 0;
if ((ifp->if_flags & XFS_IFBROOT) && !*cur) {
(*cur) = xfs_bmbt_init_cursor(mp, bma->tp, bma->ip, whichfork);
(*cur)->bc_private.b.firstblock = *firstblock;
(*cur)->bc_private.b.flist = flist;
}
/*
* Bump the number of extents we've allocated
* in this call.
*/
(*nallocs)++;
if (*cur)
(*cur)->bc_private.b.flags =
bma->wasdel ? XFS_BTCUR_BPRV_WASDEL : 0;
bma->gotp->br_startoff = aoff;
bma->gotp->br_startblock = abno;
bma->gotp->br_blockcount = alen;
bma->gotp->br_state = XFS_EXT_NORM;
/*
* A wasdelay extent has been initialized, so shouldn't be flagged
* as unwritten.
*/
if (!bma->wasdel && (flags & XFS_BMAPI_PREALLOC) &&
xfs_sb_version_hasextflgbit(&mp->m_sb))
bma->gotp->br_state = XFS_EXT_UNWRITTEN;
error = xfs_bmap_add_extent(bma->tp, bma->ip, lastx, cur, bma->gotp,
firstblock, flist, logflags, whichfork);
if (error)
return error;
/*
* Update our extent pointer, given that xfs_bmap_add_extent might
* have merged it into one of the neighbouring ones.
*/
xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *lastx), bma->gotp);
ASSERT(bma->gotp->br_startoff <= aoff);
ASSERT(bma->gotp->br_startoff + bma->gotp->br_blockcount >=
aoff + alen);
ASSERT(bma->gotp->br_state == XFS_EXT_NORM ||
bma->gotp->br_state == XFS_EXT_UNWRITTEN);
return 0;
}
/*
* Map file blocks to filesystem blocks.
* File range is given by the bno/len pair.
@ -4632,9 +4773,6 @@ xfs_bmapi(
int *nmap, /* i/o: mval size/count */
xfs_bmap_free_t *flist) /* i/o: list extents to free */
{
xfs_fsblock_t abno; /* allocated block number */
xfs_extlen_t alen; /* allocated extent length */
xfs_fileoff_t aoff; /* allocated file offset */
xfs_bmalloca_t bma = { 0 }; /* args for xfs_bmap_alloc */
xfs_btree_cur_t *cur; /* bmap btree cursor */
xfs_fileoff_t end; /* end of mapped file region */
@ -4646,7 +4784,6 @@ xfs_bmapi(
xfs_extnum_t lastx; /* last useful extent number */
int logflags; /* flags for transaction logging */
xfs_extlen_t minleft; /* min blocks left after allocation */
xfs_extlen_t minlen; /* min allocation size */
xfs_mount_t *mp; /* xfs mount structure */
int n; /* current extent index */
int nallocs; /* number of extents alloc'd */
@ -4737,7 +4874,13 @@ xfs_bmapi(
n = 0;
end = bno + len;
obno = bno;
bma.ip = NULL;
bma.tp = tp;
bma.ip = ip;
bma.prevp = &prev;
bma.gotp = &got;
bma.total = total;
bma.userdata = 0;
while (bno < end && n < *nmap) {
/*
@ -4753,144 +4896,23 @@ xfs_bmapi(
* that we found, if any.
*/
if (wr && (inhole || wasdelay)) {
/*
* For the wasdelay case, we could also just
* allocate the stuff asked for in this bmap call
* but that wouldn't be as good.
*/
if (wasdelay) {
alen = (xfs_extlen_t)got.br_blockcount;
aoff = got.br_startoff;
if (lastx != NULLEXTNUM && lastx) {
ep = xfs_iext_get_ext(ifp, lastx - 1);
xfs_bmbt_get_all(ep, &prev);
}
} else {
alen = (xfs_extlen_t)
XFS_FILBLKS_MIN(len, MAXEXTLEN);
if (!eof)
alen = (xfs_extlen_t)
XFS_FILBLKS_MIN(alen,
got.br_startoff - bno);
aoff = bno;
}
minlen = (flags & XFS_BMAPI_CONTIG) ? alen : 1;
{
/*
* If first time, allocate and fill in
* once-only bma fields.
*/
if (bma.ip == NULL) {
bma.tp = tp;
bma.ip = ip;
bma.prevp = &prev;
bma.gotp = &got;
bma.total = total;
bma.userdata = 0;
}
/* Indicate if this is the first user data
* in the file, or just any user data.
*/
if (!(flags & XFS_BMAPI_METADATA)) {
bma.userdata = (aoff == 0) ?
XFS_ALLOC_INITIAL_USER_DATA :
XFS_ALLOC_USERDATA;
}
/*
* Fill in changeable bma fields.
*/
bma.eof = eof;
bma.firstblock = *firstblock;
bma.alen = alen;
bma.off = aoff;
bma.conv = !!(flags & XFS_BMAPI_CONVERT);
bma.wasdel = wasdelay;
bma.minlen = minlen;
bma.low = flist->xbf_low;
bma.minleft = minleft;
/*
* Only want to do the alignment at the
* eof if it is userdata and allocation length
* is larger than a stripe unit.
*/
if (mp->m_dalign && alen >= mp->m_dalign &&
(!(flags & XFS_BMAPI_METADATA)) &&
(whichfork == XFS_DATA_FORK)) {
if ((error = xfs_bmap_isaeof(ip, aoff,
whichfork, &bma.aeof)))
goto error0;
} else
bma.aeof = 0;
/*
* Call allocator.
*/
if ((error = xfs_bmap_alloc(&bma)))
goto error0;
/*
* Copy out result fields.
*/
abno = bma.rval;
if ((flist->xbf_low = bma.low))
minleft = 0;
alen = bma.alen;
aoff = bma.off;
ASSERT(*firstblock == NULLFSBLOCK ||
XFS_FSB_TO_AGNO(mp, *firstblock) ==
XFS_FSB_TO_AGNO(mp, bma.firstblock) ||
(flist->xbf_low &&
XFS_FSB_TO_AGNO(mp, *firstblock) <
XFS_FSB_TO_AGNO(mp, bma.firstblock)));
*firstblock = bma.firstblock;
if (cur)
cur->bc_private.b.firstblock =
*firstblock;
if (abno == NULLFSBLOCK)
break;
if ((ifp->if_flags & XFS_IFBROOT) && !cur) {
cur = xfs_bmbt_init_cursor(mp, tp,
ip, whichfork);
cur->bc_private.b.firstblock =
*firstblock;
cur->bc_private.b.flist = flist;
}
/*
* Bump the number of extents we've allocated
* in this call.
*/
nallocs++;
}
if (cur)
cur->bc_private.b.flags =
wasdelay ? XFS_BTCUR_BPRV_WASDEL : 0;
got.br_startoff = aoff;
got.br_startblock = abno;
got.br_blockcount = alen;
got.br_state = XFS_EXT_NORM; /* assume normal */
/*
* Determine state of extent, and the filesystem.
* A wasdelay extent has been initialized, so
* shouldn't be flagged as unwritten.
*/
if (wr && xfs_sb_version_hasextflgbit(&mp->m_sb)) {
if (!wasdelay && (flags & XFS_BMAPI_PREALLOC))
got.br_state = XFS_EXT_UNWRITTEN;
}
error = xfs_bmap_add_extent(tp, ip, &lastx, &cur, &got,
firstblock, flist, &tmp_logflags,
whichfork);
bma.eof = eof;
bma.conv = !!(flags & XFS_BMAPI_CONVERT);
bma.wasdel = wasdelay;
bma.alen = len;
bma.off = bno;
bma.minleft = minleft;
error = xfs_bmapi_allocate(&bma, &lastx, &cur,
firstblock, flist, flags, &nallocs,
&tmp_logflags);
logflags |= tmp_logflags;
if (error)
goto error0;
ep = xfs_iext_get_ext(ifp, lastx);
xfs_bmbt_get_all(ep, &got);
ASSERT(got.br_startoff <= aoff);
ASSERT(got.br_startoff + got.br_blockcount >=
aoff + alen);
ASSERT(got.br_state == XFS_EXT_NORM ||
got.br_state == XFS_EXT_UNWRITTEN);
/*
* Fall down into the found allocated space case.
*/
if (flist && flist->xbf_low)
minleft = 0;
if (bma.rval == NULLFSBLOCK)
break;
} else if (inhole) {
/*
* Reading in a hole.