Blame SOURCES/bz1184154-1-Handle-adding-and-removing-UDPU-members-atomically.patch

d26a47
From d77cec24d0025d353681762fe707794c621665c7 Mon Sep 17 00:00:00 2001
d26a47
From: Jan Friesse <jfriesse@redhat.com>
d26a47
Date: Wed, 21 Jan 2015 13:30:48 +0100
d26a47
Subject: [PATCH] Handle adding and removing UDPU members atomically
d26a47
d26a47
When config file is reloaded with removed UDPU member, internal icmap
d26a47
index of nodelist.node can change. This can result in removal and then
d26a47
adding back node. This, with UDPU alive filtering (where member is by
d26a47
default considered as not a member) makes corosync not sending messages
d26a47
to such members resulting in new membership creation.
d26a47
d26a47
Solution is to properly test which members were really deleted and added
d26a47
(instead of relying on internal and dynamic naming of icmap hash table
d26a47
key name).
d26a47
d26a47
Also trully dynamic add and remove node (via cmap) is now handled by
d26a47
same function so totem_config->interfaces is now updated properly.
d26a47
d26a47
Signed-off-by: Jan Friesse <jfriesse@redhat.com>
d26a47
Reviewed-by: Fabio M. Di Nitto <fdinitto@redhat.com>
d26a47
---
d26a47
 exec/main.c        |   67 -------------------------
d26a47
 exec/totemconfig.c |  137 ++++++++++++++++++++++++++++++++++++++++++++++++++-
d26a47
 2 files changed, 134 insertions(+), 70 deletions(-)
d26a47
d26a47
diff --git a/exec/main.c b/exec/main.c
d26a47
index 85c74ee..0ca5634 100644
d26a47
--- a/exec/main.c
d26a47
+++ b/exec/main.c
d26a47
@@ -583,71 +583,6 @@ static void corosync_totem_stats_updater (void *data)
d26a47
 		&corosync_stats_timer_handle);
d26a47
 }
d26a47
 
d26a47
-static void totem_dynamic_notify(
d26a47
-	int32_t event,
d26a47
-	const char *key_name,
d26a47
-	struct icmap_notify_value new_val,
d26a47
-	struct icmap_notify_value old_val,
d26a47
-	void *user_data)
d26a47
-{
d26a47
-	int res;
d26a47
-	unsigned int ring_no;
d26a47
-	unsigned int member_no;
d26a47
-	struct totem_ip_address member;
d26a47
-	int add_new_member = 0;
d26a47
-	int remove_old_member = 0;
d26a47
-	char tmp_str[ICMAP_KEYNAME_MAXLEN];
d26a47
-
d26a47
-	res = sscanf(key_name, "nodelist.node.%u.ring%u%s", &member_no, &ring_no, tmp_str);
d26a47
-	if (res != 3)
d26a47
-		return ;
d26a47
-
d26a47
-	if (strcmp(tmp_str, "_addr") != 0) {
d26a47
-		return;
d26a47
-	}
d26a47
-
d26a47
-	if (event == ICMAP_TRACK_ADD && new_val.type == ICMAP_VALUETYPE_STRING) {
d26a47
-		add_new_member = 1;
d26a47
-	}
d26a47
-
d26a47
-	if (event == ICMAP_TRACK_DELETE && old_val.type == ICMAP_VALUETYPE_STRING) {
d26a47
-		remove_old_member = 1;
d26a47
-	}
d26a47
-
d26a47
-	if (event == ICMAP_TRACK_MODIFY && new_val.type == ICMAP_VALUETYPE_STRING &&
d26a47
-			old_val.type == ICMAP_VALUETYPE_STRING) {
d26a47
-		add_new_member = 1;
d26a47
-		remove_old_member = 1;
d26a47
-	}
d26a47
-
d26a47
-	if (remove_old_member) {
d26a47
-		log_printf(LOGSYS_LEVEL_DEBUG,
d26a47
-			"removing dynamic member %s for ring %u", (char *)old_val.data, ring_no);
d26a47
-		if (totemip_parse(&member, (char *)old_val.data, ip_version) == 0) {
d26a47
-			totempg_member_remove (&member, ring_no);
d26a47
-		}
d26a47
-	}
d26a47
-
d26a47
-	if (add_new_member) {
d26a47
-		log_printf(LOGSYS_LEVEL_DEBUG,
d26a47
-			"adding dynamic member %s for ring %u", (char *)new_val.data, ring_no);
d26a47
-		if (totemip_parse(&member, (char *)new_val.data, ip_version) == 0) {
d26a47
-			totempg_member_add (&member, ring_no);
d26a47
-		}
d26a47
-	}
d26a47
-}
d26a47
-
d26a47
-static void corosync_totem_dynamic_init (void)
d26a47
-{
d26a47
-	icmap_track_t icmap_track = NULL;
d26a47
-
d26a47
-	icmap_track_add("nodelist.node.",
d26a47
-		ICMAP_TRACK_ADD | ICMAP_TRACK_DELETE | ICMAP_TRACK_MODIFY | ICMAP_TRACK_PREFIX,
d26a47
-		totem_dynamic_notify,
d26a47
-		NULL,
d26a47
-		&icmap_track);
d26a47
-}
d26a47
-
d26a47
 static void corosync_totem_stats_init (void)
