When online discard is enabled, discards of busy extents are submitted asynchronously as a bio chain. bio completion and resulting busy extent cleanup is deferred to a workqueue. Async discard submission is intended to avoid blocking log forces on a full discard sequence which can take a noticeable amount of time in some cases. We've had reports of this still producing log force stalls with XFS on VDO, which executes discards synchronously and relies on online discard in XFS. In particular, there appears to be a limit on how many discards can execute at one time. When this limit is hit, discard submission blocks and affects XFS up through log completion. There is no need for XFS to ever block in this path as busy extents are cleared on discard completion. Since we already have a workqueue for discard bio completion, reuse that workqueue for discard submission and completely separate online discard processing from iclog completion processing. With this change, the only path that should ever block on discard completion is the allocation path if it determines a need to wait on busy extents. Signed-off-by: Brian Foster <bfoster@xxxxxxxxxx> --- fs/xfs/xfs_log_cil.c | 13 ++++++++----- fs/xfs/xfs_log_priv.h | 1 + 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c index d3884e08b43c..087e99e80edd 100644 --- a/fs/xfs/xfs_log_cil.c +++ b/fs/xfs/xfs_log_cil.c @@ -529,9 +529,11 @@ xlog_discard_endio( static void xlog_discard_busy_extents( - struct xfs_mount *mp, - struct xfs_cil_ctx *ctx) + struct work_struct *work) { + struct xfs_cil_ctx *ctx = container_of(work, struct xfs_cil_ctx, + discard_work); + struct xfs_mount *mp = ctx->cil->xc_log->l_mp; struct list_head *list = &ctx->busy_extents; struct xfs_extent_busy *busyp; struct bio *bio = NULL; @@ -603,9 +605,10 @@ xlog_cil_committed( xlog_cil_free_logvec(ctx->lv_chain); - if (!list_empty(&ctx->busy_extents)) - xlog_discard_busy_extents(mp, ctx); - else + if (!list_empty(&ctx->busy_extents)) { + INIT_WORK(&ctx->discard_work, xlog_discard_busy_extents); + queue_work(xfs_discard_wq, &ctx->discard_work); + } else kmem_free(ctx); } diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h index b5f82cb36202..085bebd51135 100644 --- a/fs/xfs/xfs_log_priv.h +++ b/fs/xfs/xfs_log_priv.h @@ -245,6 +245,7 @@ struct xfs_cil_ctx { struct xfs_log_vec *lv_chain; /* logvecs being pushed */ struct xfs_log_callback log_cb; /* completion callback hook. */ struct list_head committing; /* ctx committing list */ + struct work_struct discard_work; struct work_struct discard_endio_work; }; -- 2.17.2