|
|
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 |
|