d26a47
 {
d26a47
 	icmap_set_uint32("runtime.totem.pg.mrp.srp.mtt_rx_token", 0);
d26a47
@@ -660,7 +595,6 @@ static void corosync_totem_stats_init (void)
d26a47
 		&corosync_stats_timer_handle);
d26a47
 }
d26a47
 
d26a47
-
d26a47
 static void deliver_fn (
d26a47
 	unsigned int nodeid,
d26a47
 	const void *msg,
d26a47
@@ -1093,7 +1027,6 @@ static void main_service_ready (void)
d26a47
 	cs_ipcs_init();
d26a47
 	corosync_totem_stats_init ();
d26a47
 	corosync_fplay_control_init ();
d26a47
-	corosync_totem_dynamic_init ();
d26a47
 	sync_init (
d26a47
 		corosync_sync_callbacks_retrieve,
d26a47
 		corosync_sync_completed);
d26a47
diff --git a/exec/totemconfig.c b/exec/totemconfig.c
d26a47
index 2acee2a..b678752 100644
d26a47
--- a/exec/totemconfig.c
d26a47
+++ b/exec/totemconfig.c
d26a47
@@ -532,7 +532,73 @@ static int find_local_node_in_nodelist(struct totem_config *totem_config)
d26a47
 	return (local_node_pos);
d26a47
 }
d26a47
 
