aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_alloc.c
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2012-10-04 21:06:59 -0400
committerBen Myers <bpm@sgi.com>2012-10-18 18:42:48 -0400
commite04426b9202bccd4cfcbc70b2fa2aeca1c86d8f5 (patch)
tree2bab7921c9327c508d2ea207c9ef781a5df61874 /fs/xfs/xfs_alloc.c
parent2455881c0b52f87be539c4c7deab1afff4d8a560 (diff)
xfs: move allocation stack switch up to xfs_bmapi_allocate
Switching stacks are xfs_alloc_vextent can cause deadlocks when we run out of worker threads on the allocation workqueue. This can occur because xfs_bmap_btalloc can make multiple calls to xfs_alloc_vextent() and even if xfs_alloc_vextent() fails it can return with the AGF locked in the current allocation transaction. If we then need to make another allocation, and all the allocation worker contexts are exhausted because the are blocked waiting for the AGF lock, holder of the AGF cannot get it's xfs-alloc_vextent work completed to release the AGF. Hence allocation effectively deadlocks. To avoid this, move the stack switch one layer up to xfs_bmapi_allocate() so that all of the allocation attempts in a single switched stack transaction occur in a single worker context. This avoids the problem of an allocation being blocked waiting for a worker thread whilst holding the AGF. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Mark Tinguely <tinguely@sgi.com> Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_alloc.c')
-rw-r--r--fs/xfs/xfs_alloc.c42
1 files changed, 1 insertions, 41 deletions
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c
index 43f791bcd8b1..335206a9c698 100644
--- a/fs/xfs/xfs_alloc.c
+++ b/fs/xfs/xfs_alloc.c
@@ -2208,7 +2208,7 @@ xfs_alloc_read_agf(
2208 * group or loop over the allocation groups to find the result. 2208 * group or loop over the allocation groups to find the result.
2209 */ 2209 */
2210int /* error */ 2210int /* error */
2211__xfs_alloc_vextent( 2211xfs_alloc_vextent(
2212 xfs_alloc_arg_t *args) /* allocation argument structure */ 2212 xfs_alloc_arg_t *args) /* allocation argument structure */
2213{ 2213{
2214 xfs_agblock_t agsize; /* allocation group size */ 2214 xfs_agblock_t agsize; /* allocation group size */
@@ -2418,46 +2418,6 @@ error0:
2418 return error; 2418 return error;
2419} 2419}
2420 2420
2421static void
2422xfs_alloc_vextent_worker(
2423 struct work_struct *work)
2424{
2425 struct xfs_alloc_arg *args = container_of(work,
2426 struct xfs_alloc_arg, work);
2427 unsigned long pflags;
2428
2429 /* we are in a transaction context here */
2430 current_set_flags_nested(&pflags, PF_FSTRANS);
2431
2432 args->result = __xfs_alloc_vextent(args);
2433 complete(args->done);
2434
2435 current_restore_flags_nested(&pflags, PF_FSTRANS);
2436}
2437
2438/*
2439 * Data allocation requests often come in with little stack to work on. Push
2440 * them off to a worker thread so there is lots of stack to use. Metadata
2441 * requests, OTOH, are generally from low stack usage paths, so avoid the
2442 * context switch overhead here.
2443 */
2444int
2445xfs_alloc_vextent(
2446 struct xfs_alloc_arg *args)
2447{
2448 DECLARE_COMPLETION_ONSTACK(done);
2449
2450 if (!args->stack_switch)
2451 return __xfs_alloc_vextent(args);
2452
2453
2454 args->done = &done;
2455 INIT_WORK_ONSTACK(&args->work, xfs_alloc_vextent_worker);
2456 queue_work(xfs_alloc_wq, &args->work);
2457 wait_for_completion(&done);
2458 return args->result;
2459}
2460
2461/* 2421/*
2462 * Free an extent. 2422 * Free an extent.
2463 * Just break up the extent address and hand off to xfs_free_ag_extent 2423 * Just break up the extent address and hand off to xfs_free_ag_extent