xfs: drop firstblock constraints from allocation setup

Now that xfs_alloc_vextent() does all the AGF deadlock prevention
filtering for multiple allocations in a single transaction, we no
longer need the allocation setup code to care about what AGs we
might already have locked.

Hence we can remove all the "nullfb" conditional logic in places
like xfs_bmap_btalloc() and instead have them focus simply on
setting up locality constraints. If the allocation fails due to
AGF lock filtering in xfs_alloc_vextent, then we just fall back as
we normally do to more relaxed allocation constraints.

As a result, any allocation that allows AG scanning (i.e. not
confined to a single AG) and does not force a worst case full
filesystem scan will now be able to attempt allocation from AGs
lower than that defined by tp->t_firstblock. This is because
xfs_alloc_vextent() allows try-locking of the AGFs and hence enables
low space algorithms to at least -try- to get space from AGs lower
than the one that we have currently locked and allocated from. This
is a significant improvement in the low space allocation algorithm.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
This commit is contained in:
Dave Chinner 2023-02-11 04:10:06 +11:00
parent d5753847b2
commit 36b6ad2d9c
2 changed files with 66 additions and 132 deletions

View File

@ -645,16 +645,9 @@ xfs_bmap_extents_to_btree(
args.tp = tp; args.tp = tp;
args.mp = mp; args.mp = mp;
xfs_rmap_ino_bmbt_owner(&args.oinfo, ip->i_ino, whichfork); xfs_rmap_ino_bmbt_owner(&args.oinfo, ip->i_ino, whichfork);
if (tp->t_firstblock == NULLFSBLOCK) {
args.type = XFS_ALLOCTYPE_START_BNO; args.type = XFS_ALLOCTYPE_START_BNO;
args.fsbno = XFS_INO_TO_FSB(mp, ip->i_ino); args.fsbno = XFS_INO_TO_FSB(mp, ip->i_ino);
} else if (tp->t_flags & XFS_TRANS_LOWMODE) {
args.type = XFS_ALLOCTYPE_START_BNO;
args.fsbno = tp->t_firstblock;
} else {
args.type = XFS_ALLOCTYPE_NEAR_BNO;
args.fsbno = tp->t_firstblock;
}
args.minlen = args.maxlen = args.prod = 1; args.minlen = args.maxlen = args.prod = 1;
args.wasdel = wasdel; args.wasdel = wasdel;
*logflagsp = 0; *logflagsp = 0;
@ -662,17 +655,14 @@ xfs_bmap_extents_to_btree(
if (error) if (error)
goto out_root_realloc; goto out_root_realloc;
/*
* Allocation can't fail, the space was reserved.
*/
if (WARN_ON_ONCE(args.fsbno == NULLFSBLOCK)) { if (WARN_ON_ONCE(args.fsbno == NULLFSBLOCK)) {
error = -ENOSPC; error = -ENOSPC;
goto out_root_realloc; goto out_root_realloc;
} }
/*
* Allocation can't fail, the space was reserved.
*/
ASSERT(tp->t_firstblock == NULLFSBLOCK ||
args.agno >= XFS_FSB_TO_AGNO(mp, tp->t_firstblock));
tp->t_firstblock = args.fsbno;
cur->bc_ino.allocated++; cur->bc_ino.allocated++;
ip->i_nblocks++; ip->i_nblocks++;
xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, 1L); xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, 1L);
@ -804,13 +794,8 @@ xfs_bmap_local_to_extents(
* Allocate a block. We know we need only one, since the * Allocate a block. We know we need only one, since the
* file currently fits in an inode. * file currently fits in an inode.
*/ */
if (tp->t_firstblock == NULLFSBLOCK) {
args.fsbno = XFS_INO_TO_FSB(args.mp, ip->i_ino); args.fsbno = XFS_INO_TO_FSB(args.mp, ip->i_ino);
args.type = XFS_ALLOCTYPE_START_BNO; args.type = XFS_ALLOCTYPE_START_BNO;
} else {
args.fsbno = tp->t_firstblock;
args.type = XFS_ALLOCTYPE_NEAR_BNO;
}
args.total = total; args.total = total;
args.minlen = args.maxlen = args.prod = 1; args.minlen = args.maxlen = args.prod = 1;
error = xfs_alloc_vextent(&args); error = xfs_alloc_vextent(&args);
@ -820,7 +805,6 @@ xfs_bmap_local_to_extents(
/* Can't fail, the space was reserved. */ /* Can't fail, the space was reserved. */
ASSERT(args.fsbno != NULLFSBLOCK); ASSERT(args.fsbno != NULLFSBLOCK);
ASSERT(args.len == 1); ASSERT(args.len == 1);
tp->t_firstblock = args.fsbno;
error = xfs_trans_get_buf(tp, args.mp->m_ddev_targp, error = xfs_trans_get_buf(tp, args.mp->m_ddev_targp,
XFS_FSB_TO_DADDR(args.mp, args.fsbno), XFS_FSB_TO_DADDR(args.mp, args.fsbno),
args.mp->m_bsize, 0, &bp); args.mp->m_bsize, 0, &bp);
@ -854,8 +838,7 @@ xfs_bmap_local_to_extents(
ifp->if_nextents = 1; ifp->if_nextents = 1;
ip->i_nblocks = 1; ip->i_nblocks = 1;
xfs_trans_mod_dquot_byino(tp, ip, xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, 1L);
XFS_TRANS_DQ_BCOUNT, 1L);
flags |= xfs_ilog_fext(whichfork); flags |= xfs_ilog_fext(whichfork);
done: done:
@ -3025,9 +3008,7 @@ xfs_bmap_adjacent(
struct xfs_bmalloca *ap) /* bmap alloc argument struct */ struct xfs_bmalloca *ap) /* bmap alloc argument struct */
{ {
xfs_fsblock_t adjust; /* adjustment to block numbers */ xfs_fsblock_t adjust; /* adjustment to block numbers */
xfs_agnumber_t fb_agno; /* ag number of ap->firstblock */
xfs_mount_t *mp; /* mount point structure */ xfs_mount_t *mp; /* mount point structure */
int nullfb; /* true if ap->firstblock isn't set */
int rt; /* true if inode is realtime */ int rt; /* true if inode is realtime */
#define ISVALID(x,y) \ #define ISVALID(x,y) \
@ -3038,11 +3019,8 @@ xfs_bmap_adjacent(
XFS_FSB_TO_AGBNO(mp, x) < mp->m_sb.sb_agblocks) XFS_FSB_TO_AGBNO(mp, x) < mp->m_sb.sb_agblocks)
mp = ap->ip->i_mount; mp = ap->ip->i_mount;
nullfb = ap->tp->t_firstblock == NULLFSBLOCK;
rt = XFS_IS_REALTIME_INODE(ap->ip) && rt = XFS_IS_REALTIME_INODE(ap->ip) &&
(ap->datatype & XFS_ALLOC_USERDATA); (ap->datatype & XFS_ALLOC_USERDATA);
fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp,
ap->tp->t_firstblock);
/* /*
* If allocating at eof, and there's a previous real block, * If allocating at eof, and there's a previous real block,
* try to use its last block as our starting point. * try to use its last block as our starting point.
@ -3101,13 +3079,6 @@ xfs_bmap_adjacent(
prevbno += adjust; prevbno += adjust;
else else
prevdiff += adjust; prevdiff += adjust;
/*
* If the firstblock forbids it, can't use it,
* must use default.
*/
if (!rt && !nullfb &&
XFS_FSB_TO_AGNO(mp, prevbno) != fb_agno)
prevbno = NULLFSBLOCK;
} }
/* /*
* No previous block or can't follow it, just default. * No previous block or can't follow it, just default.
@ -3143,13 +3114,6 @@ xfs_bmap_adjacent(
gotdiff += adjust - ap->length; gotdiff += adjust - ap->length;
} else } else
gotdiff += adjust; gotdiff += adjust;
/*
* If the firstblock forbids it, can't use it,
* must use default.
*/
if (!rt && !nullfb &&
XFS_FSB_TO_AGNO(mp, gotbno) != fb_agno)
gotbno = NULLFSBLOCK;
} }
/* /*
* No next block, just default. * No next block, just default.
@ -3236,7 +3200,7 @@ xfs_bmap_select_minlen(
} }
STATIC int STATIC int
xfs_bmap_btalloc_nullfb( 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)
@ -3247,8 +3211,13 @@ xfs_bmap_btalloc_nullfb(
int error; int error;
args->type = XFS_ALLOCTYPE_START_BNO; args->type = XFS_ALLOCTYPE_START_BNO;
args->total = ap->total; if (ap->tp->t_flags & XFS_TRANS_LOWMODE) {
args->total = ap->minlen;
args->minlen = ap->minlen;
return 0;
}
args->total = ap->total;
startag = ag = XFS_FSB_TO_AGNO(mp, args->fsbno); startag = ag = XFS_FSB_TO_AGNO(mp, args->fsbno);
if (startag == NULLAGNUMBER) if (startag == NULLAGNUMBER)
startag = ag = 0; startag = ag = 0;
@ -3280,6 +3249,13 @@ xfs_bmap_btalloc_filestreams(
int notinit = 0; int notinit = 0;
int error; int error;
if (ap->tp->t_flags & XFS_TRANS_LOWMODE) {
args->type = XFS_ALLOCTYPE_FIRST_AG;
args->total = ap->minlen;
args->minlen = ap->minlen;
return 0;
}
args->type = XFS_ALLOCTYPE_NEAR_BNO; args->type = XFS_ALLOCTYPE_NEAR_BNO;
args->total = ap->total; args->total = ap->total;
@ -3460,7 +3436,6 @@ xfs_bmap_exact_minlen_extent_alloc(
xfs_bmap_compute_alignments(ap, &args); xfs_bmap_compute_alignments(ap, &args);
if (ap->tp->t_firstblock == NULLFSBLOCK) {
/* /*
* Unlike the longest extent available in an AG, we don't track * Unlike the longest extent available in an AG, we don't track
* the length of an AG's shortest extent. * the length of an AG's shortest extent.
@ -3470,9 +3445,6 @@ xfs_bmap_exact_minlen_extent_alloc(
* "debug only" code paths. * "debug only" code paths.
*/ */
ap->blkno = XFS_AGB_TO_FSB(mp, 0, 0); ap->blkno = XFS_AGB_TO_FSB(mp, 0, 0);
} else {
ap->blkno = ap->tp->t_firstblock;
}
args.fsbno = ap->blkno; args.fsbno = ap->blkno;
args.oinfo = XFS_RMAP_OINFO_SKIP_UPDATE; args.oinfo = XFS_RMAP_OINFO_SKIP_UPDATE;
@ -3515,13 +3487,11 @@ xfs_bmap_btalloc(
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 = { .tp = ap->tp, .mp = mp };
xfs_alloctype_t atype = 0; xfs_alloctype_t atype = 0;
xfs_agnumber_t fb_agno; /* ag number of ap->firstblock */
xfs_agnumber_t ag; xfs_agnumber_t ag;
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 blen;
xfs_extlen_t nextminlen = 0; xfs_extlen_t nextminlen = 0;
int nullfb; /* true if ap->firstblock isn't set */
int isaligned; int isaligned;
int tryagain; int tryagain;
int error; int error;
@ -3533,10 +3503,6 @@ xfs_bmap_btalloc(
stripe_align = xfs_bmap_compute_alignments(ap, &args); stripe_align = xfs_bmap_compute_alignments(ap, &args);
nullfb = ap->tp->t_firstblock == NULLFSBLOCK;
fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp,
ap->tp->t_firstblock);
if (nullfb) {
if ((ap->datatype & XFS_ALLOC_USERDATA) && if ((ap->datatype & XFS_ALLOC_USERDATA) &&
xfs_inode_is_filestream(ap->ip)) { xfs_inode_is_filestream(ap->ip)) {
ag = xfs_filestream_lookup_ag(ap->ip); ag = xfs_filestream_lookup_ag(ap->ip);
@ -3545,22 +3511,9 @@ xfs_bmap_btalloc(
} else { } else {
ap->blkno = XFS_INO_TO_FSB(mp, ap->ip->i_ino); ap->blkno = XFS_INO_TO_FSB(mp, ap->ip->i_ino);
} }
} else
ap->blkno = ap->tp->t_firstblock;
xfs_bmap_adjacent(ap); xfs_bmap_adjacent(ap);
/*
* If allowed, use ap->blkno; otherwise must use firstblock since
* it's in the right allocation group.
*/
if (nullfb || XFS_FSB_TO_AGNO(mp, ap->blkno) == fb_agno)
;
else
ap->blkno = ap->tp->t_firstblock;
/*
* Normal allocation, done through xfs_alloc_vextent.
*/
tryagain = isaligned = 0; tryagain = isaligned = 0;
args.fsbno = ap->blkno; args.fsbno = ap->blkno;
args.oinfo = XFS_RMAP_OINFO_SKIP_UPDATE; args.oinfo = XFS_RMAP_OINFO_SKIP_UPDATE;
@ -3568,7 +3521,7 @@ xfs_bmap_btalloc(
/* 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; blen = 0;
if (nullfb) {
/* /*
* Search for an allocation group with a single extent large * Search for an allocation group with a single extent large
* enough for the request. If one isn't found, then adjust * enough for the request. If one isn't found, then adjust
@ -3578,20 +3531,9 @@ xfs_bmap_btalloc(
xfs_inode_is_filestream(ap->ip)) xfs_inode_is_filestream(ap->ip))
error = xfs_bmap_btalloc_filestreams(ap, &args, &blen); error = xfs_bmap_btalloc_filestreams(ap, &args, &blen);
else else
error = xfs_bmap_btalloc_nullfb(ap, &args, &blen); error = xfs_bmap_btalloc_select_lengths(ap, &args, &blen);
if (error) if (error)
return error; return error;
} else if (ap->tp->t_flags & XFS_TRANS_LOWMODE) {
if (xfs_inode_is_filestream(ap->ip))
args.type = XFS_ALLOCTYPE_FIRST_AG;
else
args.type = XFS_ALLOCTYPE_START_BNO;
args.total = args.minlen = ap->minlen;
} else {
args.type = XFS_ALLOCTYPE_NEAR_BNO;
args.total = ap->total;
args.minlen = ap->minlen;
}
/* /*
* If we are not low on available data blocks, and the underlying * If we are not low on available data blocks, and the underlying
@ -3678,7 +3620,7 @@ xfs_bmap_btalloc(
if ((error = xfs_alloc_vextent(&args))) if ((error = xfs_alloc_vextent(&args)))
return error; return error;
} }
if (args.fsbno == NULLFSBLOCK && nullfb && if (args.fsbno == NULLFSBLOCK &&
args.minlen > ap->minlen) { args.minlen > ap->minlen) {
args.minlen = ap->minlen; args.minlen = ap->minlen;
args.type = XFS_ALLOCTYPE_START_BNO; args.type = XFS_ALLOCTYPE_START_BNO;
@ -3686,7 +3628,7 @@ xfs_bmap_btalloc(
if ((error = xfs_alloc_vextent(&args))) if ((error = xfs_alloc_vextent(&args)))
return error; return error;
} }
if (args.fsbno == NULLFSBLOCK && nullfb) { if (args.fsbno == NULLFSBLOCK) {
args.fsbno = 0; args.fsbno = 0;
args.type = XFS_ALLOCTYPE_FIRST_AG; args.type = XFS_ALLOCTYPE_FIRST_AG;
args.total = ap->minlen; args.total = ap->minlen;

View File

@ -206,28 +206,21 @@ xfs_bmbt_alloc_block(
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
args.tp = cur->bc_tp; args.tp = cur->bc_tp;
args.mp = cur->bc_mp; args.mp = cur->bc_mp;
args.fsbno = cur->bc_tp->t_firstblock;
xfs_rmap_ino_bmbt_owner(&args.oinfo, cur->bc_ino.ip->i_ino, xfs_rmap_ino_bmbt_owner(&args.oinfo, cur->bc_ino.ip->i_ino,
cur->bc_ino.whichfork); cur->bc_ino.whichfork);
if (args.fsbno == NULLFSBLOCK) {
args.fsbno = be64_to_cpu(start->l); args.fsbno = be64_to_cpu(start->l);
args.type = XFS_ALLOCTYPE_START_BNO; args.type = XFS_ALLOCTYPE_START_BNO;
/* /*
* If we are coming here from something like unwritten extent * If we are coming here from something like unwritten extent
* conversion, there has been no data extent allocation already * conversion, there has been no data extent allocation already done, so
* done, so we have to ensure that we attempt to locate the * we have to ensure that we attempt to locate the entire set of bmbt
* entire set of bmbt allocations in the same AG, as * allocations in the same AG, as xfs_bmapi_write() would have reserved.
* xfs_bmapi_write() would have reserved.
*/ */
if (cur->bc_tp->t_firstblock == NULLFSBLOCK)
args.minleft = xfs_bmapi_minleft(cur->bc_tp, cur->bc_ino.ip, args.minleft = xfs_bmapi_minleft(cur->bc_tp, cur->bc_ino.ip,
cur->bc_ino.whichfork); cur->bc_ino.whichfork);
} else if (cur->bc_tp->t_flags & XFS_TRANS_LOWMODE) {
args.type = XFS_ALLOCTYPE_START_BNO;
} else {
args.type = XFS_ALLOCTYPE_NEAR_BNO;
}
args.minlen = args.maxlen = args.prod = 1; args.minlen = args.maxlen = args.prod = 1;
args.wasdel = cur->bc_ino.flags & XFS_BTCUR_BMBT_WASDEL; args.wasdel = cur->bc_ino.flags & XFS_BTCUR_BMBT_WASDEL;
@ -247,7 +240,7 @@ xfs_bmbt_alloc_block(
*/ */
args.fsbno = 0; args.fsbno = 0;
args.minleft = 0; args.minleft = 0;
args.type = XFS_ALLOCTYPE_FIRST_AG; args.type = XFS_ALLOCTYPE_START_BNO;
error = xfs_alloc_vextent(&args); error = xfs_alloc_vextent(&args);
if (error) if (error)
goto error0; goto error0;
@ -259,7 +252,6 @@ xfs_bmbt_alloc_block(
} }
ASSERT(args.len == 1); ASSERT(args.len == 1);
cur->bc_tp->t_firstblock = args.fsbno;
cur->bc_ino.allocated++; cur->bc_ino.allocated++;
cur->bc_ino.ip->i_nblocks++; cur->bc_ino.ip->i_nblocks++;
xfs_trans_log_inode(args.tp, cur->bc_ino.ip, XFS_ILOG_CORE); xfs_trans_log_inode(args.tp, cur->bc_ino.ip, XFS_ILOG_CORE);