d26a47
-static void put_nodelist_members_to_config(struct totem_config *totem_config)
d26a47
+/*
d26a47
+ * Compute difference between two set of totem interface arrays. set1 and set2
d26a47
+ * are changed so for same ring, ip existing in both set1 and set2 are cleared
d26a47
+ * (set to 0), and ips which are only in set1 or set2 remains untouched.
d26a47
+ * totempg_node_add/remove is called.
d26a47
+ */
d26a47
+static void compute_interfaces_diff(int interface_count,
d26a47
+	struct totem_interface *set1,
d26a47
+	struct totem_interface *set2)
d26a47
+{
d26a47
+	int ring_no, set1_pos, set2_pos;
d26a47
+	struct totem_ip_address empty_ip_address;
d26a47
+
d26a47
+	memset(&empty_ip_address, 0, sizeof(empty_ip_address));
d26a47
+
d26a47
+	for (ring_no = 0; ring_no < interface_count; ring_no++) {
d26a47
+		for (set1_pos = 0; set1_pos < set1[ring_no].member_count; set1_pos++) {
d26a47
+			for (set2_pos = 0; set2_pos < set2[ring_no].member_count; set2_pos++) {
d26a47
+				/*
d26a47
+				 * For current ring_no remove all set1 items existing
d26a47
+				 * in set2
d26a47
+				 */
d26a47
+				if (memcmp(&set1[ring_no].member_list[set1_pos],
d26a47
+				    &set2[ring_no].member_list[set2_pos],
d26a47
+				    sizeof(struct totem_ip_address)) == 0) {
d26a47
+					memset(&set1[ring_no].member_list[set1_pos], 0,
d26a47
+					    sizeof(struct totem_ip_address));
d26a47
+					memset(&set2[ring_no].member_list[set2_pos], 0,
d26a47
+					    sizeof(struct totem_ip_address));
d26a47
+				}
d26a47
+			}
d26a47
+		}
d26a47
+	}
d26a47
+
d26a47
+	for (ring_no = 0; ring_no < interface_count; ring_no++) {
d26a47
+		for (set1_pos = 0; set1_pos < set1[ring_no].member_count; set1_pos++) {
d26a47
+			/*
d26a47
+			 * All items which remained in set1 doesn't exists in set2 any longer so
d26a47
+			 * node has to be removed.
d26a47
+			 */
d26a47
+			if (memcmp(&set1[ring_no].member_list[set1_pos], &empty_ip_address, sizeof(empty_ip_address)) != 0) {
d26a47
+				log_printf(LOGSYS_LEVEL_DEBUG,
d26a47
+					"removing dynamic member %s for ring %u",
d26a47
+					totemip_print(&set1[ring_no].member_list[set1_pos]),
d26a47
+					ring_no);
d26a47
+
d26a47
+				totempg_member_remove(&set1[ring_no].member_list[set1_pos], ring_no);
d26a47
+			}
d26a47
+		}
d26a47
+		for (set2_pos = 0; set2_pos < set2[ring_no].member_count; set2_pos++) {
d26a47
+			/*
d26a47
+			 * All items which remained in set2 doesn't existed in set1 so this is no node
d26a47
+			 * and has to be added.
d26a47
+			 */
d26a47
+			if (memcmp(&set2[ring_no].member_list[set2_pos], &empty_ip_address, sizeof(empty_ip_address)) != 0) {
d26a47
+				log_printf(LOGSYS_LEVEL_DEBUG,
d26a47
+					"adding dynamic member %s for ring %u",
d26a47
+					totemip_print(&set2[ring_no].member_list[set2_pos]),
d26a47
+					ring_no);
d26a47
+
d26a47
+				totempg_member_add(&set2[ring_no].member_list[set2_pos], ring_no);
d26a47
+			}
d26a47
+		}
d26a47
+	}
d26a47
+}
d26a47
+
d26a47
+static void put_nodelist_members_to_config(struct totem_config *totem_config, int reload)
d26a47
 {
d26a47
 	icmap_iter_t iter, iter2;
d26a47
 	const char *iter_key, *iter_key2;
d26a47
@@ -544,6 +610,22 @@ static void put_nodelist_members_to_config(struct totem_config *totem_config)
d26a47
 	int member_count;
d26a47
 	unsigned int ringnumber = 0;
d26a47
 	int i, j;
d26a47
+	struct totem_interface *orig_interfaces = NULL;
d26a47
+	struct totem_interface *new_interfaces = NULL;
d26a47
+
d26a47
+	if (reload) {
d26a47
+		/*
d26a47
+		 * We need to compute diff only for reload. Also for initial configuration
d26a47
+		 * not all totem structures are initialized so corosync will crash during
d26a47
+		 * member_add/remove
d26a47
+		 */
d26a47
+		orig_interfaces = malloc (sizeof (struct totem_interface) * INTERFACE_MAX);
d26a47
+		assert(orig_interfaces != NULL);
d26a47
+		new_interfaces = malloc (sizeof (struct totem_interface) * INTERFACE_MAX);
d26a47
+		assert(new_interfaces != NULL);
d26a47
+
d26a47
+		memcpy(orig_interfaces, totem_config->interfaces, sizeof (struct totem_interface) * INTERFACE_MAX);
d26a47
+	}
d26a47
 
d26a47
 	/* Clear out nodelist so we can put the new one in if needed */
d26a47
 	for (i = 0; i < totem_config->interface_count; i++) {
d26a47
@@ -590,8 +672,51 @@ static void put_nodelist_members_to_config(struct totem_config *totem_config)
d26a47
 	}
d26a47
 
d26a47
 	icmap_iter_finalize(iter);
d26a47
+
d26a47
+	if (reload) {
d26a47
+		memcpy(new_interfaces, totem_config->interfaces, sizeof (struct totem_interface) * INTERFACE_MAX);
d26a47
+
d26a47
+		compute_interfaces_diff(totem_config->interface_count, orig_interfaces, new_interfaces);
d26a47
+
d26a47
+		free(new_interfaces);
d26a47
+		free(orig_interfaces);
d26a47
+	}
d26a47
+}
d26a47
+
d26a47
+static void nodelist_dynamic_notify(
d26a47
+	int32_t event,
d26a47
+	const char *key_name,
d26a47
+	struct icmap_notify_value new_val,
d26a47
+	struct icmap_notify_value old_val,
d26a47
+	void *user_data)
d26a47
+{
d26a47
+	int res;
d26a47
+	unsigned int ring_no;
d26a47
+	unsigned int member_no;
d26a47
+	char tmp_str[ICMAP_KEYNAME_MAXLEN];
d26a47
+	uint8_t reloading;
d26a47
+	struct totem_config *totem_config = (struct totem_config *)user_data;
d26a47
+
d26a47
+	/*
d26a47
+	* If a full reload is in progress then don't do anything until it's done and
d26a47
+	* can reconfigure it all atomically
d26a47
+	*/
d26a47
+	if (icmap_get_uint8("config.totemconfig_reload_in_progress", &reloading) == CS_OK && reloading) {
d26a47
+		return ;
d26a47
+	}
d26a47
+
d26a47
+	res = sscanf(key_name, "nodelist.node.%u.ring%u%s", &member_no, &ring_no, tmp_str);
d26a47
+	if (res != 3)
d26a47
+		return ;
d26a47
+
d26a47
+	if (strcmp(tmp_str, "_addr") != 0) {
d26a47
+		return;
d26a47
+	}
d26a47
+
d26a47
+	put_nodelist_members_to_config(totem_config, 1);
d26a47
 }
