Commit 3432ef61 authored by Dave Chinner's avatar Dave Chinner

xfs: convert xfs_alloc_vextent_iterate_ags() to use perag walker

Now that the AG iteration code in the core allocation code has been
cleaned up, we can easily convert it to use a for_each_perag..()
variant to use active references and skip AGs that it can't get
active references on.
Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarDarrick J. Wong <djwong@kernel.org>
parent 8b813568
...@@ -253,6 +253,7 @@ xfs_perag_next_wrap( ...@@ -253,6 +253,7 @@ xfs_perag_next_wrap(
struct xfs_perag *pag, struct xfs_perag *pag,
xfs_agnumber_t *agno, xfs_agnumber_t *agno,
xfs_agnumber_t stop_agno, xfs_agnumber_t stop_agno,
xfs_agnumber_t restart_agno,
xfs_agnumber_t wrap_agno) xfs_agnumber_t wrap_agno)
{ {
struct xfs_mount *mp = pag->pag_mount; struct xfs_mount *mp = pag->pag_mount;
...@@ -260,10 +261,11 @@ xfs_perag_next_wrap( ...@@ -260,10 +261,11 @@ xfs_perag_next_wrap(
*agno = pag->pag_agno + 1; *agno = pag->pag_agno + 1;
xfs_perag_rele(pag); xfs_perag_rele(pag);
while (*agno != stop_agno) { while (*agno != stop_agno) {
if (*agno >= wrap_agno) if (*agno >= wrap_agno) {
*agno = 0; if (restart_agno >= stop_agno)
if (*agno == stop_agno)
break; break;
*agno = restart_agno;
}
pag = xfs_perag_grab(mp, *agno); pag = xfs_perag_grab(mp, *agno);
if (pag) if (pag)
...@@ -274,14 +276,20 @@ xfs_perag_next_wrap( ...@@ -274,14 +276,20 @@ xfs_perag_next_wrap(
} }
/* /*
* Iterate all AGs from start_agno through wrap_agno, then 0 through * Iterate all AGs from start_agno through wrap_agno, then restart_agno through
* (start_agno - 1). * (start_agno - 1).
*/ */
#define for_each_perag_wrap_at(mp, start_agno, wrap_agno, agno, pag) \ #define for_each_perag_wrap_range(mp, start_agno, restart_agno, wrap_agno, agno, pag) \
for ((agno) = (start_agno), (pag) = xfs_perag_grab((mp), (agno)); \ for ((agno) = (start_agno), (pag) = xfs_perag_grab((mp), (agno)); \
(pag) != NULL; \ (pag) != NULL; \
(pag) = xfs_perag_next_wrap((pag), &(agno), (start_agno), \ (pag) = xfs_perag_next_wrap((pag), &(agno), (start_agno), \
(wrap_agno))) (restart_agno), (wrap_agno)))
/*
* Iterate all AGs from start_agno through wrap_agno, then 0 through
* (start_agno - 1).
*/
#define for_each_perag_wrap_at(mp, start_agno, wrap_agno, agno, pag) \
for_each_perag_wrap_range((mp), (start_agno), 0, (wrap_agno), (agno), (pag))
/* /*
* Iterate all AGs from start_agno through to the end of the filesystem, then 0 * Iterate all AGs from start_agno through to the end of the filesystem, then 0
......
...@@ -3156,6 +3156,7 @@ xfs_alloc_vextent_prepare_ag( ...@@ -3156,6 +3156,7 @@ xfs_alloc_vextent_prepare_ag(
if (need_pag) if (need_pag)
args->pag = xfs_perag_get(args->mp, args->agno); args->pag = xfs_perag_get(args->mp, args->agno);
args->agbp = NULL;
error = xfs_alloc_fix_freelist(args, 0); error = xfs_alloc_fix_freelist(args, 0);
if (error) { if (error) {
trace_xfs_alloc_vextent_nofix(args); trace_xfs_alloc_vextent_nofix(args);
...@@ -3255,8 +3256,8 @@ xfs_alloc_vextent_finish( ...@@ -3255,8 +3256,8 @@ xfs_alloc_vextent_finish(
XFS_STATS_ADD(mp, xs_allocb, args->len); XFS_STATS_ADD(mp, xs_allocb, args->len);
out_drop_perag: out_drop_perag:
if (drop_perag) { if (drop_perag && args->pag) {
xfs_perag_put(args->pag); xfs_perag_rele(args->pag);
args->pag = NULL; args->pag = NULL;
} }
return error; return error;
...@@ -3304,6 +3305,10 @@ xfs_alloc_vextent_this_ag( ...@@ -3304,6 +3305,10 @@ xfs_alloc_vextent_this_ag(
* we attempt to allocation in as there is no locality optimisation possible for * we attempt to allocation in as there is no locality optimisation possible for
* those allocations. * those allocations.
* *
* On return, args->pag may be left referenced if we finish before the "all
* failed" return point. The allocation finish still needs the perag, and
* so the caller will release it once they've finished the allocation.
*
* When we wrap the AG iteration at the end of the filesystem, we have to be * When we wrap the AG iteration at the end of the filesystem, we have to be
* careful not to wrap into AGs below ones we already have locked in the * careful not to wrap into AGs below ones we already have locked in the
* transaction if we are doing a blocking iteration. This will result in an * transaction if we are doing a blocking iteration. This will result in an
...@@ -3318,25 +3323,24 @@ xfs_alloc_vextent_iterate_ags( ...@@ -3318,25 +3323,24 @@ xfs_alloc_vextent_iterate_ags(
uint32_t flags) uint32_t flags)
{ {
struct xfs_mount *mp = args->mp; struct xfs_mount *mp = args->mp;
xfs_agnumber_t agno;
int error = 0; int error = 0;
ASSERT(start_agno >= minimum_agno); restart:
for_each_perag_wrap_range(mp, start_agno, minimum_agno,
/* mp->m_sb.sb_agcount, agno, args->pag) {
* Loop over allocation groups twice; first time with args->agno = agno;
* trylock set, second time without.
*/
args->agno = start_agno;
for (;;) {
args->pag = xfs_perag_get(mp, args->agno);
error = xfs_alloc_vextent_prepare_ag(args); error = xfs_alloc_vextent_prepare_ag(args);
if (error) if (error)
break; break;
if (!args->agbp) {
trace_xfs_alloc_vextent_loopfailed(args);
continue;
}
if (args->agbp) {
/* /*
* Allocation is supposed to succeed now, so break out * Allocation is supposed to succeed now, so break out of the
* of the loop regardless of whether we succeed or not. * loop regardless of whether we succeed or not.
*/ */
if (args->agno == start_agno && target_agbno) { if (args->agno == start_agno && target_agbno) {
args->agbno = target_agbno; args->agbno = target_agbno;
...@@ -3347,43 +3351,27 @@ xfs_alloc_vextent_iterate_ags( ...@@ -3347,43 +3351,27 @@ xfs_alloc_vextent_iterate_ags(
} }
break; break;
} }
if (error) {
trace_xfs_alloc_vextent_loopfailed(args); xfs_perag_rele(args->pag);
args->pag = NULL;
/* return error;
* If we are try-locking, we can't deadlock on AGF locks so we
* can wrap all the way back to the first AG. Otherwise, wrap
* back to the start AG so we can't deadlock and let the end of
* scan handler decide what to do next.
*/
if (++(args->agno) == mp->m_sb.sb_agcount) {
if (flags & XFS_ALLOC_FLAG_TRYLOCK)
args->agno = 0;
else
args->agno = minimum_agno;
} }
if (args->agbp)
return 0;
/* /*
* Reached the starting a.g., must either be done * We didn't find an AG we can alloation from. If we were given
* or switch to non-trylock mode. * constraining flags by the caller, drop them and retry the allocation
* without any constraints being set.
*/ */
if (args->agno == start_agno) { if (flags) {
if (flags == 0) {
args->agbno = NULLAGBLOCK;
trace_xfs_alloc_vextent_allfailed(args);
break;
}
args->agbno = target_agbno;
flags = 0; flags = 0;
goto restart;
} }
xfs_perag_put(args->pag);
args->pag = NULL; ASSERT(args->pag == NULL);
} trace_xfs_alloc_vextent_allfailed(args);
/* return 0;
* The perag is left referenced in args for the caller to clean
* up after they've finished the allocation.
*/
return error;
} }
/* /*
...@@ -3524,7 +3512,7 @@ xfs_alloc_vextent_near_bno( ...@@ -3524,7 +3512,7 @@ xfs_alloc_vextent_near_bno(
} }
if (needs_perag) if (needs_perag)
args->pag = xfs_perag_get(mp, args->agno); args->pag = xfs_perag_grab(mp, args->agno);
error = xfs_alloc_vextent_prepare_ag(args); error = xfs_alloc_vextent_prepare_ag(args);
if (!error && args->agbp) if (!error && args->agbp)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment