[RFC,10/10] xfs: relog random buffers based on errortag
diff mbox series

Message ID 20200701165116.47344-11-bfoster@redhat.com
State New
Headers show
Series
  • xfs: automatic relogging
Related show

Commit Message

Brian Foster July 1, 2020, 4:51 p.m. UTC
Since there is currently no specific use case for buffer relogging,
add some hacky and experimental code to relog random buffers when
the associated errortag is enabled. Use fixed termination logic
regardless of the user-specified error rate to help ensure that the
relog queue doesn't grow indefinitely.

Note that this patch was useful in causing log reservation deadlocks
on an fsstress workload if the relog mechanism code is modified to
acquire its own log reservation rather than rely on the
pre-reservation mechanism. In other words, this helps prove that the
relog reservation management code effectively avoids log reservation
deadlocks.

Signed-off-by: Brian Foster <bfoster@redhat.com>
---
 fs/xfs/xfs_buf_item.c  |  1 +
 fs/xfs/xfs_trans.h     |  4 +++-
 fs/xfs/xfs_trans_ail.c | 33 +++++++++++++++++++++++++++++++++
 fs/xfs/xfs_trans_buf.c | 14 ++++++++++++++
 4 files changed, 51 insertions(+), 1 deletion(-)

Patch
diff mbox series

diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
index eb827a31b47f..fb277187a2cf 100644
--- a/fs/xfs/xfs_buf_item.c
+++ b/fs/xfs/xfs_buf_item.c
@@ -469,6 +469,7 @@  xfs_buf_item_unpin(
 			ASSERT(!test_bit(XFS_LI_RELOG_QUEUED, &lip->li_flags));
 			if (test_bit(XFS_LI_RELOG, &lip->li_flags)) {
 				atomic_dec(&bp->b_pin_count);
+				clear_bit(XFS_LI_RELOG_RAND, &bip->bli_item.li_flags);
 				xfs_trans_relog_item_cancel(NULL, lip, true);
 			}
 
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index 0262a883969f..18714e6af476 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -65,6 +65,7 @@  struct xfs_log_item {
 #define	XFS_LI_RECOVERED 4	/* log intent item has been recovered */
 #define	XFS_LI_RELOG	5	/* automatically relog item */
 #define XFS_LI_RELOG_QUEUED 6	/* queued for relog */
+#define XFS_LI_RELOG_RAND   7
 
 #define XFS_LI_FLAGS \
 	{ (1 << XFS_LI_IN_AIL),		"IN_AIL" }, \
@@ -73,7 +74,8 @@  struct xfs_log_item {
 	{ (1 << XFS_LI_DIRTY),		"DIRTY" }, \
 	{ (1 << XFS_LI_RECOVERED),	"RECOVERED" }, \
 	{ (1 << XFS_LI_RELOG),		"RELOG" }, \
-	{ (1 << XFS_LI_RELOG_QUEUED),	"RELOG_QUEUED" }
+	{ (1 << XFS_LI_RELOG_QUEUED),	"RELOG_QUEUED" }, \
+	{ (1 << XFS_LI_RELOG_RAND),	"RELOG_RAND" }
 
 struct xfs_item_ops {
 	unsigned flags;
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c
index 6c4d219801a6..3a8a1abc6c4c 100644
--- a/fs/xfs/xfs_trans_ail.c
+++ b/fs/xfs/xfs_trans_ail.c
@@ -18,6 +18,7 @@ 
 #include "xfs_error.h"
 #include "xfs_log.h"
 #include "xfs_log_priv.h"
+#include "xfs_buf_item.h"
 
 #ifdef DEBUG
 /*
@@ -176,6 +177,7 @@  xfs_ail_relog(
 	struct xfs_trans_res	tres = {};
 	struct xfs_trans	*tp;
 	struct xfs_log_item	*lip, *lipp;
+	int			cancelres;
 	int			error;
 	LIST_HEAD(relog_list);
 
@@ -209,6 +211,37 @@  xfs_ail_relog(
 			ASSERT(lip->li_ops->iop_relog);
 			if (lip->li_ops->iop_relog)
 				lip->li_ops->iop_relog(lip, tp);
+
+			/*
+			 * Cancel random buffer relogs at a fixed rate to
+			 * prevent too much buildup.
+			 */
+			if (test_bit(XFS_LI_RELOG_RAND, &lip->li_flags) &&
+			    ((prandom_u32() & 1) ||
+			     (mp->m_flags & XFS_MOUNT_UNMOUNTING))) {
+				struct xfs_buf_log_item	*bli;
+				bli = container_of(lip, struct xfs_buf_log_item,
+						   bli_item);
+				xfs_trans_relog_buf_cancel(tp, bli->bli_buf);
+			}
+		}
+
+		/*
+		 * Cancelling relog reservation in the same transaction as
+		 * consuming it means the current transaction over releases
+		 * reservation on commit and the next transaction reservation
+		 * restores the grant heads to even. To avoid this behavior,
+		 * remove surplus reservation (->t_curr_res) from the committing
+		 * transaction and replace it with a reduction in the
+		 * reservation requirement (->t_unit_res) for the next. This has
+		 * no net effect on reservation accounting, but ensures we don't
+		 * cause problems elsewhere with odd reservation behavior.
+		 */
+		cancelres = tp->t_ticket->t_curr_res - tp->t_ticket->t_unit_res;
+		if (cancelres) {
+			tp->t_ticket->t_curr_res -= cancelres;
+			tp->t_ticket->t_unit_res -= cancelres;
+			tp->t_log_res -= cancelres;
 		}
 
 		error = xfs_trans_roll(&tp);
diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c
index b5b552a4bcfb..565386912e4d 100644
--- a/fs/xfs/xfs_trans_buf.c
+++ b/fs/xfs/xfs_trans_buf.c
@@ -14,6 +14,8 @@ 
 #include "xfs_buf_item.h"
 #include "xfs_trans_priv.h"
 #include "xfs_trace.h"
+#include "xfs_error.h"
+#include "xfs_errortag.h"
 
 /*
  * Check to see if a buffer matching the given parameters is already
@@ -527,6 +529,17 @@  xfs_trans_log_buf(
 
 	trace_xfs_trans_log_buf(bip);
 	xfs_buf_item_log(bip, first, last);
+
+	/*
+	 * Relog random buffers so long as the transaction is relog enabled and
+	 * the buffer wasn't already relogged explicitly.
+	 */
+	if (XFS_TEST_ERROR(false, tp->t_mountp, XFS_ERRTAG_RELOG) &&
+	    (tp->t_flags & XFS_TRANS_RELOG) &&
+	    !test_bit(XFS_LI_RELOG, &bip->bli_item.li_flags)) {
+		if (xfs_trans_relog_buf(tp, bp))
+			set_bit(XFS_LI_RELOG_RAND, &bip->bli_item.li_flags);
+	}
 }
 
 
@@ -852,4 +865,5 @@  xfs_trans_relog_buf_cancel(
 
 	atomic_dec(&bp->b_pin_count);
 	xfs_trans_relog_item_cancel(tp, &bip->bli_item, false);
+	clear_bit(XFS_LI_RELOG_RAND, &bip->bli_item.li_flags);
 }