diff options
Diffstat (limited to 'fs/xfs/libxfs/xfs_alloc.c')
-rw-r--r-- | fs/xfs/libxfs/xfs_alloc.c | 50 |
1 files changed, 31 insertions, 19 deletions
diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c index 008b3622b286..85e3b65286ac 100644 --- a/fs/xfs/libxfs/xfs_alloc.c +++ b/fs/xfs/libxfs/xfs_alloc.c @@ -3479,35 +3479,47 @@ xfs_alloc_vextent_first_ag( } /* - * Allocate an extent (variable-size). - * Depending on the allocation type, we either look in a single allocation - * group or loop over the allocation groups to find the result. + * Allocate an extent as close to the target as possible. If there are not + * viable candidates in the AG, then fail the allocation. */ int -xfs_alloc_vextent( - struct xfs_alloc_arg *args) +xfs_alloc_vextent_near_bno( + struct xfs_alloc_arg *args, + xfs_fsblock_t target) { + struct xfs_mount *mp = args->mp; + bool need_pag = !args->pag; xfs_agnumber_t minimum_agno = 0; int error; if (args->tp->t_highest_agno != NULLAGNUMBER) minimum_agno = args->tp->t_highest_agno; - switch (args->type) { - case XFS_ALLOCTYPE_THIS_AG: - case XFS_ALLOCTYPE_NEAR_BNO: - case XFS_ALLOCTYPE_THIS_BNO: - args->pag = xfs_perag_get(args->mp, - XFS_FSB_TO_AGNO(args->mp, args->fsbno)); - error = xfs_alloc_vextent_this_ag(args); - xfs_perag_put(args->pag); - break; - default: - error = -EFSCORRUPTED; - ASSERT(0); - break; + error = xfs_alloc_vextent_check_args(args, target); + if (error) { + if (error == -ENOSPC) + return 0; + return error; } - return error; + + args->agno = XFS_FSB_TO_AGNO(mp, target); + if (minimum_agno > args->agno) { + trace_xfs_alloc_vextent_skip_deadlock(args); + 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); + if (need_pag) + xfs_perag_put(args->pag); + if (error) + return error; + + xfs_alloc_vextent_set_fsbno(args, minimum_agno); + return 0; } /* Ensure that the freelist is at full capacity. */ |