Re: [PATCH] Handle adding and removing UDPU members atomically

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



ACK

Fabio

On 01/21/2015 04:05 PM, Jan Friesse wrote:

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

_______________________________________________
discuss mailing list
discuss@xxxxxxxxxxxx
http://lists.corosync.org/mailman/listinfo/discuss




[Index of Archives]     [Linux Clusters]     [Corosync Project]     [Linux USB Devel]     [Linux Audio Users]     [Photo]     [Yosemite News]    [Yosemite Photos]    [Linux Kernel]     [Linux SCSI]     [X.Org]

  Powered by Linux