Blob Blame History Raw
From b0c850f308d44ddcdf1a1f881c1e1142ad489385 Mon Sep 17 00:00:00 2001
From: Jan Friesse <jfriesse@redhat.com>
Date: Tue, 30 Aug 2016 16:57:31 +0200
Subject: [PATCH] Qnetd LMS: Fix two partition use case

Solves situation when in 2 node cluster tie-breaker node dies. Because
code contains two bugs, other node got NACK instead of ACK.

- Algo timer is not stack, so calling abort and schedule in timer
callback without setting reschedule is noop.
- It's needed to check not only what current node thinks about
membership, but also what other nodes thinks. If views diverge -> wait.

Thanks Christine Caulfield <ccaulfie@redhat.com> for fixing the English
in the comments somewhat.

Signed-off-by: Jan Friesse <jfriesse@redhat.com>
Reviewed-by: Christine Caulfield <ccaulfie@redhat.com>
---
 qdevices/qnetd-algo-lms.c   |   12 ++++++++++++
 qdevices/qnetd-algo-utils.c |   14 ++++++++++++++
 2 files changed, 26 insertions(+), 0 deletions(-)

diff --git a/qdevices/qnetd-algo-lms.c b/qdevices/qnetd-algo-lms.c
index 55a1bb2..cdd86c4 100644
--- a/qdevices/qnetd-algo-lms.c
+++ b/qdevices/qnetd-algo-lms.c
@@ -361,6 +361,18 @@ qnetd_algo_lms_timer_callback(struct qnetd_client *client, int *reschedule_timer
 	    (*result_vote == TLV_VOTE_ACK || *result_vote == TLV_VOTE_NACK)) {
 		*send_vote = 1;
 	}
+
+	if (ret == TLV_REPLY_ERROR_CODE_NO_ERROR &&
+	    *result_vote == TLV_VOTE_WAIT_FOR_REPLY) {
+		/*
+		 * Reschedule was called in the do_lms_algorithm but algo_timer is
+		 * not stack based so there can only be one. So if do_lms aborted
+		 * the active timer, and scheduled it again the timer would be aborted
+		 * if reschedule_timer was not set.
+		 */
+		*reschedule_timer = 1;
+	}
+
 	return ret;
 }
 
diff --git a/qdevices/qnetd-algo-utils.c b/qdevices/qnetd-algo-utils.c
index 440f81f..e26b40a 100644
--- a/qdevices/qnetd-algo-utils.c
+++ b/qdevices/qnetd-algo-utils.c
@@ -65,6 +65,19 @@ qnetd_algo_all_ring_ids_match(struct qnetd_client *client, const struct tlv_ring
 			}
 		}
 
+		if (in_our_partition == 0) {
+			/*
+			 * Also try to look from the other side to see if we are
+			 * not in the other node's membership list.
+			 * Because if so it may mean the membership lists are not equal
+			 */
+			TAILQ_FOREACH(node_info, &other_client->last_membership_node_list, entries) {
+				if (node_info->node_id == client->node_id) {
+					in_our_partition = 1;
+				}
+			}
+		}
+
 		/*
 		 * If the other nodes on our side of a partition have a different ring ID then
 		 * we need to wait until they have all caught up before making a decision
@@ -74,6 +87,7 @@ qnetd_algo_all_ring_ids_match(struct qnetd_client *client, const struct tlv_ring
 			return (-1); /* ring IDs don't match */
 		}
 	}
+
 	return (0);
 }
 
-- 
1.7.1