@@ -63,6 +63,8 @@
#define trace_xfs_iext_insert(a,b,c,d) ((void) 0)
#define trace_xfs_iext_remove(a,b,c,d) ((void) 0)
+#define trace_xfs_defer_relog_intent(a,b) ((void) 0)
+
#define trace_xfs_dir2_grow_inode(a,b) ((void) 0)
#define trace_xfs_dir2_shrink_inode(a,b) ((void) 0)
@@ -148,4 +148,7 @@ libxfs_trans_read_buf(
return libxfs_trans_read_buf_map(mp, tp, btp, &map, 1, flags, bpp, ops);
}
+#define xfs_log_item_in_current_chkpt(lip) (false)
+#define xfs_trans_item_relog(lip, tp) (NULL)
+
#endif /* __XFS_TRANS_H__ */
@@ -342,6 +342,42 @@ 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 int
+xfs_defer_relog(
+ struct xfs_trans **tpp,
+ struct list_head *dfops)
+{
+ struct xfs_defer_pending *dfp;
+
+ ASSERT((*tpp)->t_flags & XFS_TRANS_PERM_LOG_RES);
+
+ list_for_each_entry(dfp, dfops, dfp_list) {
+ /*
+ * If the log intent item for this deferred op is not a part of
+ * the current log checkpoint, relog the intent item to keep
+ * the log tail moving forward. We're ok with this being racy
+ * because an incorrect decision means we'll be a little slower
+ * at pushing the tail.
+ */
+ if (dfp->dfp_intent == NULL ||
+ xfs_log_item_in_current_chkpt(dfp->dfp_intent))
+ continue;
+
+ trace_xfs_defer_relog_intent((*tpp)->t_mountp, dfp);
+ XFS_STATS_INC((*tpp)->t_mountp, defer_relog);
+ dfp->dfp_intent = xfs_trans_item_relog(dfp->dfp_intent, *tpp);
+ }
+
+ if ((*tpp)->t_flags & XFS_TRANS_DIRTY)
+ return xfs_defer_trans_roll(tpp);
+ return 0;
+}
+
/*
* Log an intent-done item for the first pending intent, and finish the work
* items.
@@ -428,6 +464,11 @@ xfs_defer_finish_noroll(
if (error)
goto out_shutdown;
+ /* Possibly relog intent items to keep the log moving. */
+ error = xfs_defer_relog(tp, &dop_pending);
+ if (error)
+ goto out_shutdown;
+
dfp = list_first_entry(&dop_pending, struct xfs_defer_pending,
dfp_list);
error = xfs_defer_finish_one(*tp, dfp);