From a623a1dda33993f60558abe76327c7528126eec7 Mon Sep 17 00:00:00 2001
From: Philipp Reisner <philipp.reisner@linbit.com>
Date: Tue, 10 Jul 2018 17:15:56 +0200
Subject: [PATCH] drbd: optimize submit path a bit

on my mid-range Skylake system Xeon Silver 4112 CPU @ 2.60GHz
this brings me from 450k read IOPs to 455k read IOPs.
---
 drbd/drbd_debugfs.c |  2 +-
 drbd/drbd_int.h     | 69 ++-------------------------------------------
 drbd/drbd_state.c   | 67 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 70 insertions(+), 68 deletions(-)

diff --git a/drbd/drbd_debugfs.c b/drbd/drbd_debugfs.c
index 8f972ccb..2ae638bc 100644
--- a/drbd/drbd_debugfs.c
+++ b/drbd/drbd_debugfs.c
@@ -1074,7 +1074,7 @@ static int device_io_frozen_show(struct seq_file *m, void *ignored)
 
 	seq_printf(m, "drbd_suspended(): %d\n", drbd_suspended(device));
 	seq_printf(m, "suspend_cnt: %d\n", atomic_read(&device->suspend_cnt));
-	seq_printf(m, "!drbd_state_is_stable(): %d\n", !drbd_state_is_stable(device));
+	seq_printf(m, "!drbd_state_is_stable(): %d\n", device->cached_state_unstable);
 	seq_printf(m, "ap_bio_cnt[READ]: %d\n", atomic_read(&device->ap_bio_cnt[READ]));
 	seq_printf(m, "ap_bio_cnt[WRITE]: %d\n", atomic_read(&device->ap_bio_cnt[WRITE]));
 	seq_printf(m, "device->pending_bitmap_work.n: %d\n", atomic_read(&device->pending_bitmap_work.n));
