aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2012-03-22 01:15:07 -0400
committerBen Myers <bpm@sgi.com>2012-03-22 17:12:24 -0400
commitc999a223c2f0d31c64ef7379814cea1378b2b800 (patch)
treeed699c3c98075bbfc4aed0ab22bd174e65e575a8 /fs/xfs
parent1a1d772433d42aaff7315b3468fef5951604f5c6 (diff)
xfs: introduce an allocation workqueue
We currently have significant issues with the amount of stack that allocation in XFS uses, especially in the writeback path. We can easily consume 4k of stack between mapping the page, manipulating the bmap btree and allocating blocks from the free list. Not to mention btree block readahead and other functionality that issues IO in the allocation path. As a result, we can no longer fit allocation in the writeback path in the stack space provided on x86_64. To alleviate this problem, introduce an allocation workqueue and move all allocations to a seperate context. This can be easily added as an interposing layer into xfs_alloc_vextent(), which takes a single argument structure and does not return until the allocation is complete or has failed. To do this, add a work structure and a completion to the allocation args structure. This allows xfs_alloc_vextent to queue the args onto the workqueue and wait for it to be completed by the worker. This can be done completely transparently to the caller. The worker function needs to ensure that it sets and clears the PF_TRANS flag appropriately as it is being run in an active transaction context. Work can also be queued in a memory reclaim context, so a rescuer is needed for the workqueue. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/xfs_alloc.c34
-rw-r--r--fs/xfs/xfs_alloc.h5
-rw-r--r--fs/xfs/xfs_super.c16
3 files changed, 54 insertions, 1 deletions
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c
index ce84ffd0264c..31e90335b83d 100644
--- a/fs/xfs/xfs_alloc.c
+++ b/fs/xfs/xfs_alloc.c
@@ -35,6 +35,7 @@
35#include "xfs_error.h" 35#include "xfs_error.h"
36#include "xfs_trace.h" 36#include "xfs_trace.h"
37 37
38struct workqueue_struct *xfs_alloc_wq;
38 39
39#define XFS_ABSDIFF(a,b) (((a) <= (b)) ? ((b) - (a)) : ((a) - (b))) 40#define XFS_ABSDIFF(a,b) (((a) <= (b)) ? ((b) - (a)) : ((a) - (b)))
40 41
@@ -2207,7 +2208,7 @@ xfs_alloc_read_agf(
2207 * group or loop over the allocation groups to find the result. 2208 * group or loop over the allocation groups to find the result.
2208 */ 2209 */
2209int /* error */ 2210int /* error */
2210xfs_alloc_vextent( 2211__xfs_alloc_vextent(
2211 xfs_alloc_arg_t *args) /* allocation argument structure */ 2212 xfs_alloc_arg_t *args) /* allocation argument structure */
2212{ 2213{
2213 xfs_agblock_t agsize; /* allocation group size */ 2214 xfs_agblock_t agsize; /* allocation group size */
@@ -2417,6 +2418,37 @@ error0:
2417 return error; 2418 return error;
2418} 2419}
2419 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
2439int /* error */
2440xfs_alloc_vextent(
2441 xfs_alloc_arg_t *args) /* allocation argument structure */
2442{
2443 DECLARE_COMPLETION_ONSTACK(done);
2444
2445 args->done = &done;
2446 INIT_WORK(&args->work, xfs_alloc_vextent_worker);
2447 queue_work(xfs_alloc_wq, &args->work);
2448 wait_for_completion(&done);
2449 return args->result;
2450}
2451
2420/* 2452/*
2421 * Free an extent. 2453 * Free an extent.
2422 * Just break up the extent address and hand off to xfs_free_ag_extent 2454 * Just break up the extent address and hand off to xfs_free_ag_extent
diff --git a/fs/xfs/xfs_alloc.h b/fs/xfs/xfs_alloc.h
index 2f52b924be79..ab5d0fd2f535 100644
--- a/fs/xfs/xfs_alloc.h
+++ b/fs/xfs/xfs_alloc.h
@@ -25,6 +25,8 @@ struct xfs_perag;
25struct xfs_trans; 25struct xfs_trans;
26struct xfs_busy_extent; 26struct xfs_busy_extent;
27 27
28extern struct workqueue_struct *xfs_alloc_wq;
29
28/* 30/*
29 * Freespace allocation types. Argument to xfs_alloc_[v]extent. 31 * Freespace allocation types. Argument to xfs_alloc_[v]extent.
30 */ 32 */
@@ -119,6 +121,9 @@ typedef struct xfs_alloc_arg {
119 char isfl; /* set if is freelist blocks - !acctg */ 121 char isfl; /* set if is freelist blocks - !acctg */
120 char userdata; /* set if this is user data */ 122 char userdata; /* set if this is user data */
121 xfs_fsblock_t firstblock; /* io first block allocated */ 123 xfs_fsblock_t firstblock; /* io first block allocated */
124 struct completion *done;
125 struct work_struct work;
126 int result;
122} xfs_alloc_arg_t; 127} xfs_alloc_arg_t;
123 128
124/* 129/*
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 06d23b976f4c..5484888d39c4 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -1607,12 +1607,28 @@ xfs_init_workqueues(void)
1607 xfs_syncd_wq = alloc_workqueue("xfssyncd", WQ_NON_REENTRANT, 0); 1607 xfs_syncd_wq = alloc_workqueue("xfssyncd", WQ_NON_REENTRANT, 0);
1608 if (!xfs_syncd_wq) 1608 if (!xfs_syncd_wq)
1609 return -ENOMEM; 1609 return -ENOMEM;
1610
1611 /*
1612 * The allocation workqueue can be used in memory reclaim situations
1613 * (writepage path), and parallelism is only limited by the number of
1614 * AGs in all the filesystems mounted. Hence use the default large
1615 * max_active value for this workqueue.
1616 */
1617 xfs_alloc_wq = alloc_workqueue("xfsalloc", WQ_MEM_RECLAIM, 0);
1618 if (!xfs_alloc_wq)
1619 goto out_destroy_syncd;
1620
1610 return 0; 1621 return 0;
1622
1623out_destroy_syncd:
1624 destroy_workqueue(xfs_syncd_wq);
1625 return -ENOMEM;
1611} 1626}
1612 1627
1613STATIC void 1628STATIC void
1614xfs_destroy_workqueues(void) 1629xfs_destroy_workqueues(void)
1615{ 1630{
1631 destroy_workqueue(xfs_alloc_wq);
1616 destroy_workqueue(xfs_syncd_wq); 1632 destroy_workqueue(xfs_syncd_wq);
1617} 1633}
1618 1634