Move the allocation worker call so that any loops on xfs_alloc_vextent() calls for a particular transaction are contained within a single worker. This prevents a filesystem hang that can occur because the holder of AGF buffer lock cannot allocate a worker. Signed-off-by: Mark Tinguely <tinguely@xxxxxxx> --- fs/xfs/xfs_alloc.c | 53 ------------------------------------------- fs/xfs/xfs_alloc.h | 3 -- fs/xfs/xfs_bmap.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++- fs/xfs/xfs_bmap.h | 16 +++++++++++++ 4 files changed, 80 insertions(+), 56 deletions(-) Index: b/fs/xfs/xfs_alloc.c =================================================================== --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c @@ -2207,7 +2207,7 @@ xfs_alloc_read_agf( * group or loop over the allocation groups to find the result. */ int /* error */ -__xfs_alloc_vextent( +xfs_alloc_vextent( xfs_alloc_arg_t *args) /* allocation argument structure */ { xfs_agblock_t agsize; /* allocation group size */ @@ -2417,57 +2417,6 @@ error0: return error; } -#if defined(CONFIG_X86_64) -static void -xfs_alloc_vextent_worker( - struct work_struct *work) -{ - struct xfs_alloc_arg *args = container_of(work, - struct xfs_alloc_arg, work); - unsigned long pflags; - - /* we are in a transaction context here */ - current_set_flags_nested(&pflags, PF_FSTRANS); - - args->result = __xfs_alloc_vextent(args); - complete(args->done); - - current_restore_flags_nested(&pflags, PF_FSTRANS); -} -#endif - -/* - * Data allocation requests often come in with little stack to work on. Push - * them off to a worker thread so there is lots of stack to use. Metadata - * requests, OTOH, are generally from low stack usage paths, so avoid the - * context switch overhead here. - */ -int -xfs_alloc_vextent( - struct xfs_alloc_arg *args) -{ -#if defined(CONFIG_X86_64) - DECLARE_COMPLETION_ONSTACK(done); - - if (!args->userdata) - return __xfs_alloc_vextent(args); - - - args->done = &done; - INIT_WORK_ONSTACK(&args->work, xfs_alloc_vextent_worker); - queue_work(xfs_alloc_wq, &args->work); - wait_for_completion(&done); - return args->result; -#else - /* The allocation worker is needed by the i386_64. - * Do not use the worker for other platforms. This will - * allow those platforms avoid the performance hit and - * the potential AGF buffer deadlock issue. - */ - return __xfs_alloc_vextent(args); -#endif -} - /* * Free an extent. * Just break up the extent address and hand off to xfs_free_ag_extent Index: b/fs/xfs/xfs_alloc.h =================================================================== --- a/fs/xfs/xfs_alloc.h +++ b/fs/xfs/xfs_alloc.h @@ -120,9 +120,6 @@ typedef struct xfs_alloc_arg { char isfl; /* set if is freelist blocks - !acctg */ char userdata; /* set if this is user data */ xfs_fsblock_t firstblock; /* io first block allocated */ - struct completion *done; - struct work_struct work; - int result; } xfs_alloc_arg_t; /* Index: b/fs/xfs/xfs_bmap.c =================================================================== --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c @@ -48,7 +48,6 @@ #include "xfs_vnodeops.h" #include "xfs_trace.h" - kmem_zone_t *xfs_bmap_free_item_zone; /* @@ -4807,7 +4806,11 @@ xfs_bmapi_convert_unwritten( * blocks then the call will fail (return NULLFSBLOCK in "firstblock"). */ int +#if defined(CONFIG_X86_64) +__xfs_bmapi_write( +#else xfs_bmapi_write( +#endif struct xfs_trans *tp, /* transaction pointer */ struct xfs_inode *ip, /* incore inode */ xfs_fileoff_t bno, /* starting file offs. mapped */ @@ -5031,6 +5034,65 @@ error0: return error; } +#if defined(CONFIG_X86_64) +static void +xfs_bmapi_write_worker( + struct work_struct *work) +{ + struct xfs_bmw_wkr *bw = container_of(work, + struct xfs_bmw_wkr, work); + unsigned long pflags; + + /* we are in a transaction context here */ + current_set_flags_nested(&pflags, PF_FSTRANS); + + bw->result = __xfs_bmapi_write(bw->tp, bw->ip, bw->bno, bw->len, + bw->flags, bw->firstblock, bw->total, + bw->mval, bw->nmap, bw->flist); + complete(bw->done); + + current_restore_flags_nested(&pflags, PF_FSTRANS); +} + +int +xfs_bmapi_write( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_inode *ip, /* incore inode */ + xfs_fileoff_t bno, /* starting file offs. mapped */ + xfs_filblks_t len, /* length to map in file */ + int flags, /* XFS_BMAPI_... */ + xfs_fsblock_t *firstblock, /* first allocated block + controls a.g. for allocs */ + xfs_extlen_t total, /* total blocks needed */ + struct xfs_bmbt_irec *mval, /* output: map values */ + int *nmap, /* i/o: mval size/count */ + struct xfs_bmap_free *flist) /* i/o: list extents to free */ +{ + struct xfs_bmw_wkr bw; + DECLARE_COMPLETION_ONSTACK(done); + + if (flags & XFS_BMAPI_METADATA) + return __xfs_bmapi_write(tp, ip, bno, len, flags, firstblock, + total, mval, nmap, flist); + /* initialize the worker argument list structure */ + bw.tp = tp; + bw.ip = ip; + bw.bno = bno; + bw.len = len; + bw.flags = flags; + bw.firstblock = firstblock; + bw.total = total; + bw.mval = mval; + bw.nmap = nmap; + bw.flist = flist; + bw.done = &done; + INIT_WORK_ONSTACK(&bw.work, xfs_bmapi_write_worker); + queue_work(xfs_alloc_wq, &bw.work); + wait_for_completion(&done); + return bw.result; +} +#endif + /* * Unmap (remove) blocks from a file. * If nexts is nonzero then the number of extents to remove is limited to Index: b/fs/xfs/xfs_bmap.h =================================================================== --- a/fs/xfs/xfs_bmap.h +++ b/fs/xfs/xfs_bmap.h @@ -135,6 +135,22 @@ typedef struct xfs_bmalloca { char conv; /* overwriting unwritten extents */ } xfs_bmalloca_t; +struct xfs_bmw_wkr { + struct xfs_trans *tp; /* transaction pointer */ + struct xfs_inode *ip; /* incore inode */ + xfs_fileoff_t bno; /* starting file offs. mapped */ + xfs_filblks_t len; /* length to map in file */ + int flags; /* XFS_BMAPI_... */ + xfs_fsblock_t *firstblock; /* first allocblock controls */ + xfs_extlen_t total; /* total blocks needed */ + struct xfs_bmbt_irec *mval; /* output: map values */ + int *nmap; /* i/o: mval size/count */ + struct xfs_bmap_free *flist; /* bmap freelist */ + struct completion *done; /* worker completion ptr */ + struct work_struct work; /* worker */ + int result; /* worker function result */ +} ; + /* * Flags for xfs_bmap_add_extent*. */ _______________________________________________ xfs mailing list xfs@xxxxxxxxxxx http://oss.sgi.com/mailman/listinfo/xfs