@@ -1148,31 +1148,8 @@ static int
xfs_alloc_ag_vextent(
struct xfs_alloc_arg *args)
{
- struct xfs_mount *mp = args->mp;
int error = 0;
- ASSERT(args->minlen > 0);
- ASSERT(args->maxlen > 0);
- ASSERT(args->minlen <= args->maxlen);
- ASSERT(args->mod < args->prod);
- ASSERT(args->alignment > 0);
- ASSERT(args->resv != XFS_AG_RESV_AGFL);
-
-
- error = xfs_alloc_fix_freelist(args, 0);
- if (error) {
- trace_xfs_alloc_vextent_nofix(args);
- return error;
- }
- if (!args->agbp) {
- /* cannot allocate in this AG at all */
- trace_xfs_alloc_vextent_noagbp(args);
- args->agbno = NULLAGBLOCK;
- return 0;
- }
- args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno);
- args->wasfromfl = 0;
-
/*
* Branch to correct routine based on the type.
*/
@@ -3204,11 +3181,18 @@ xfs_alloc_vextent_check_args(
args->maxlen = agsize;
if (args->alignment == 0)
args->alignment = 1;
+
+ ASSERT(args->minlen > 0);
+ ASSERT(args->maxlen > 0);
+ ASSERT(args->alignment > 0);
+ ASSERT(args->resv != XFS_AG_RESV_AGFL);
+
ASSERT(XFS_FSB_TO_AGNO(mp, target) < mp->m_sb.sb_agcount);
ASSERT(XFS_FSB_TO_AGBNO(mp, target) < agsize);
ASSERT(args->minlen <= args->maxlen);
ASSERT(args->minlen <= agsize);
ASSERT(args->mod < args->prod);
+
if (XFS_FSB_TO_AGNO(mp, target) >= mp->m_sb.sb_agcount ||
XFS_FSB_TO_AGBNO(mp, target) >= agsize ||
args->minlen > args->maxlen || args->minlen > agsize ||
@@ -3220,6 +3204,40 @@ xfs_alloc_vextent_check_args(
return 0;
}
+/*
+ * Prepare an AG for allocation. If the AG is not prepared to accept the
+ * allocation, return failure.
+ *
+ * XXX(dgc): The complexity of "need_pag" will go away as all caller paths are
+ * modified to hold their own perag references.
+ */
+static int
+xfs_alloc_vextent_prepare_ag(
+ struct xfs_alloc_arg *args)
+{
+ bool need_pag = !args->pag;
+ int error;
+
+ if (need_pag)
+ args->pag = xfs_perag_get(args->mp, args->agno);
+
+ error = xfs_alloc_fix_freelist(args, 0);
+ if (error) {
+ trace_xfs_alloc_vextent_nofix(args);
+ if (need_pag)
+ xfs_perag_put(args->pag);
+ return error;
+ }
+ if (!args->agbp) {
+ /* cannot allocate in this AG at all */
+ trace_xfs_alloc_vextent_noagbp(args);
+ args->agbno = NULLAGBLOCK;
+ return 0;
+ }
+ args->wasfromfl = 0;
+ return 0;
+}
+
/*
* Post-process allocation results to set the allocated block number correctly
* for the caller.
@@ -3249,7 +3267,8 @@ xfs_alloc_vextent_set_fsbno(
}
/*
- * Allocate within a single AG only.
+ * Allocate within a single AG only. Caller is expected to hold a
+ * perag reference in args->pag.
*/
int
xfs_alloc_vextent_this_ag(
@@ -3271,10 +3290,16 @@ xfs_alloc_vextent_this_ag(
args->agbno = 0;
args->fsbno = target;
args->type = XFS_ALLOCTYPE_THIS_AG;
- error = xfs_alloc_ag_vextent(args);
+ error = xfs_alloc_vextent_prepare_ag(args);
if (error)
return error;
+ if (args->agbp) {
+ error = xfs_alloc_ag_vextent(args);
+ if (error)
+ return error;
+ }
+
xfs_alloc_vextent_set_fsbno(args);
return 0;
}
@@ -3312,16 +3337,27 @@ xfs_alloc_vextent_iterate_ags(
*/
args->agno = start_agno;
for (;;) {
- args->pag = xfs_perag_get(mp, args->agno);
- error = xfs_alloc_ag_vextent(args);
- if (error || args->agbp)
+ args->pag = xfs_perag_get(args->mp, args->agno);
+ args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno);
+ error = xfs_alloc_vextent_prepare_ag(args);
+ if (error)
break;
+ if (args->agbp) {
+ /*
+ * Allocation is supposed to succeed now, so break out
+ * of the loop regardless of whether we succeed or not.
+ */
+ error = xfs_alloc_ag_vextent(args);
+ break;
+ }
+
trace_xfs_alloc_vextent_loopfailed(args);
if (args->agno == start_agno &&
args->otype == XFS_ALLOCTYPE_NEAR_BNO)
args->type = XFS_ALLOCTYPE_THIS_AG;
+
/*
* For the first allocation, we can try any AG to get
* space. However, if we already have allocated a
@@ -3347,14 +3383,14 @@ xfs_alloc_vextent_iterate_ags(
}
flags = 0;
- if (args->otype == XFS_ALLOCTYPE_NEAR_BNO) {
- args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno);
+ if (args->otype == XFS_ALLOCTYPE_NEAR_BNO)
args->type = XFS_ALLOCTYPE_NEAR_BNO;
- }
}
xfs_perag_put(args->pag);
+ args->pag = NULL;
}
xfs_perag_put(args->pag);
+ args->pag = NULL;
return error;
}
@@ -3447,7 +3483,8 @@ xfs_alloc_vextent_first_ag(
}
/*
- * Allocate within a single AG only.
+ * Allocate at the exact block target or fail. Caller is expected to hold a
+ * perag reference in args->pag.
*/
int
xfs_alloc_vextent_exact_bno(
@@ -3468,10 +3505,17 @@ xfs_alloc_vextent_exact_bno(
args->agbno = XFS_FSB_TO_AGBNO(mp, target);
args->fsbno = target;
args->type = XFS_ALLOCTYPE_THIS_BNO;
- error = xfs_alloc_ag_vextent(args);
+
+ error = xfs_alloc_vextent_prepare_ag(args);
if (error)
return error;
+ if (args->agbp) {
+ error = xfs_alloc_ag_vextent(args);
+ if (error)
+ return error;
+ }
+
xfs_alloc_vextent_set_fsbno(args);
return 0;
}
@@ -3479,6 +3523,8 @@ xfs_alloc_vextent_exact_bno(
/*
* Allocate an extent as close to the target as possible. If there are not
* viable candidates in the AG, then fail the allocation.
+ *
+ * Caller may or may not have a per-ag reference in args->pag.
*/
int
xfs_alloc_vextent_near_bno(
@@ -3499,9 +3545,13 @@ xfs_alloc_vextent_near_bno(
args->agno = XFS_FSB_TO_AGNO(mp, target);
args->agbno = XFS_FSB_TO_AGBNO(mp, target);
args->type = XFS_ALLOCTYPE_NEAR_BNO;
- if (need_pag)
- args->pag = xfs_perag_get(args->mp, args->agno);
- error = xfs_alloc_ag_vextent(args);
+
+ error = xfs_alloc_vextent_prepare_ag(args);
+ if (error)
+ return error;
+
+ if (args->agbp)
+ error = xfs_alloc_ag_vextent(args);
if (need_pag)
xfs_perag_put(args->pag);
if (error)