diff mbox series

[4/7] xfs: factor callbacks out of xlog_state_do_callback()

Message ID 20190904042451.9314-5-david@fromorbit.com (mailing list archive)
State Superseded
Headers show
Series xfs: log race fixes and cleanups | expand

Commit Message

Dave Chinner Sept. 4, 2019, 4:24 a.m. UTC
From: Dave Chinner <dchinner@redhat.com>

Simplify the code flow by lifting the iclog callback work out of
the main iclog iteration loop. This isolates the log juggling and
callbacks from the iclog state change logic in the loop.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/xfs_log.c | 69 +++++++++++++++++++++++++++++++-----------------
 1 file changed, 45 insertions(+), 24 deletions(-)

Comments

Christoph Hellwig Sept. 4, 2019, 6:13 a.m. UTC | #1
Looks good,

Reviewed-by: Christoph Hellwig <hch@lst.de>
Christoph Hellwig Sept. 4, 2019, 6:32 a.m. UTC | #2
After going back to this from the next patch I think I spotted a
behavior difference:  xlog_state_do_iclog_callbacks only returns true,
and xlog_state_do_callback only increments loopdidcallbacks if
ic_callbacks was non-emty.  But we already dropped the block just
to check that it is empty, so I think we need to keep the old
behavior.
Dave Chinner Sept. 4, 2019, 9:22 p.m. UTC | #3
On Tue, Sep 03, 2019 at 11:32:40PM -0700, Christoph Hellwig wrote:
> After going back to this from the next patch I think I spotted a
> behavior difference:  xlog_state_do_iclog_callbacks only returns true,
> and xlog_state_do_callback only increments loopdidcallbacks if
> ic_callbacks was non-emty.  But we already dropped the block just
> to check that it is empty, so I think we need to keep the old
> behavior.

IIUC, you are saying that loopdidcallbacks is not a variable that
tracks whether callbacks were run, but whether the icloglock was
released or not. Ok, I'll go fix that up, and name the variable
appropriately.

Cheers,

Dave.
diff mbox series

Patch

diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index b3d8dbb3b956..c3a43fe023ea 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -2612,6 +2612,47 @@  xlog_get_lowest_lsn(
 	return lowest_lsn;
 }
 
+/*
+ * Keep processing entries in the iclog callback list until we come around and
+ * it is empty.  We need to atomically see that the list is empty and change the
+ * state to DIRTY so that we don't miss any more callbacks being added.
+ *
+ * This function is called with the icloglock held and returns with it held. We
+ * drop it while running callbacks, however, as holding it over thousands of
+ * callbacks is unnecessary and causes excessive contention if we do.
+ */
+static bool
+xlog_state_do_iclog_callbacks(
+	struct xlog		*log,
+	struct xlog_in_core	*iclog,
+	bool			aborted)
+{
+	bool			ret = false;
+
+	spin_unlock(&log->l_icloglock);
+
+	spin_lock(&iclog->ic_callback_lock);
+	while (!list_empty(&iclog->ic_callbacks)) {
+		LIST_HEAD(tmp);
+
+		list_splice_init(&iclog->ic_callbacks, &tmp);
+
+		spin_unlock(&iclog->ic_callback_lock);
+		xlog_cil_process_committed(&tmp, aborted);
+		spin_lock(&iclog->ic_callback_lock);
+		ret = true;
+	}
+
+	/*
+	 * Pick up the icloglock while still holding the callback lock so we
+	 * serialise against anyone trying to add more callbacks to this iclog
+	 * now we've finished processing.
+	 */
+	spin_lock(&log->l_icloglock);
+	spin_unlock(&iclog->ic_callback_lock);
+	return ret;
+}
+
 #ifdef DEBUG
 /*
  * Make one last gasp attempt to see if iclogs are being left in limbo.  If the
@@ -2784,31 +2825,9 @@  xlog_state_do_callback(
 			} else
 				ioerrors++;
 
-			spin_unlock(&log->l_icloglock);
+			if (xlog_state_do_iclog_callbacks(log, iclog, aborted))
+				loopdidcallbacks++;
 
-			/*
-			 * Keep processing entries in the callback list until
-			 * we come around and it is empty.  We need to
-			 * atomically see that the list is empty and change the
-			 * state to DIRTY so that we don't miss any more
-			 * callbacks being added.
-			 */
-			spin_lock(&iclog->ic_callback_lock);
-			while (!list_empty(&iclog->ic_callbacks)) {
-				LIST_HEAD(tmp);
-
-				list_splice_init(&iclog->ic_callbacks, &tmp);
-
-				spin_unlock(&iclog->ic_callback_lock);
-				xlog_cil_process_committed(&tmp, aborted);
-				spin_lock(&iclog->ic_callback_lock);
-			}
-
-			loopdidcallbacks++;
-			funcdidcallbacks++;
-
-			spin_lock(&log->l_icloglock);
-			spin_unlock(&iclog->ic_callback_lock);
 			if (!(iclog->ic_state & XLOG_STATE_IOERROR))
 				iclog->ic_state = XLOG_STATE_DIRTY;
 
@@ -2824,6 +2843,8 @@  xlog_state_do_callback(
 			iclog = iclog->ic_next;
 		} while (first_iclog != iclog);
 
+		funcdidcallbacks += loopdidcallbacks;
+
 		if (repeats > 5000) {
 			flushcnt += repeats;
 			repeats = 0;