xfs: introduce XFS_BMAPI_STACK_SWITCH
authorDave Chinner <dchinner@redhat.com>
Fri, 5 Oct 2012 01:06:58 +0000 (11:06 +1000)
committerBen Myers <bpm@sgi.com>
Thu, 18 Oct 2012 22:41:56 +0000 (17:41 -0500)
Certain allocation paths through xfs_bmapi_write() are in situations
where we have limited stack available. These are almost always in
the buffered IO writeback path when convertion delayed allocation
extents to real extents.

The current stack switch occurs for userdata allocations, which
means we also do stack switches for preallocation, direct IO and
unwritten extent conversion, even those these call chains have never
been implicated in a stack overrun.

Hence, let's target just the single stack overun offended for stack
switches. To do that, introduce a XFS_BMAPI_STACK_SWITCH flag that
the caller can pass xfs_bmapi_write() to indicate it should switch
stacks if it needs to do allocation.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Mark Tinguely <tinguely@sgi.com>
Signed-off-by: Ben Myers <bpm@sgi.com>
fs/xfs/xfs_alloc.c
fs/xfs/xfs_alloc.h
fs/xfs/xfs_bmap.c
fs/xfs/xfs_bmap.h
fs/xfs/xfs_iomap.c

index 0287f3b1b503c65488c877421289e54d714e7626..43f791bcd8b1b7dbf4053cdedf2856ee41d1eed0 100644 (file)
@@ -2447,7 +2447,7 @@ xfs_alloc_vextent(
 {
        DECLARE_COMPLETION_ONSTACK(done);
 
-       if (!args->userdata)
+       if (!args->stack_switch)
                return __xfs_alloc_vextent(args);
 
 
index 93be4a667ca1692648aec03195b5747bac4239f2..ef7d4885dc2d448ea9f4313b11324dad04ad0a76 100644 (file)
@@ -123,6 +123,7 @@ typedef struct xfs_alloc_arg {
        struct completion *done;
        struct work_struct work;
        int             result;
+       char            stack_switch;
 } xfs_alloc_arg_t;
 
 /*
index e1545ec2f7d2b118713460d2c722e80d7fc3571c..91259554df8b50053c9c141f290aac665811991c 100644 (file)
@@ -2441,6 +2441,7 @@ xfs_bmap_btalloc(
        args.tp = ap->tp;
        args.mp = mp;
        args.fsbno = ap->blkno;
+       args.stack_switch = ap->stack_switch;
 
        /* Trim the allocation back to the maximum an AG can fit. */
        args.maxlen = MIN(ap->length, XFS_ALLOC_AG_MAX_USABLE(mp));
@@ -4675,6 +4676,9 @@ xfs_bmapi_allocate(
                        return error;
        }
 
+       if (flags & XFS_BMAPI_STACK_SWITCH)
+               bma->stack_switch = 1;
+
        error = xfs_bmap_alloc(bma);
        if (error)
                return error;
index 803b56d7ce16a97b7e5eb8075ba4e7853e4b8d30..b68c598034c1513d02f4e2ad03c81e4850185460 100644 (file)
@@ -77,6 +77,7 @@ typedef       struct xfs_bmap_free
  * from written to unwritten, otherwise convert from unwritten to written.
  */
 #define XFS_BMAPI_CONVERT      0x040
+#define XFS_BMAPI_STACK_SWITCH 0x080
 
 #define XFS_BMAPI_FLAGS \
        { XFS_BMAPI_ENTIRE,     "ENTIRE" }, \
@@ -85,7 +86,8 @@ typedef       struct xfs_bmap_free
        { XFS_BMAPI_PREALLOC,   "PREALLOC" }, \
        { XFS_BMAPI_IGSTATE,    "IGSTATE" }, \
        { XFS_BMAPI_CONTIG,     "CONTIG" }, \
-       { XFS_BMAPI_CONVERT,    "CONVERT" }
+       { XFS_BMAPI_CONVERT,    "CONVERT" }, \
+       { XFS_BMAPI_STACK_SWITCH, "STACK_SWITCH" }
 
 
 static inline int xfs_bmapi_aflag(int w)
@@ -133,6 +135,7 @@ typedef struct xfs_bmalloca {
        char                    userdata;/* set if is user data */
        char                    aeof;   /* allocated space at eof */
        char                    conv;   /* overwriting unwritten extents */
+       char                    stack_switch;
 } xfs_bmalloca_t;
 
 /*
index f858b903678e067ec009b406f47df09ca2899cdf..a066cf1766ab6a3963759b4e7e3268bc2a81f47b 100644 (file)
@@ -575,7 +575,9 @@ xfs_iomap_write_allocate(
                         * pointer that the caller gave to us.
                         */
                        error = xfs_bmapi_write(tp, ip, map_start_fsb,
-                                               count_fsb, 0, &first_block, 1,
+                                               count_fsb,
+                                               XFS_BMAPI_STACK_SWITCH,
+                                               &first_block, 1,
                                                imap, &nimaps, &free_list);
                        if (error)
                                goto trans_cancel;