File bsc#1181744-0005-Fix-st_client-make-safe-to-remove-notifications-from.patch of Package pacemaker.19271
From 2b038831edf6dd345c3f39f0fc27cfbf9503f512 Mon Sep 17 00:00:00 2001
From: Klaus Wenninger <klaus.wenninger@aon.at>
Date: Tue, 18 Jun 2019 21:54:49 +0200
Subject: [PATCH 5/7] Fix: st_client: make safe to remove notifications from
notifications
While cycling over the notification-list just mark for deletion
and delete afterwards.
---
lib/fencing/st_client.c | 58 ++++++++++++++++++++++++++++++++++++++---
1 file changed, 54 insertions(+), 4 deletions(-)
diff --git a/lib/fencing/st_client.c b/lib/fencing/st_client.c
index 629887a20..ba23ac517 100644
--- a/lib/fencing/st_client.c
+++ b/lib/fencing/st_client.c
@@ -67,6 +67,8 @@ typedef struct stonith_private_s {
mainloop_io_t *source;
GHashTable *stonith_op_callback_table;
GList *notify_list;
+ int notify_refcnt;
+ bool notify_deletes;
void (*op_callback) (stonith_t * st, stonith_callback_data_t * data);
@@ -77,6 +79,7 @@ typedef struct stonith_notify_client_s {
const char *obj_id; /* implement one day */
const char *obj_type; /* implement one day */
void (*notify) (stonith_t * st, stonith_event_t * e);
+ bool delete;
} stonith_notify_client_t;
@@ -211,6 +214,38 @@ log_action(stonith_action_t *action, pid_t pid)
}
}
+/* when cycling through the list we don't want to delete items
+ so just mark them and when we know nobody is using the list
+ loop over it to remove the marked items
+ */
+static void
+foreach_notify_entry (stonith_private_t *private,
+ GFunc func,
+ gpointer user_data)
+{
+ private->notify_refcnt++;
+ g_list_foreach(private->notify_list, func, user_data);
+ private->notify_refcnt--;
+ if ((private->notify_refcnt == 0) &&
+ private->notify_deletes) {
+ GList *list_item = private->notify_list;
+
+ private->notify_deletes = FALSE;
+ while (list_item != NULL)
+ {
+ stonith_notify_client_t *list_client = list_item->data;
+ GList *next = g_list_next(list_item);
+
+ if (list_client->delete) {
+ free(list_client);
+ private->notify_list =
+ g_list_delete_link(private->notify_list, list_item);
+ }
+ list_item = next;
+ }
+ }
+}
+
static void
stonith_connection_destroy(gpointer user_data)
{
@@ -230,7 +265,7 @@ stonith_connection_destroy(gpointer user_data)
crm_xml_add(blob.xml, F_TYPE, T_STONITH_NOTIFY);
crm_xml_add(blob.xml, F_SUBTYPE, T_STONITH_NOTIFY_DISCONNECT);
- g_list_foreach(native->notify_list, stonith_send_notification, &blob);
+ foreach_notify_entry(native, stonith_send_notification, &blob);
free_xml(blob.xml);
}
@@ -1140,6 +1175,10 @@ stonithlib_GCompareFunc(gconstpointer a, gconstpointer b)
const stonith_notify_client_t *a_client = a;
const stonith_notify_client_t *b_client = b;
+ if (a_client->delete || b_client->delete) {
+ /* make entries marked for deletion not findable */
+ return -1;
+ }
CRM_CHECK(a_client->event != NULL && b_client->event != NULL, return 0);
rc = strcmp(a_client->event, b_client->event);
if (rc == 0) {
@@ -1394,7 +1433,7 @@ stonith_dispatch_internal(const char *buffer, ssize_t length, gpointer userdata)
stonith_perform_callback(st, blob.xml, 0, 0);
} else if (safe_str_eq(type, T_STONITH_NOTIFY)) {
- g_list_foreach(private->notify_list, stonith_send_notification, &blob);
+ foreach_notify_entry(private, stonith_send_notification, &blob);
} else if (safe_str_eq(type, T_STONITH_TIMEOUT_VALUE)) {
int call_id = 0;
int timeout = 0;
@@ -1592,8 +1631,13 @@ stonith_api_del_notification(stonith_t * stonith, const char *event)
if (list_item != NULL) {
stonith_notify_client_t *list_client = list_item->data;
- private->notify_list = g_list_remove(private->notify_list, list_client);
- free(list_client);
+ if (private->notify_refcnt) {
+ list_client->delete = TRUE;
+ private->notify_deletes = TRUE;
+ } else {
+ private->notify_list = g_list_remove(private->notify_list, list_client);
+ free(list_client);
+ }
crm_trace("Removed callback");
@@ -1754,6 +1798,10 @@ stonith_send_notification(gpointer data, gpointer user_data)
crm_warn("Skipping callback - NULL callback client");
return;
+ } else if (entry->delete) {
+ crm_trace("Skipping callback - marked for deletion");
+ return;
+
} else if (entry->notify == NULL) {
crm_warn("Skipping callback - NULL callback");
return;
@@ -2037,6 +2085,8 @@ stonith_api_new(void)
private->stonith_op_callback_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
NULL, stonith_destroy_op_callback);
private->notify_list = NULL;
+ private->notify_refcnt = 0;
+ private->notify_deletes = FALSE;
new_stonith->call_id = 1;
new_stonith->state = stonith_disconnected;
--
2.26.2