diff --git a/drbd/drbd_int.h b/drbd/drbd_int.h
index 434c44e0..7b5f3a66 100644
--- a/drbd/drbd_int.h
+++ b/drbd/drbd_int.h
@@ -1302,6 +1302,7 @@ struct drbd_device {
 	struct submit_worker submit;
 	u64 read_nodes; /* used for balancing read requests among peers */
 	bool have_quorum[2];	/* no quorum -> suspend IO or error IO */
+	bool cached_state_unstable; /* updates with each state change */
 
 	spinlock_t timing_lock;
 	unsigned long reqs;
@@ -2585,72 +2586,6 @@ static inline int _get_ldev_if_state(struct drbd_device *device, enum drbd_disk_
 extern int _get_ldev_if_state(struct drbd_device *device, enum drbd_disk_state mins);
 #endif
 
-static inline bool drbd_state_is_stable(struct drbd_device *device)
-{
-	struct drbd_peer_device *peer_device;
-	bool stable = true;
-
-	/* DO NOT add a default clause, we want the compiler to warn us
-	 * for any newly introduced state we may have forgotten to add here */
-
-	rcu_read_lock();
-	for_each_peer_device_rcu(peer_device, device) {
-		switch (peer_device->repl_state[NOW]) {
-		/* New io is only accepted when the peer device is unknown or there is
-		 * a well-established connection. */
-		case L_OFF:
-		case L_ESTABLISHED:
-		case L_SYNC_SOURCE:
-		case L_SYNC_TARGET:
-		case L_VERIFY_S:
-		case L_VERIFY_T:
-		case L_PAUSED_SYNC_S:
-		case L_PAUSED_SYNC_T:
-		case L_AHEAD:
-		case L_BEHIND:
-		case L_STARTING_SYNC_S:
-		case L_STARTING_SYNC_T:
-			break;
-
-			/* Allow IO in BM exchange states with new protocols */
-		case L_WF_BITMAP_S:
-			if (peer_device->connection->agreed_pro_version < 96)
-				stable = false;
-			break;
-
-			/* no new io accepted in these states */
-		case L_WF_BITMAP_T:
-		case L_WF_SYNC_UUID:
-			stable = false;
-			break;
-		}
-		if (!stable)
-			break;
-	}
-	rcu_read_unlock();
-
-	switch (device->disk_state[NOW]) {
-	case D_DISKLESS:
-	case D_INCONSISTENT:
-	case D_OUTDATED:
-	case D_CONSISTENT:
-	case D_UP_TO_DATE:
-	case D_FAILED:
-	case D_DETACHING:
-		/* disk state is stable as well. */
-		break;
-
-	/* no new io accepted during transitional states */
-	case D_ATTACHING:
-	case D_NEGOTIATING:
-	case D_UNKNOWN:
-	case D_MASK:
-		stable = false;
-	}
-
-	return stable;
-}
-
 extern void drbd_queue_pending_bitmap_work(struct drbd_device *);
 
 /* rw = READ or WRITE (0 or 1); nothing else. */
@@ -2691,7 +2626,7 @@ static inline bool may_inc_ap_bio(struct drbd_device *device)
 	 * to start during "stable" states. */
 
 	/* no new io accepted when attaching or detaching the disk */
-	if (!drbd_state_is_stable(device))
+	if (device->cached_state_unstable)
 		return false;
 
 	if (atomic_read(&device->pending_bitmap_work.n))
diff --git a/drbd/drbd_state.c b/drbd/drbd_state.c
index f59c7e5d..ca5df671 100644
--- a/drbd/drbd_state.c
+++ b/drbd/drbd_state.c
@@ -617,6 +617,72 @@ static void __clear_remote_state_change(struct drbd_resource *resource)
 	apply_update_to_exposed_data_uuid(resource);
 }
 
+static bool state_is_stable(struct drbd_device *device)
+{
+	struct drbd_peer_device *peer_device;
+	bool stable = true;
+
+	/* DO NOT add a default clause, we want the compiler to warn us
+	 * for any newly introduced state we may have forgotten to add here */
+
+	rcu_read_lock();
+	for_each_peer_device_rcu(peer_device, device) {
+		switch (peer_device->repl_state[NOW]) {
+		/* New io is only accepted when the peer device is unknown or there is
+		 * a well-established connection. */
+		case L_OFF:
+		case L_ESTABLISHED:
+		case L_SYNC_SOURCE:
+		case L_SYNC_TARGET:
+		case L_VERIFY_S:
+		case L_VERIFY_T:
+		case L_PAUSED_SYNC_S:
+		case L_PAUSED_SYNC_T:
+		case L_AHEAD:
+		case L_BEHIND:
+		case L_STARTING_SYNC_S:
+		case L_STARTING_SYNC_T:
+			break;
+
+			/* Allow IO in BM exchange states with new protocols */
+		case L_WF_BITMAP_S:
+			if (peer_device->connection->agreed_pro_version < 96)
+				stable = false;
+			break;
+
+			/* no new io accepted in these states */
+		case L_WF_BITMAP_T:
+		case L_WF_SYNC_UUID:
+			stable = false;
+			break;
+		}
+		if (!stable)
+			break;
+	}
+	rcu_read_unlock();
+
+	switch (device->disk_state[NOW]) {
+	case D_DISKLESS:
+	case D_INCONSISTENT:
+	case D_OUTDATED:
+	case D_CONSISTENT:
+	case D_UP_TO_DATE:
+	case D_FAILED:
+	case D_DETACHING:
+		/* disk state is stable as well. */
+		break;
+
+	/* no new io accepted during transitional states */
+	case D_ATTACHING:
+	case D_NEGOTIATING:
+	case D_UNKNOWN:
+	case D_MASK:
+		stable = false;
+	}
+
+	return stable;
+}
+
 static enum drbd_state_rv ___end_state_change(struct drbd_resource *resource, struct completion *done,
 					      enum drbd_state_rv rv)
 {
@@ -677,6 +743,7 @@ static enum drbd_state_rv ___end_state_change(struct drbd_resource *resource, st
 			peer_device->resync_susp_other_c[NOW] =
 				peer_device->resync_susp_other_c[NEW];
 		}
+		device->cached_state_unstable = !state_is_stable(device);
 	}
 	smp_wmb(); /* Make the NEW_CUR_UUID bit visible after the state change! */
 
-- 
2.34.1

