diff options
Diffstat (limited to 'fs/xfs/libxfs/xfs_defer.c')
-rw-r--r-- | fs/xfs/libxfs/xfs_defer.c | 34 |
1 files changed, 34 insertions, 0 deletions
diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c index 9e6412bd6845..15c84e11625d 100644 --- a/fs/xfs/libxfs/xfs_defer.c +++ b/fs/xfs/libxfs/xfs_defer.c @@ -361,6 +361,30 @@ xfs_defer_cancel_list( } /* + * Prevent a log intent item from pinning the tail of the log by logging a + * done item to release the intent item; and then log a new intent item. + * The caller should provide a fresh transaction and roll it after we're done. + */ +static void +xfs_defer_relog( + struct xfs_trans *tp, + struct list_head *dfops) +{ + struct xfs_defer_pending *dfp; + + ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); + + trace_xfs_defer_relog(tp, _RET_IP_); + + list_for_each_entry(dfp, dfops, dfp_list) { + trace_xfs_defer_relog_intent(tp->t_mountp, dfp); + dfp->dfp_intent = xfs_trans_item_relog(dfp->dfp_intent, tp); + } + + trace_xfs_defer_relog_done(tp, _RET_IP_); +} + +/* * Log an intent-done item for the first pending intent, and finish the work * items. */ @@ -420,6 +444,7 @@ xfs_defer_finish_noroll( struct xfs_trans **tp) { struct xfs_defer_pending *dfp; + unsigned int nr_rolls = 0; int error = 0; LIST_HEAD(dop_pending); @@ -445,6 +470,15 @@ xfs_defer_finish_noroll( if (error) goto out_shutdown; + /* Every few rolls we relog all the intent items. */ + if (!(++nr_rolls % 7)) { + xfs_defer_relog(*tp, &dop_pending); + + error = xfs_defer_trans_roll(tp); + if (error) + goto out_shutdown; + } + dfp = list_first_entry(&dop_pending, struct xfs_defer_pending, dfp_list); error = xfs_defer_finish_one(*tp, dfp); |