d26a47
 
d26a47
+
d26a47
 /*
d26a47
  * Tries to find node (node_pos) in config nodelist which address matches any
d26a47
  * local interface. Address can be stored in ring0_addr or if ipaddr_key_prefix is not NULL
d26a47
@@ -999,7 +1124,7 @@ extern int totem_config_read (
d26a47
 			icmap_set_ro_access("nodelist.local_node_pos", 0, 1);
d26a47
 		}
d26a47
 
d26a47
-		put_nodelist_members_to_config(totem_config);
d26a47
+		put_nodelist_members_to_config(totem_config, 0);
d26a47
 	}
d26a47
 
d26a47
 	/*
d26a47
@@ -1362,7 +1487,7 @@ static void totem_reload_notify(
d26a47
 
d26a47
 	/* Reload has completed */
d26a47
 	if (*(uint8_t *)new_val.data == 0) {
d26a47
-		put_nodelist_members_to_config (totem_config);
d26a47
+		put_nodelist_members_to_config (totem_config, 1);
d26a47
 		totem_volatile_config_read (totem_config, NULL);
d26a47
 		log_printf(LOGSYS_LEVEL_DEBUG, "Configuration reloaded. Dumping actual totem config.");
d26a47
 		debug_dump_totem_config(totem_config);
d26a47
@@ -1401,4 +1526,10 @@ static void add_totem_config_notification(struct totem_config *totem_config)
d26a47
 		totem_reload_notify,
d26a47
 		totem_config,
d26a47
 		&icmap_track);
d26a47
+
d26a47
+	icmap_track_add("nodelist.node.",
d26a47
+		ICMAP_TRACK_ADD | ICMAP_TRACK_DELETE | ICMAP_TRACK_MODIFY | ICMAP_TRACK_PREFIX,
d26a47
+		nodelist_dynamic_notify,
d26a47
+		(void *)totem_config,
d26a47
+		&icmap_track);
d26a47
 }
d26a47
-- 
d26a47
1.7.1
d26a47