diff options
Diffstat (limited to 'fs/xfs/libxfs/xfs_alloc.c')
-rw-r--r-- | fs/xfs/libxfs/xfs_alloc.c | 120 |
1 files changed, 76 insertions, 44 deletions
diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c index 5093fa856f35..dc1b6c6e1de7 100644 --- a/fs/xfs/libxfs/xfs_alloc.c +++ b/fs/xfs/libxfs/xfs_alloc.c @@ -1144,31 +1144,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. */ @@ -3201,11 +3178,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 || @@ -3218,6 +3202,41 @@ xfs_alloc_vextent_check_args( } /* + * 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); + args->agbno = NULLAGBLOCK; + 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. * @@ -3268,7 +3287,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( @@ -3301,7 +3321,10 @@ xfs_alloc_vextent_this_ag( args->fsbno = target; args->type = XFS_ALLOCTYPE_THIS_AG; - error = xfs_alloc_ag_vextent(args); + error = xfs_alloc_vextent_prepare_ag(args); + if (!error && args->agbp) + error = xfs_alloc_ag_vextent(args); + xfs_alloc_vextent_set_fsbno(args, minimum_agno); return error; } @@ -3339,13 +3362,19 @@ 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->agbno = NULLAGBLOCK; + args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno); + error = xfs_alloc_vextent_prepare_ag(args); + if (error) break; - } - if (args->agbp) + + 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); @@ -3378,10 +3407,8 @@ 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; @@ -3485,7 +3512,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( @@ -3515,9 +3543,10 @@ 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); - if (error) - return error; + + error = xfs_alloc_vextent_prepare_ag(args); + if (!error && args->agbp) + error = xfs_alloc_ag_vextent(args); xfs_alloc_vextent_set_fsbno(args, minimum_agno); return 0; @@ -3526,6 +3555,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( @@ -3550,21 +3581,22 @@ xfs_alloc_vextent_near_bno( args->agno = XFS_FSB_TO_AGNO(mp, target); if (minimum_agno > args->agno) { trace_xfs_alloc_vextent_skip_deadlock(args); + args->fsbno = NULLFSBLOCK; return 0; } 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 && args->agbp) + error = xfs_alloc_ag_vextent(args); + + xfs_alloc_vextent_set_fsbno(args, minimum_agno); if (need_pag) xfs_perag_put(args->pag); - if (error) - return error; - xfs_alloc_vextent_set_fsbno(args, minimum_agno); - return 0; + return error; } /* Ensure that the freelist is at full capacity. */ |