From 94edfe9843d33f3fb6cf34314f7eb72d5db6a43f Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Mon, 8 Dec 2025 13:20:45 -0500 Subject: [PATCH 01/25] Refactor: daemons: Split up IPC code in fenced. This brings it in line with how other daemons are organized. Note that unlike other daemons I've reorganized recently, fenced uses both corosync and IPC. This will require further reorganization and refactoring in later commits. For the moment, not everything IPC related is in this file. --- daemons/fenced/Makefile.am | 3 +- daemons/fenced/fenced_ipc.c | 169 ++++++++++++++++++++++++++++++ daemons/fenced/pacemaker-fenced.c | 144 ------------------------- daemons/fenced/pacemaker-fenced.h | 1 + 4 files changed, 172 insertions(+), 145 deletions(-) create mode 100644 daemons/fenced/fenced_ipc.c diff --git a/daemons/fenced/Makefile.am b/daemons/fenced/Makefile.am index 4df1098d67b..2030933a344 100644 --- a/daemons/fenced/Makefile.am +++ b/daemons/fenced/Makefile.am @@ -2,7 +2,7 @@ # Original Author: Sun Jiang Dong # Copyright 2004 International Business Machines # -# with later changes copyright 2004-2024 the Pacemaker project contributors. +# with later changes copyright 2004-2025 the Pacemaker project contributors. # The version control history for this file may have further details. # # This source code is licensed under the GNU General Public License version 2 @@ -42,6 +42,7 @@ pacemaker_fenced_LDADD += $(CLUSTERLIBS) pacemaker_fenced_SOURCES = pacemaker-fenced.c \ fenced_cib.c \ fenced_commands.c \ + fenced_ipc.c \ fenced_remote.c \ fenced_scheduler.c \ fenced_history.c diff --git a/daemons/fenced/fenced_ipc.c b/daemons/fenced/fenced_ipc.c new file mode 100644 index 00000000000..a5a18631b98 --- /dev/null +++ b/daemons/fenced/fenced_ipc.c @@ -0,0 +1,169 @@ +/* + * Copyright 2009-2025 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include + +#include // ECONNREFUSED, ENOMEM +#include // int32_t, uint32_t, PRIu32 +#include // NULL, size_t +#include // gid_t, uid_t + +#include // xmlNode +#include // g_byte_array_free, TRUE +#include // for qb_ipcs_connection_t + +#include "pacemaker-fenced.h" // fenced_get_local_node + +#include // crm_ipc_flags, pcmk_ipc_fenced +#include // pcmk_rc_*, pcmk_rc_str +#include // CRM_OP_RM_NODE_CACHE +#include // stonith_call_options + +static int32_t +st_ipc_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid) +{ + if (stonith_shutdown_flag) { + crm_info("Ignoring new client [%d] during shutdown", + pcmk__client_pid(c)); + return -ECONNREFUSED; + } + + if (pcmk__new_client(c, uid, gid) == NULL) { + return -ENOMEM; + } + return 0; +} + +/* Exit code means? */ +static int32_t +st_ipc_dispatch(qb_ipcs_connection_t * qbc, void *data, size_t size) +{ + uint32_t id = 0; + uint32_t flags = 0; + uint32_t call_options = st_opt_none; + xmlNode *request = NULL; + pcmk__client_t *c = pcmk__find_client(qbc); + const char *op = NULL; + int rc = pcmk_rc_ok; + + if (c == NULL) { + crm_info("Invalid client: %p", qbc); + return 0; + } + + rc = pcmk__ipc_msg_append(&c->buffer, data); + + if (rc == pcmk_rc_ipc_more) { + /* We haven't read the complete message yet, so just return. */ + return 0; + + } else if (rc == pcmk_rc_ok) { + /* We've read the complete message and there's already a header on + * the front. Pass it off for processing. + */ + request = pcmk__client_data2xml(c, &id, &flags); + g_byte_array_free(c->buffer, TRUE); + c->buffer = NULL; + + } else { + /* Some sort of error occurred reassembling the message. All we can + * do is clean up, log an error and return. + */ + crm_err("Error when reading IPC message: %s", pcmk_rc_str(rc)); + + if (c->buffer != NULL) { + g_byte_array_free(c->buffer, TRUE); + c->buffer = NULL; + } + + return 0; + } + + if (request == NULL) { + pcmk__ipc_send_ack(c, id, flags, PCMK__XE_NACK, NULL, CRM_EX_PROTOCOL); + return 0; + } + + op = pcmk__xe_get(request, PCMK__XA_CRM_TASK); + if(pcmk__str_eq(op, CRM_OP_RM_NODE_CACHE, pcmk__str_casei)) { + pcmk__xe_set(request, PCMK__XA_T, PCMK__VALUE_STONITH_NG); + pcmk__xe_set(request, PCMK__XA_ST_OP, op); + pcmk__xe_set(request, PCMK__XA_ST_CLIENTID, c->id); + pcmk__xe_set(request, PCMK__XA_ST_CLIENTNAME, pcmk__client_name(c)); + pcmk__xe_set(request, PCMK__XA_ST_CLIENTNODE, fenced_get_local_node()); + + pcmk__cluster_send_message(NULL, pcmk_ipc_fenced, request); + pcmk__xml_free(request); + return 0; + } + + if (c->name == NULL) { + const char *value = pcmk__xe_get(request, PCMK__XA_ST_CLIENTNAME); + + c->name = pcmk__assert_asprintf("%s.%u", pcmk__s(value, "unknown"), + c->pid); + } + + rc = pcmk__xe_get_flags(request, PCMK__XA_ST_CALLOPT, &call_options, + st_opt_none); + if (rc != pcmk_rc_ok) { + crm_warn("Couldn't parse options from request: %s", pcmk_rc_str(rc)); + } + + crm_trace("Flags %#08" PRIx32 "/%#08x for command %" PRIu32 + " from client %s", flags, call_options, id, pcmk__client_name(c)); + + if (pcmk__is_set(call_options, st_opt_sync_call)) { + pcmk__assert(pcmk__is_set(flags, crm_ipc_client_response)); + CRM_LOG_ASSERT(c->request_id == 0); /* This means the client has two synchronous events in-flight */ + c->request_id = id; /* Reply only to the last one */ + } + + pcmk__xe_set(request, PCMK__XA_ST_CLIENTID, c->id); + pcmk__xe_set(request, PCMK__XA_ST_CLIENTNAME, pcmk__client_name(c)); + pcmk__xe_set(request, PCMK__XA_ST_CLIENTNODE, fenced_get_local_node()); + + crm_log_xml_trace(request, "ipc-received"); + stonith_command(c, id, flags, request, NULL); + + pcmk__xml_free(request); + return 0; +} + +/* Error code means? */ +static int32_t +st_ipc_closed(qb_ipcs_connection_t * c) +{ + pcmk__client_t *client = pcmk__find_client(c); + + if (client == NULL) { + return 0; + } + + crm_trace("Connection %p closed", c); + pcmk__free_client(client); + + /* 0 means: yes, go ahead and destroy the connection */ + return 0; +} + +static void +st_ipc_destroy(qb_ipcs_connection_t * c) +{ + crm_trace("Connection %p destroyed", c); + st_ipc_closed(c); +} + +struct qb_ipcs_service_handlers ipc_callbacks = { + .connection_accept = st_ipc_accept, + .connection_created = NULL, + .msg_process = st_ipc_dispatch, + .connection_closed = st_ipc_closed, + .connection_destroyed = st_ipc_destroy +}; diff --git a/daemons/fenced/pacemaker-fenced.c b/daemons/fenced/pacemaker-fenced.c index 57cb83dc2e7..e4ad8540289 100644 --- a/daemons/fenced/pacemaker-fenced.c +++ b/daemons/fenced/pacemaker-fenced.c @@ -68,142 +68,6 @@ crm_exit_t exit_code = CRM_EX_OK; static void stonith_cleanup(void); -static int32_t -st_ipc_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid) -{ - if (stonith_shutdown_flag) { - crm_info("Ignoring new client [%d] during shutdown", - pcmk__client_pid(c)); - return -ECONNREFUSED; - } - - if (pcmk__new_client(c, uid, gid) == NULL) { - return -ENOMEM; - } - return 0; -} - -/* Exit code means? */ -static int32_t -st_ipc_dispatch(qb_ipcs_connection_t * qbc, void *data, size_t size) -{ - uint32_t id = 0; - uint32_t flags = 0; - uint32_t call_options = st_opt_none; - xmlNode *request = NULL; - pcmk__client_t *c = pcmk__find_client(qbc); - const char *op = NULL; - int rc = pcmk_rc_ok; - - if (c == NULL) { - crm_info("Invalid client: %p", qbc); - return 0; - } - - rc = pcmk__ipc_msg_append(&c->buffer, data); - - if (rc == pcmk_rc_ipc_more) { - /* We haven't read the complete message yet, so just return. */ - return 0; - - } else if (rc == pcmk_rc_ok) { - /* We've read the complete message and there's already a header on - * the front. Pass it off for processing. - */ - request = pcmk__client_data2xml(c, &id, &flags); - g_byte_array_free(c->buffer, TRUE); - c->buffer = NULL; - - } else { - /* Some sort of error occurred reassembling the message. All we can - * do is clean up, log an error and return. - */ - crm_err("Error when reading IPC message: %s", pcmk_rc_str(rc)); - - if (c->buffer != NULL) { - g_byte_array_free(c->buffer, TRUE); - c->buffer = NULL; - } - - return 0; - } - - if (request == NULL) { - pcmk__ipc_send_ack(c, id, flags, PCMK__XE_NACK, NULL, CRM_EX_PROTOCOL); - return 0; - } - - op = pcmk__xe_get(request, PCMK__XA_CRM_TASK); - if(pcmk__str_eq(op, CRM_OP_RM_NODE_CACHE, pcmk__str_casei)) { - pcmk__xe_set(request, PCMK__XA_T, PCMK__VALUE_STONITH_NG); - pcmk__xe_set(request, PCMK__XA_ST_OP, op); - pcmk__xe_set(request, PCMK__XA_ST_CLIENTID, c->id); - pcmk__xe_set(request, PCMK__XA_ST_CLIENTNAME, pcmk__client_name(c)); - pcmk__xe_set(request, PCMK__XA_ST_CLIENTNODE, fenced_get_local_node()); - - pcmk__cluster_send_message(NULL, pcmk_ipc_fenced, request); - pcmk__xml_free(request); - return 0; - } - - if (c->name == NULL) { - const char *value = pcmk__xe_get(request, PCMK__XA_ST_CLIENTNAME); - - c->name = pcmk__assert_asprintf("%s.%u", pcmk__s(value, "unknown"), - c->pid); - } - - rc = pcmk__xe_get_flags(request, PCMK__XA_ST_CALLOPT, &call_options, - st_opt_none); - if (rc != pcmk_rc_ok) { - crm_warn("Couldn't parse options from IPC request: %s", - pcmk_rc_str(rc)); - } - - crm_trace("Flags %#08" PRIx32 "/%#08x for command %" PRIu32 - " from client %s", flags, call_options, id, pcmk__client_name(c)); - - if (pcmk__is_set(call_options, st_opt_sync_call)) { - pcmk__assert(pcmk__is_set(flags, crm_ipc_client_response)); - CRM_LOG_ASSERT(c->request_id == 0); /* This means the client has two synchronous events in-flight */ - c->request_id = id; /* Reply only to the last one */ - } - - pcmk__xe_set(request, PCMK__XA_ST_CLIENTID, c->id); - pcmk__xe_set(request, PCMK__XA_ST_CLIENTNAME, pcmk__client_name(c)); - pcmk__xe_set(request, PCMK__XA_ST_CLIENTNODE, fenced_get_local_node()); - - crm_log_xml_trace(request, "ipc-received"); - stonith_command(c, id, flags, request, NULL); - - pcmk__xml_free(request); - return 0; -} - -/* Error code means? */ -static int32_t -st_ipc_closed(qb_ipcs_connection_t * c) -{ - pcmk__client_t *client = pcmk__find_client(c); - - if (client == NULL) { - return 0; - } - - crm_trace("Connection %p closed", c); - pcmk__free_client(client); - - /* 0 means: yes, go ahead and destroy the connection */ - return 0; -} - -static void -st_ipc_destroy(qb_ipcs_connection_t * c) -{ - crm_trace("Connection %p destroyed", c); - st_ipc_closed(c); -} - static void stonith_peer_callback(xmlNode * msg, void *private_data) { @@ -474,14 +338,6 @@ stonith_cleanup(void) fenced_unregister_handlers(); } -struct qb_ipcs_service_handlers ipc_callbacks = { - .connection_accept = st_ipc_accept, - .connection_created = NULL, - .msg_process = st_ipc_dispatch, - .connection_closed = st_ipc_closed, - .connection_destroyed = st_ipc_destroy -}; - /*! * \internal * \brief Callback for peer status changes diff --git a/daemons/fenced/pacemaker-fenced.h b/daemons/fenced/pacemaker-fenced.h index e46f26102e9..1ba0b7702bd 100644 --- a/daemons/fenced/pacemaker-fenced.h +++ b/daemons/fenced/pacemaker-fenced.h @@ -401,3 +401,4 @@ extern GList *stonith_watchdog_targets; extern GHashTable *stonith_remote_op_list; extern crm_exit_t exit_code; extern gboolean stonith_shutdown_flag; +extern struct qb_ipcs_service_handlers ipc_callbacks; From 8d8a687ec24ea20b8564d57fbb2f51d8bec9866a Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Mon, 8 Dec 2025 13:22:14 -0500 Subject: [PATCH 02/25] Refactor: daemons: Rename functions in fenced_ipc.c. --- daemons/fenced/fenced_ipc.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/daemons/fenced/fenced_ipc.c b/daemons/fenced/fenced_ipc.c index a5a18631b98..0a20b85edff 100644 --- a/daemons/fenced/fenced_ipc.c +++ b/daemons/fenced/fenced_ipc.c @@ -26,7 +26,7 @@ #include // stonith_call_options static int32_t -st_ipc_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid) +fenced_ipc_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid) { if (stonith_shutdown_flag) { crm_info("Ignoring new client [%d] during shutdown", @@ -42,7 +42,7 @@ st_ipc_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid) /* Exit code means? */ static int32_t -st_ipc_dispatch(qb_ipcs_connection_t * qbc, void *data, size_t size) +fenced_ipc_dispatch(qb_ipcs_connection_t * qbc, void *data, size_t size) { uint32_t id = 0; uint32_t flags = 0; @@ -138,7 +138,7 @@ st_ipc_dispatch(qb_ipcs_connection_t * qbc, void *data, size_t size) /* Error code means? */ static int32_t -st_ipc_closed(qb_ipcs_connection_t * c) +fenced_ipc_closed(qb_ipcs_connection_t * c) { pcmk__client_t *client = pcmk__find_client(c); @@ -154,16 +154,16 @@ st_ipc_closed(qb_ipcs_connection_t * c) } static void -st_ipc_destroy(qb_ipcs_connection_t * c) +fenced_ipc_destroy(qb_ipcs_connection_t * c) { crm_trace("Connection %p destroyed", c); - st_ipc_closed(c); + fenced_ipc_closed(c); } struct qb_ipcs_service_handlers ipc_callbacks = { - .connection_accept = st_ipc_accept, + .connection_accept = fenced_ipc_accept, .connection_created = NULL, - .msg_process = st_ipc_dispatch, - .connection_closed = st_ipc_closed, - .connection_destroyed = st_ipc_destroy + .msg_process = fenced_ipc_dispatch, + .connection_closed = fenced_ipc_closed, + .connection_destroyed = fenced_ipc_destroy }; From 745784de949b4a79f21d7a83b8bf0cc17109ebf8 Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Mon, 8 Dec 2025 13:52:36 -0500 Subject: [PATCH 03/25] Refactor: daemons: Standardize functions in fenced_ipc.c. * Add doxygen comments to explain what each function does. * Remove unnecessary whitespace in function headers. * Standardize log messages with what's happening in the same functions in attrd. * Standardize variable names (c becomes client, qbc becomes c, request becomes msg). * Make sure return values and comments match what libqb documents. --- daemons/fenced/fenced_ipc.c | 136 ++++++++++++++++++++++-------------- 1 file changed, 85 insertions(+), 51 deletions(-) diff --git a/daemons/fenced/fenced_ipc.c b/daemons/fenced/fenced_ipc.c index 0a20b85edff..c3673b8d0ab 100644 --- a/daemons/fenced/fenced_ipc.c +++ b/daemons/fenced/fenced_ipc.c @@ -25,11 +25,22 @@ #include // CRM_OP_RM_NODE_CACHE #include // stonith_call_options +/*! + * \internal + * \brief Accept a new client IPC connection + * + * \param[in,out] c New connection + * \param[in] uid Client user id + * \param[in] gid Client group id + * + * \return 0 on success, -errno otherwise + */ static int32_t -fenced_ipc_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid) +fenced_ipc_accept(qb_ipcs_connection_t *c, uid_t uid, gid_t gid) { + crm_trace("New client connection %p", c); if (stonith_shutdown_flag) { - crm_info("Ignoring new client [%d] during shutdown", + crm_info("Ignoring new connection from pid %d during shutdown", pcmk__client_pid(c)); return -ECONNREFUSED; } @@ -40,24 +51,32 @@ fenced_ipc_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid) return 0; } -/* Exit code means? */ +/*! + * \internal + * \brief Handle a message from an IPC connection + * + * \param[in,out] c Established IPC connection + * \param[in] data The message data read from the connection - this can be + * a complete IPC message or just a part of one if it's + * very large + * \param[in] size Unused + * + * \return 0 in all cases + */ static int32_t -fenced_ipc_dispatch(qb_ipcs_connection_t * qbc, void *data, size_t size) +fenced_ipc_dispatch(qb_ipcs_connection_t *c, void *data, size_t size) { uint32_t id = 0; uint32_t flags = 0; uint32_t call_options = st_opt_none; - xmlNode *request = NULL; - pcmk__client_t *c = pcmk__find_client(qbc); + xmlNode *msg = NULL; + pcmk__client_t *client = pcmk__find_client(c); const char *op = NULL; int rc = pcmk_rc_ok; - if (c == NULL) { - crm_info("Invalid client: %p", qbc); - return 0; - } + CRM_CHECK(client != NULL, return 0); - rc = pcmk__ipc_msg_append(&c->buffer, data); + rc = pcmk__ipc_msg_append(&client->buffer, data); if (rc == pcmk_rc_ipc_more) { /* We haven't read the complete message yet, so just return. */ @@ -67,9 +86,9 @@ fenced_ipc_dispatch(qb_ipcs_connection_t * qbc, void *data, size_t size) /* We've read the complete message and there's already a header on * the front. Pass it off for processing. */ - request = pcmk__client_data2xml(c, &id, &flags); - g_byte_array_free(c->buffer, TRUE); - c->buffer = NULL; + msg = pcmk__client_data2xml(client, &id, &flags); + g_byte_array_free(client->buffer, TRUE); + client->buffer = NULL; } else { /* Some sort of error occurred reassembling the message. All we can @@ -77,86 +96,101 @@ fenced_ipc_dispatch(qb_ipcs_connection_t * qbc, void *data, size_t size) */ crm_err("Error when reading IPC message: %s", pcmk_rc_str(rc)); - if (c->buffer != NULL) { - g_byte_array_free(c->buffer, TRUE); - c->buffer = NULL; + if (client->buffer != NULL) { + g_byte_array_free(client->buffer, TRUE); + client->buffer = NULL; } return 0; } - if (request == NULL) { - pcmk__ipc_send_ack(c, id, flags, PCMK__XE_NACK, NULL, CRM_EX_PROTOCOL); + if (msg == NULL) { + pcmk__ipc_send_ack(client, id, flags, PCMK__XE_NACK, NULL, CRM_EX_PROTOCOL); return 0; } - op = pcmk__xe_get(request, PCMK__XA_CRM_TASK); + op = pcmk__xe_get(msg, PCMK__XA_CRM_TASK); if(pcmk__str_eq(op, CRM_OP_RM_NODE_CACHE, pcmk__str_casei)) { - pcmk__xe_set(request, PCMK__XA_T, PCMK__VALUE_STONITH_NG); - pcmk__xe_set(request, PCMK__XA_ST_OP, op); - pcmk__xe_set(request, PCMK__XA_ST_CLIENTID, c->id); - pcmk__xe_set(request, PCMK__XA_ST_CLIENTNAME, pcmk__client_name(c)); - pcmk__xe_set(request, PCMK__XA_ST_CLIENTNODE, fenced_get_local_node()); - - pcmk__cluster_send_message(NULL, pcmk_ipc_fenced, request); - pcmk__xml_free(request); + pcmk__xe_set(msg, PCMK__XA_T, PCMK__VALUE_STONITH_NG); + pcmk__xe_set(msg, PCMK__XA_ST_OP, op); + pcmk__xe_set(msg, PCMK__XA_ST_CLIENTID, client->id); + pcmk__xe_set(msg, PCMK__XA_ST_CLIENTNAME, pcmk__client_name(client)); + pcmk__xe_set(msg, PCMK__XA_ST_CLIENTNODE, fenced_get_local_node()); + + pcmk__cluster_send_message(NULL, pcmk_ipc_fenced, msg); + pcmk__xml_free(msg); return 0; } - if (c->name == NULL) { - const char *value = pcmk__xe_get(request, PCMK__XA_ST_CLIENTNAME); + if (client->name == NULL) { + const char *value = pcmk__xe_get(msg, PCMK__XA_ST_CLIENTNAME); - c->name = pcmk__assert_asprintf("%s.%u", pcmk__s(value, "unknown"), - c->pid); + client->name = pcmk__assert_asprintf("%s.%u", pcmk__s(value, "unknown"), + client->pid); } - rc = pcmk__xe_get_flags(request, PCMK__XA_ST_CALLOPT, &call_options, + rc = pcmk__xe_get_flags(msg, PCMK__XA_ST_CALLOPT, &call_options, st_opt_none); if (rc != pcmk_rc_ok) { crm_warn("Couldn't parse options from request: %s", pcmk_rc_str(rc)); } crm_trace("Flags %#08" PRIx32 "/%#08x for command %" PRIu32 - " from client %s", flags, call_options, id, pcmk__client_name(c)); + " from client %s", flags, call_options, id, pcmk__client_name(client)); if (pcmk__is_set(call_options, st_opt_sync_call)) { pcmk__assert(pcmk__is_set(flags, crm_ipc_client_response)); - CRM_LOG_ASSERT(c->request_id == 0); /* This means the client has two synchronous events in-flight */ - c->request_id = id; /* Reply only to the last one */ + CRM_LOG_ASSERT(client->request_id == 0); /* This means the client has two synchronous events in-flight */ + client->request_id = id; /* Reply only to the last one */ } - pcmk__xe_set(request, PCMK__XA_ST_CLIENTID, c->id); - pcmk__xe_set(request, PCMK__XA_ST_CLIENTNAME, pcmk__client_name(c)); - pcmk__xe_set(request, PCMK__XA_ST_CLIENTNODE, fenced_get_local_node()); + pcmk__xe_set(msg, PCMK__XA_ST_CLIENTID, client->id); + pcmk__xe_set(msg, PCMK__XA_ST_CLIENTNAME, pcmk__client_name(client)); + pcmk__xe_set(msg, PCMK__XA_ST_CLIENTNODE, fenced_get_local_node()); - crm_log_xml_trace(request, "ipc-received"); - stonith_command(c, id, flags, request, NULL); + crm_log_xml_trace(msg, "ipc-received"); + stonith_command(client, id, flags, msg, NULL); - pcmk__xml_free(request); + pcmk__xml_free(msg); return 0; } -/* Error code means? */ +/*! + * \internal + * \brief Destroy a client IPC connection + * + * \param[in] c Connection to destroy + * + * \return 0 (i.e. do not re-run this callback) + */ static int32_t -fenced_ipc_closed(qb_ipcs_connection_t * c) +fenced_ipc_closed(qb_ipcs_connection_t *c) { pcmk__client_t *client = pcmk__find_client(c); if (client == NULL) { - return 0; + crm_trace("Ignoring request to clean up unknown connection %p", c); + } else { + crm_trace("Cleaning up closed client connection %p", c); + pcmk__free_client(client); } - crm_trace("Connection %p closed", c); - pcmk__free_client(client); - - /* 0 means: yes, go ahead and destroy the connection */ return 0; } +/*! + * \internal + * \brief Destroy a client IPC connection + * + * \param[in] c Connection to destroy + * + * \note We handle a destroyed connection the same as a closed one, + * but we need a separate handler because the return type is different. + */ static void -fenced_ipc_destroy(qb_ipcs_connection_t * c) +fenced_ipc_destroy(qb_ipcs_connection_t *c) { - crm_trace("Connection %p destroyed", c); + crm_trace("Destroying client connection %p", c); fenced_ipc_closed(c); } From 525ed7bed3e464d6532cb0f9ab421158f42247ae Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Mon, 8 Dec 2025 13:59:09 -0500 Subject: [PATCH 04/25] Refactor: daemons: Standardize fenced IPC startup/shutdown. * Add fenced_ipc_init to register callback functions and add them to the mainloop. This means the callback struct can now be static. * Add fenced_ipc_cleanup to clean up. This includes client dropping and cleanup tasks that were previously not happening. I'm not sure if this was a bug or if it doesn't really matter, but it's still good to do this in all daemons. --- daemons/fenced/fenced_ipc.c | 27 ++++++++++++++++++++++++++- daemons/fenced/pacemaker-fenced.c | 11 ++--------- daemons/fenced/pacemaker-fenced.h | 4 +++- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/daemons/fenced/fenced_ipc.c b/daemons/fenced/fenced_ipc.c index c3673b8d0ab..789ceca8372 100644 --- a/daemons/fenced/fenced_ipc.c +++ b/daemons/fenced/fenced_ipc.c @@ -25,6 +25,8 @@ #include // CRM_OP_RM_NODE_CACHE #include // stonith_call_options +static qb_ipcs_service_t *ipcs = NULL; + /*! * \internal * \brief Accept a new client IPC connection @@ -194,10 +196,33 @@ fenced_ipc_destroy(qb_ipcs_connection_t *c) fenced_ipc_closed(c); } -struct qb_ipcs_service_handlers ipc_callbacks = { +static struct qb_ipcs_service_handlers ipc_callbacks = { .connection_accept = fenced_ipc_accept, .connection_created = NULL, .msg_process = fenced_ipc_dispatch, .connection_closed = fenced_ipc_closed, .connection_destroyed = fenced_ipc_destroy }; + +void +fenced_ipc_cleanup(void) +{ + if (ipcs != NULL) { + pcmk__drop_all_clients(ipcs); + qb_ipcs_destroy(ipcs); + ipcs = NULL; + } + + fenced_unregister_handlers(); + pcmk__client_cleanup(); +} + +/*! + * \internal + * \brief Set up fenced IPC communication + */ +void +fenced_ipc_init(void) +{ + pcmk__serve_fenced_ipc(&ipcs, &ipc_callbacks); +} diff --git a/daemons/fenced/pacemaker-fenced.c b/daemons/fenced/pacemaker-fenced.c index e4ad8540289..41fe51cf193 100644 --- a/daemons/fenced/pacemaker-fenced.c +++ b/daemons/fenced/pacemaker-fenced.c @@ -49,7 +49,6 @@ static GMainLoop *mainloop = NULL; gboolean stonith_shutdown_flag = FALSE; -static qb_ipcs_service_t *ipcs = NULL; static pcmk__output_t *out = NULL; pcmk__supported_format_t formats[] = { @@ -325,17 +324,12 @@ static void stonith_cleanup(void) { fenced_cib_cleanup(); - if (ipcs) { - qb_ipcs_destroy(ipcs); - } - + fenced_ipc_cleanup(); pcmk__cluster_destroy_node_caches(); - pcmk__client_cleanup(); free_stonith_remote_op_list(); free_topology_list(); fenced_free_device_table(); free_metadata_cache(); - fenced_unregister_handlers(); } /*! @@ -524,8 +518,7 @@ main(int argc, char **argv) fenced_init_device_table(); init_topology_list(); - - pcmk__serve_fenced_ipc(&ipcs, &ipc_callbacks); + fenced_ipc_init(); // Create the mainloop and run it... mainloop = g_main_loop_new(NULL, FALSE); diff --git a/daemons/fenced/pacemaker-fenced.h b/daemons/fenced/pacemaker-fenced.h index 1ba0b7702bd..52e25867bba 100644 --- a/daemons/fenced/pacemaker-fenced.h +++ b/daemons/fenced/pacemaker-fenced.h @@ -377,6 +377,9 @@ const char *fenced_get_local_node(void); void fenced_scheduler_cleanup(void); void fenced_scheduler_run(xmlNode *cib); +void fenced_ipc_init(void); +void fenced_ipc_cleanup(void); + /*! * \internal * \brief Get the device flag to use with a given action when searching devices @@ -401,4 +404,3 @@ extern GList *stonith_watchdog_targets; extern GHashTable *stonith_remote_op_list; extern crm_exit_t exit_code; extern gboolean stonith_shutdown_flag; -extern struct qb_ipcs_service_handlers ipc_callbacks; From 77a5ac0957ae87c6b98e4e919f02605b28c587d1 Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Tue, 9 Dec 2025 10:42:27 -0500 Subject: [PATCH 05/25] Refactor: daemons: Move corosync-related code into fenced_corosync.c. This isn't all the corosync code - just the initial setup/teardown stuff. There are no code changes aside from renaming the cluster variable to fenced_cluster and defining it in fenced_corosync.c. --- daemons/fenced/Makefile.am | 1 + daemons/fenced/fenced_corosync.c | 129 ++++++++++++++++++++++++++++++ daemons/fenced/pacemaker-fenced.c | 104 ++---------------------- daemons/fenced/pacemaker-fenced.h | 3 + 4 files changed, 141 insertions(+), 96 deletions(-) create mode 100644 daemons/fenced/fenced_corosync.c diff --git a/daemons/fenced/Makefile.am b/daemons/fenced/Makefile.am index 2030933a344..801f4b63655 100644 --- a/daemons/fenced/Makefile.am +++ b/daemons/fenced/Makefile.am @@ -42,6 +42,7 @@ pacemaker_fenced_LDADD += $(CLUSTERLIBS) pacemaker_fenced_SOURCES = pacemaker-fenced.c \ fenced_cib.c \ fenced_commands.c \ + fenced_corosync.c \ fenced_ipc.c \ fenced_remote.c \ fenced_scheduler.c \ diff --git a/daemons/fenced/fenced_corosync.c b/daemons/fenced/fenced_corosync.c new file mode 100644 index 00000000000..633d1fb0c3c --- /dev/null +++ b/daemons/fenced/fenced_corosync.c @@ -0,0 +1,129 @@ +/* + * Copyright 2009-2025 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include + +#include // uint32_t, PRIu32 +#include // NULL, free, size_t + +#include // cpg_handle_t, cpg_name +#include // gpointer +#include // xmlNode + +#include // pcmk_cluster_connect +#include // pcmk_ipc_server +#include // pcmk_rc_* + +#include "pacemaker-fenced.h" + +pcmk_cluster_t *fenced_cluster = NULL; + +static void +stonith_peer_callback(xmlNode * msg, void *private_data) +{ + const char *remote_peer = pcmk__xe_get(msg, PCMK__XA_SRC); + const char *op = pcmk__xe_get(msg, PCMK__XA_ST_OP); + + if (pcmk__str_eq(op, STONITH_OP_POKE, pcmk__str_none)) { + return; + } + + crm_log_xml_trace(msg, "Peer[inbound]"); + stonith_command(NULL, 0, 0, msg, remote_peer); +} + +/*! + * \internal + * \brief Callback for peer status changes + * + * \param[in] type What changed + * \param[in] node What peer had the change + * \param[in] data Previous value of what changed + */ +static void +st_peer_update_callback(enum pcmk__node_update type, pcmk__node_status_t *node, + const void *data) +{ + if ((type != pcmk__node_update_processes) + && !pcmk__is_set(node->flags, pcmk__node_status_remote)) { + /* + * This is a hack until we can send to a nodeid and/or we fix node name lookups + * These messages are ignored in stonith_peer_callback() + */ + xmlNode *query = pcmk__xe_create(NULL, PCMK__XE_STONITH_COMMAND); + + pcmk__xe_set(query, PCMK__XA_T, PCMK__VALUE_STONITH_NG); + pcmk__xe_set(query, PCMK__XA_ST_OP, STONITH_OP_POKE); + + crm_debug("Broadcasting our uname because of node %" PRIu32, + node->cluster_layer_id); + pcmk__cluster_send_message(NULL, pcmk_ipc_fenced, query); + + pcmk__xml_free(query); + } +} + +#if SUPPORT_COROSYNC +static void +handle_cpg_message(cpg_handle_t handle, const struct cpg_name *groupName, + uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len) +{ + xmlNode *xml = NULL; + const char *from = NULL; + char *data = pcmk__cpg_message_data(handle, nodeid, pid, msg, &from); + + if(data == NULL) { + return; + } + + xml = pcmk__xml_parse(data); + if (xml == NULL) { + crm_err("Invalid XML: '%.120s'", data); + free(data); + return; + } + pcmk__xe_set(xml, PCMK__XA_SRC, from); + stonith_peer_callback(xml, NULL); + + pcmk__xml_free(xml); + free(data); +} + +static void +stonith_peer_cs_destroy(gpointer user_data) +{ + crm_crit("Lost connection to cluster layer, shutting down"); + stonith_shutdown(0); +} +#endif // SUPPORT_COROSYNC + +int +fenced_cluster_connect(void) +{ + int rc = pcmk_rc_ok; + + fenced_cluster = pcmk_cluster_new(); + +#if SUPPORT_COROSYNC + if (pcmk_get_cluster_layer() == pcmk_cluster_layer_corosync) { + pcmk_cluster_set_destroy_fn(fenced_cluster, stonith_peer_cs_destroy); + pcmk_cpg_set_deliver_fn(fenced_cluster, handle_cpg_message); + pcmk_cpg_set_confchg_fn(fenced_cluster, pcmk__cpg_confchg_cb); + } +#endif // SUPPORT_COROSYNC + + pcmk__cluster_set_status_callback(&st_peer_update_callback); + + rc = pcmk_cluster_connect(fenced_cluster); + if (rc != pcmk_rc_ok) { + crm_err("Cluster connection failed"); + } + + return rc; +} diff --git a/daemons/fenced/pacemaker-fenced.c b/daemons/fenced/pacemaker-fenced.c index 41fe51cf193..e70a73faa0e 100644 --- a/daemons/fenced/pacemaker-fenced.c +++ b/daemons/fenced/pacemaker-fenced.c @@ -67,54 +67,6 @@ crm_exit_t exit_code = CRM_EX_OK; static void stonith_cleanup(void); -static void -stonith_peer_callback(xmlNode * msg, void *private_data) -{ - const char *remote_peer = pcmk__xe_get(msg, PCMK__XA_SRC); - const char *op = pcmk__xe_get(msg, PCMK__XA_ST_OP); - - if (pcmk__str_eq(op, STONITH_OP_POKE, pcmk__str_none)) { - return; - } - - crm_log_xml_trace(msg, "Peer[inbound]"); - stonith_command(NULL, 0, 0, msg, remote_peer); -} - -#if SUPPORT_COROSYNC -static void -handle_cpg_message(cpg_handle_t handle, const struct cpg_name *groupName, - uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len) -{ - xmlNode *xml = NULL; - const char *from = NULL; - char *data = pcmk__cpg_message_data(handle, nodeid, pid, msg, &from); - - if(data == NULL) { - return; - } - - xml = pcmk__xml_parse(data); - if (xml == NULL) { - crm_err("Invalid XML: '%.120s'", data); - free(data); - return; - } - pcmk__xe_set(xml, PCMK__XA_SRC, from); - stonith_peer_callback(xml, NULL); - - pcmk__xml_free(xml); - free(data); -} - -static void -stonith_peer_cs_destroy(gpointer user_data) -{ - crm_crit("Lost connection to cluster layer, shutting down"); - stonith_shutdown(0); -} -#endif - void do_local_reply(const xmlNode *notify_src, pcmk__client_t *client, int call_options) @@ -332,37 +284,6 @@ stonith_cleanup(void) free_metadata_cache(); } -/*! - * \internal - * \brief Callback for peer status changes - * - * \param[in] type What changed - * \param[in] node What peer had the change - * \param[in] data Previous value of what changed - */ -static void -st_peer_update_callback(enum pcmk__node_update type, pcmk__node_status_t *node, - const void *data) -{ - if ((type != pcmk__node_update_processes) - && !pcmk__is_set(node->flags, pcmk__node_status_remote)) { - /* - * This is a hack until we can send to a nodeid and/or we fix node name lookups - * These messages are ignored in stonith_peer_callback() - */ - xmlNode *query = pcmk__xe_create(NULL, PCMK__XE_STONITH_COMMAND); - - pcmk__xe_set(query, PCMK__XA_T, PCMK__VALUE_STONITH_NG); - pcmk__xe_set(query, PCMK__XA_ST_OP, STONITH_OP_POKE); - - crm_debug("Broadcasting our uname because of node %" PRIu32, - node->cluster_layer_id); - pcmk__cluster_send_message(NULL, pcmk_ipc_fenced, query); - - pcmk__xml_free(query); - } -} - /* @COMPAT Deprecated since 2.1.8. Use pcmk_list_fence_attrs() or * crm_resource --list-options=fencing instead of querying daemon metadata. * @@ -407,7 +328,6 @@ int main(int argc, char **argv) { int rc = pcmk_rc_ok; - pcmk_cluster_t *cluster = NULL; crm_ipc_t *old_instance = NULL; GError *error = NULL; @@ -493,24 +413,16 @@ main(int argc, char **argv) goto done; } - cluster = pcmk_cluster_new(); - -#if SUPPORT_COROSYNC - if (pcmk_get_cluster_layer() == pcmk_cluster_layer_corosync) { - pcmk_cluster_set_destroy_fn(cluster, stonith_peer_cs_destroy); - pcmk_cpg_set_deliver_fn(cluster, handle_cpg_message); - pcmk_cpg_set_confchg_fn(cluster, pcmk__cpg_confchg_cb); - } -#endif // SUPPORT_COROSYNC - - pcmk__cluster_set_status_callback(&st_peer_update_callback); - - if (pcmk_cluster_connect(cluster) != pcmk_rc_ok) { + if (fenced_cluster_connect() != pcmk_rc_ok) { exit_code = CRM_EX_FATAL; - crm_crit("Cannot sign in to the cluster... terminating"); + g_set_error(&error, PCMK__EXITC_ERROR, exit_code, + "Could not connect to the cluster"); goto done; } - fenced_set_local_node(cluster->priv->node_name); + + crm_info("Cluster connection active"); + + fenced_set_local_node(fenced_cluster->priv->node_name); if (!options.stand_alone) { setup_cib(); @@ -532,7 +444,7 @@ main(int argc, char **argv) g_strfreev(options.log_files); stonith_cleanup(); - pcmk_cluster_free(cluster); + pcmk_cluster_free(fenced_cluster); fenced_scheduler_cleanup(); pcmk__output_and_clear_error(&error, out); diff --git a/daemons/fenced/pacemaker-fenced.h b/daemons/fenced/pacemaker-fenced.h index 52e25867bba..f758bb8e3dc 100644 --- a/daemons/fenced/pacemaker-fenced.h +++ b/daemons/fenced/pacemaker-fenced.h @@ -380,6 +380,8 @@ void fenced_scheduler_run(xmlNode *cib); void fenced_ipc_init(void); void fenced_ipc_cleanup(void); +int fenced_cluster_connect(void); + /*! * \internal * \brief Get the device flag to use with a given action when searching devices @@ -404,3 +406,4 @@ extern GList *stonith_watchdog_targets; extern GHashTable *stonith_remote_op_list; extern crm_exit_t exit_code; extern gboolean stonith_shutdown_flag; +extern pcmk_cluster_t *fenced_cluster; From 2a772008078d8197d38aec1d67c782fed28e13d6 Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Tue, 9 Dec 2025 10:52:22 -0500 Subject: [PATCH 06/25] Refactor: daemons: Use standard return codes in attrd_cluster_connect. --- daemons/attrd/attrd_corosync.c | 7 +++---- daemons/attrd/pacemaker-attrd.c | 3 ++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/daemons/attrd/attrd_corosync.c b/daemons/attrd/attrd_corosync.c index 6d79aca0796..7e6b612ef64 100644 --- a/daemons/attrd/attrd_corosync.c +++ b/daemons/attrd/attrd_corosync.c @@ -469,12 +469,11 @@ attrd_cluster_connect(void) pcmk__cluster_set_status_callback(&attrd_peer_change_cb); rc = pcmk_cluster_connect(attrd_cluster); - rc = pcmk_rc2legacy(rc); - if (rc != pcmk_ok) { + if (rc != pcmk_rc_ok) { crm_err("Cluster connection failed"); - return rc; } - return pcmk_ok; + + return rc; } void diff --git a/daemons/attrd/pacemaker-attrd.c b/daemons/attrd/pacemaker-attrd.c index 1bbb129d1ea..3f14772ba5d 100644 --- a/daemons/attrd/pacemaker-attrd.c +++ b/daemons/attrd/pacemaker-attrd.c @@ -164,12 +164,13 @@ main(int argc, char **argv) crm_info("CIB connection active"); } - if (attrd_cluster_connect() != pcmk_ok) { + if (attrd_cluster_connect() != pcmk_rc_ok) { attrd_exit_status = CRM_EX_FATAL; g_set_error(&error, PCMK__EXITC_ERROR, attrd_exit_status, "Could not connect to the cluster"); goto done; } + crm_info("Cluster connection active"); // Initialization that requires the cluster to be connected From c1f6876f0fffc8a4cbd34aafb9adaee7ab4b1d71 Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Tue, 9 Dec 2025 10:55:23 -0500 Subject: [PATCH 07/25] Refactor: daemons: Rename callbacks in fenced_corosync.c. This brings them in line with what's happening in attrd. Note that stonith_peer_callback remains unchanged, but there's other things that need to be done to that function so it will be handled separately. --- daemons/fenced/fenced_corosync.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/daemons/fenced/fenced_corosync.c b/daemons/fenced/fenced_corosync.c index 633d1fb0c3c..9900e07fdcd 100644 --- a/daemons/fenced/fenced_corosync.c +++ b/daemons/fenced/fenced_corosync.c @@ -47,7 +47,7 @@ stonith_peer_callback(xmlNode * msg, void *private_data) * \param[in] data Previous value of what changed */ static void -st_peer_update_callback(enum pcmk__node_update type, pcmk__node_status_t *node, +fenced_peer_change_cb(enum pcmk__node_update type, pcmk__node_status_t *node, const void *data) { if ((type != pcmk__node_update_processes) @@ -71,7 +71,7 @@ st_peer_update_callback(enum pcmk__node_update type, pcmk__node_status_t *node, #if SUPPORT_COROSYNC static void -handle_cpg_message(cpg_handle_t handle, const struct cpg_name *groupName, +fenced_cpg_dispatch(cpg_handle_t handle, const struct cpg_name *groupName, uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len) { xmlNode *xml = NULL; @@ -96,7 +96,7 @@ handle_cpg_message(cpg_handle_t handle, const struct cpg_name *groupName, } static void -stonith_peer_cs_destroy(gpointer user_data) +fenced_cpg_destroy(gpointer user_data) { crm_crit("Lost connection to cluster layer, shutting down"); stonith_shutdown(0); @@ -112,13 +112,13 @@ fenced_cluster_connect(void) #if SUPPORT_COROSYNC if (pcmk_get_cluster_layer() == pcmk_cluster_layer_corosync) { - pcmk_cluster_set_destroy_fn(fenced_cluster, stonith_peer_cs_destroy); - pcmk_cpg_set_deliver_fn(fenced_cluster, handle_cpg_message); + pcmk_cluster_set_destroy_fn(fenced_cluster, fenced_cpg_destroy); + pcmk_cpg_set_deliver_fn(fenced_cluster, fenced_cpg_dispatch); pcmk_cpg_set_confchg_fn(fenced_cluster, pcmk__cpg_confchg_cb); } #endif // SUPPORT_COROSYNC - pcmk__cluster_set_status_callback(&st_peer_update_callback); + pcmk__cluster_set_status_callback(&fenced_peer_change_cb); rc = pcmk_cluster_connect(fenced_cluster); if (rc != pcmk_rc_ok) { From 8ef4cf74efae27cc5a52abd58883b84cbc99398f Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Tue, 9 Dec 2025 11:30:08 -0500 Subject: [PATCH 08/25] Refactor: daemons: Standardize callback code in fenced_corosync.c. * Add doxygen comments to each. * Improve whitespace. * Rename groupName parameter to group_name. * Rearrange code in fenced_cpg_dispatch to be more in line with what's happening in attrd. --- daemons/fenced/fenced_corosync.c | 39 +++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/daemons/fenced/fenced_corosync.c b/daemons/fenced/fenced_corosync.c index 9900e07fdcd..1d937cee81f 100644 --- a/daemons/fenced/fenced_corosync.c +++ b/daemons/fenced/fenced_corosync.c @@ -25,7 +25,7 @@ pcmk_cluster_t *fenced_cluster = NULL; static void -stonith_peer_callback(xmlNode * msg, void *private_data) +stonith_peer_callback(xmlNode *msg, void *private_data) { const char *remote_peer = pcmk__xe_get(msg, PCMK__XA_SRC); const char *op = pcmk__xe_get(msg, PCMK__XA_ST_OP); @@ -48,7 +48,7 @@ stonith_peer_callback(xmlNode * msg, void *private_data) */ static void fenced_peer_change_cb(enum pcmk__node_update type, pcmk__node_status_t *node, - const void *data) + const void *data) { if ((type != pcmk__node_update_processes) && !pcmk__is_set(node->flags, pcmk__node_status_remote)) { @@ -70,33 +70,50 @@ fenced_peer_change_cb(enum pcmk__node_update type, pcmk__node_status_t *node, } #if SUPPORT_COROSYNC +/*! + * \internal + * \brief Callback for when a peer message is received + * + * \param[in] handle The cluster connection + * \param[in] group_name The group that \p nodeid is a member of + * \param[in] nodeid Peer node that sent \p msg + * \param[in] pid Process that sent \p msg + * \param[in,out] msg Received message + * \param[in] msg_len Length of \p msg + */ static void -fenced_cpg_dispatch(cpg_handle_t handle, const struct cpg_name *groupName, - uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len) +fenced_cpg_dispatch(cpg_handle_t handle, const struct cpg_name *group_name, + uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len) { xmlNode *xml = NULL; const char *from = NULL; char *data = pcmk__cpg_message_data(handle, nodeid, pid, msg, &from); - if(data == NULL) { + if (data == NULL) { return; } xml = pcmk__xml_parse(data); if (xml == NULL) { - crm_err("Invalid XML: '%.120s'", data); - free(data); - return; + crm_err("Bad message received from %s[%" PRIu32 "]: '%.120s'", + from, nodeid, data); + } else { + pcmk__xe_set(xml, PCMK__XA_SRC, from); + stonith_peer_callback(xml, NULL); } - pcmk__xe_set(xml, PCMK__XA_SRC, from); - stonith_peer_callback(xml, NULL); pcmk__xml_free(xml); free(data); } +/*! + * \internal + * \brief Callback for when the cluster object is destroyed + * + * \param[in] unused Unused + */ static void -fenced_cpg_destroy(gpointer user_data) +fenced_cpg_destroy(gpointer unused) { crm_crit("Lost connection to cluster layer, shutting down"); stonith_shutdown(0); From edd116b3e9ba5fd05ec9b3a39153ee0468f572fc Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Tue, 9 Dec 2025 11:32:40 -0500 Subject: [PATCH 09/25] Refactor: daemons: Standardize callback code in attrd_corosync.c. * Add doxygen comments to each. * Improve whitespace. * Rename groupName parameter to group_name. --- daemons/attrd/attrd_corosync.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/daemons/attrd/attrd_corosync.c b/daemons/attrd/attrd_corosync.c index 7e6b612ef64..d741824e4b4 100644 --- a/daemons/attrd/attrd_corosync.c +++ b/daemons/attrd/attrd_corosync.c @@ -133,21 +133,30 @@ attrd_peer_message(pcmk__node_status_t *peer, xmlNode *xml) } } +/*! + * \internal + * \brief Callback for when a peer message is received + * + * \param[in] handle The cluster connection + * \param[in] group_name The group that \p nodeid is a member of + * \param[in] nodeid Peer node that sent \p msg + * \param[in] pid Process that sent \p msg + * \param[in,out] msg Received message + * \param[in] msg_len Length of \p msg + */ static void -attrd_cpg_dispatch(cpg_handle_t handle, - const struct cpg_name *groupName, - uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len) +attrd_cpg_dispatch(cpg_handle_t handle, const struct cpg_name *group_name, + uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len) { xmlNode *xml = NULL; const char *from = NULL; char *data = pcmk__cpg_message_data(handle, nodeid, pid, msg, &from); - if(data == NULL) { + if (data == NULL) { return; } xml = pcmk__xml_parse(data); - if (xml == NULL) { crm_err("Bad message received from %s[%" PRIu32 "]: '%.120s'", from, nodeid, data); @@ -161,6 +170,12 @@ attrd_cpg_dispatch(cpg_handle_t handle, free(data); } +/*! + * \internal + * \brief Callback for when the cluster object is destroyed + * + * \param[in] unused Unused + */ static void attrd_cpg_destroy(gpointer unused) { @@ -194,6 +209,14 @@ attrd_broadcast_value(const attribute_t *a, const attribute_value_t *v) #define state_text(state) pcmk__s((state), "in unknown state") +/*! + * \internal + * \brief Callback for peer status changes + * + * \param[in] type What changed + * \param[in] node What peer had the change + * \param[in] data Previous value of what changed + */ static void attrd_peer_change_cb(enum pcmk__node_update kind, pcmk__node_status_t *peer, const void *data) From 97b4b6e4b93bfb0e0617972c1f642437154d4cdd Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Tue, 9 Dec 2025 11:41:13 -0500 Subject: [PATCH 10/25] Refactor: daemons: Rename stonith_peer_callback to fenced_peer_message. This brings it closer to what is happening in attrd. For the moment it's still basically just a wrapper around stonith_command, but that will change in future patches. --- daemons/fenced/fenced_corosync.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/daemons/fenced/fenced_corosync.c b/daemons/fenced/fenced_corosync.c index 1d937cee81f..8a204e21a92 100644 --- a/daemons/fenced/fenced_corosync.c +++ b/daemons/fenced/fenced_corosync.c @@ -25,17 +25,15 @@ pcmk_cluster_t *fenced_cluster = NULL; static void -stonith_peer_callback(xmlNode *msg, void *private_data) +fenced_peer_message(pcmk__node_status_t *peer, xmlNode *xml) { - const char *remote_peer = pcmk__xe_get(msg, PCMK__XA_SRC); - const char *op = pcmk__xe_get(msg, PCMK__XA_ST_OP); + const char *op = pcmk__xe_get(xml, PCMK__XA_ST_OP); if (pcmk__str_eq(op, STONITH_OP_POKE, pcmk__str_none)) { return; } - crm_log_xml_trace(msg, "Peer[inbound]"); - stonith_command(NULL, 0, 0, msg, remote_peer); + stonith_command(NULL, 0, 0, xml, peer->name); } /*! @@ -99,7 +97,9 @@ fenced_cpg_dispatch(cpg_handle_t handle, const struct cpg_name *group_name, from, nodeid, data); } else { pcmk__xe_set(xml, PCMK__XA_SRC, from); - stonith_peer_callback(xml, NULL); + fenced_peer_message(pcmk__get_node(nodeid, from, NULL, + pcmk__node_search_cluster_member), + xml); } pcmk__xml_free(xml); From 2ce96bbdd2cfb7b2fc2571b1016114c3b4385cac Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Tue, 9 Dec 2025 14:50:21 -0500 Subject: [PATCH 11/25] Refactor: daemons: Rename handle_request to fenced_handle_request. And make it look a lot more like the version in attrd. It looks likely that there's always going to be daemon-specific code to these handle_request functions, but so far it looks like it will be pretty minimal. --- daemons/fenced/fenced_commands.c | 37 +++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c index 8d81ce896c3..477c9158fd9 100644 --- a/daemons/fenced/fenced_commands.c +++ b/daemons/fenced/fenced_commands.c @@ -3584,16 +3584,22 @@ fenced_unregister_handlers(void) } static void -handle_request(pcmk__request_t *request) +fenced_handle_request(pcmk__request_t *request) { xmlNode *reply = NULL; + char *log_msg = NULL; + const char *exec_status_s = NULL; const char *reason = NULL; if (fenced_handlers == NULL) { fenced_register_handlers(); } + reply = pcmk__process_request(request, fenced_handlers); + if (reply != NULL) { + crm_log_xml_trace(reply, "Reply"); + if (pcmk__is_set(request->flags, pcmk__request_reuse_options) && (request->ipc_client != NULL)) { /* Certain IPC-only commands must reuse the call options from the @@ -3603,6 +3609,7 @@ handle_request(pcmk__request_t *request) pcmk__ipc_send_xml(request->ipc_client, request->ipc_id, reply, request->ipc_flags); request->ipc_client->request_id = 0; + } else { stonith_send_reply(reply, request->call_options, request->peer, request->ipc_client); @@ -3610,14 +3617,25 @@ handle_request(pcmk__request_t *request) pcmk__xml_free(reply); } + exec_status_s = pcmk_exec_status_str(request->result.execution_status); reason = request->result.exit_reason; - crm_debug("Processed %s request from %s %s: %s%s%s%s", - request->op, pcmk__request_origin_type(request), - pcmk__request_origin(request), - pcmk_exec_status_str(request->result.execution_status), - (reason == NULL)? "" : " (", - (reason == NULL)? "" : reason, - (reason == NULL)? "" : ")"); + log_msg = pcmk__assert_asprintf("Processed %s request from %s %s: %s%s%s%s", + request->op, + pcmk__request_origin_type(request), + pcmk__request_origin(request), + exec_status_s, + (reason == NULL)? "" : " (", + pcmk__s(reason, ""), + (reason == NULL)? "" : ")"); + + if (!pcmk__result_ok(&request->result)) { + crm_warn("%s", log_msg); + } else { + crm_debug("%s", log_msg); + } + + free(log_msg); + pcmk__reset_request(request); } static void @@ -3709,7 +3727,6 @@ stonith_command(pcmk__client_t *client, uint32_t id, uint32_t flags, pcmk__set_request_flags(&request, pcmk__request_sync); } - handle_request(&request); - pcmk__reset_request(&request); + fenced_handle_request(&request); } } From 394d8d933154b5528e4a82bc0a59f4ad2297f911 Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Tue, 9 Dec 2025 15:35:15 -0500 Subject: [PATCH 12/25] Refactor: daemons: Don't copy op in handle_reply. The comment indicates the reply might be freed before we log the op, but I don't see anywhere that happens. --- daemons/fenced/fenced_commands.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c index 477c9158fd9..141ba9481f6 100644 --- a/daemons/fenced/fenced_commands.c +++ b/daemons/fenced/fenced_commands.c @@ -3641,8 +3641,7 @@ fenced_handle_request(pcmk__request_t *request) static void handle_reply(pcmk__client_t *client, xmlNode *request, const char *remote_peer) { - // Copy, because request might be freed before we want to log this - char *op = pcmk__xe_get_copy(request, PCMK__XA_ST_OP); + const char *op = pcmk__xe_get(request, PCMK__XA_ST_OP); if (pcmk__str_eq(op, STONITH_OP_QUERY, pcmk__str_none)) { process_remote_stonith_query(request); @@ -3656,13 +3655,12 @@ handle_reply(pcmk__client_t *client, xmlNode *request, const char *remote_peer) pcmk__s(op, "untyped"), ((client == NULL)? "peer" : "client"), ((client == NULL)? remote_peer : pcmk__client_name(client))); crm_log_xml_warn(request, "UnknownOp"); - free(op); return; } + crm_debug("Processed %s reply from %s %s", op, ((client == NULL)? "peer" : "client"), ((client == NULL)? remote_peer : pcmk__client_name(client))); - free(op); } /*! From 0b3f7fc4eb1f54740068b4333c9e27bf6e38bc0c Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Tue, 9 Dec 2025 15:46:36 -0500 Subject: [PATCH 13/25] Refactor: daemons: Simplify attrd message handlers a bit. If the handler only deals with one type of message (IPC or CPG), it should first check for the error case and handle that. If it deals with both types of messages, it should first check for whichever one requires less code to process. This allows as much of the body of the function as possible to be indented as little as possible. --- daemons/attrd/attrd_messages.c | 83 ++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 40 deletions(-) diff --git a/daemons/attrd/attrd_messages.c b/daemons/attrd/attrd_messages.c index dd1516a941c..50e7f5c420a 100644 --- a/daemons/attrd/attrd_messages.c +++ b/daemons/attrd/attrd_messages.c @@ -104,24 +104,24 @@ handle_clear_failure_request(pcmk__request_t *request) static xmlNode * handle_confirm_request(pcmk__request_t *request) { - if (request->peer != NULL) { - int callid; + int callid = 0; - crm_debug("Received confirmation from %s", request->peer); + if (request->ipc_client != NULL) { + return handle_unknown_request(request); + } - if (pcmk__xe_get_int(request->xml, PCMK__XA_CALL_ID, - &callid) != pcmk_rc_ok) { - pcmk__set_result(&request->result, CRM_EX_PROTOCOL, PCMK_EXEC_INVALID, - "Could not get callid from XML"); - } else { - attrd_handle_confirmation(callid, request->peer); - } + crm_debug("Received confirmation from %s", request->peer); - pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL); - return NULL; + if (pcmk__xe_get_int(request->xml, PCMK__XA_CALL_ID, + &callid) != pcmk_rc_ok) { + pcmk__set_result(&request->result, CRM_EX_PROTOCOL, PCMK_EXEC_INVALID, + "Could not get callid from XML"); } else { - return handle_unknown_request(request); + attrd_handle_confirmation(callid, request->peer); } + + pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL); + return NULL; } static xmlNode * @@ -129,29 +129,31 @@ handle_query_request(pcmk__request_t *request) { if (request->peer != NULL) { return handle_unknown_request(request); - } else { - return attrd_client_query(request); } + + return attrd_client_query(request); } static xmlNode * handle_remove_request(pcmk__request_t *request) { - if (request->peer != NULL) { - const char *host = pcmk__xe_get(request->xml, PCMK__XA_ATTR_HOST); - bool reap = false; - - if (pcmk__xe_get_bool(request->xml, PCMK__XA_REAP, - &reap) != pcmk_rc_ok) { - reap = true; // Default to true for backward compatibility - } - attrd_peer_remove(host, reap, request->peer); - pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL); + const char *host = NULL; + bool reap = false; - } else { + if (request->ipc_client != NULL) { attrd_client_peer_remove(request); + return NULL; } + host = pcmk__xe_get(request->xml, PCMK__XA_ATTR_HOST); + + if (pcmk__xe_get_bool(request->xml, PCMK__XA_REAP, + &reap) != pcmk_rc_ok) { + reap = true; // Default to true for backward compatibility + } + + attrd_peer_remove(host, reap, request->peer); + pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL); return NULL; } @@ -161,6 +163,7 @@ handle_refresh_request(pcmk__request_t *request) if (request->peer != NULL) { return handle_unknown_request(request); } + attrd_client_refresh(request); return NULL; } @@ -168,24 +171,24 @@ handle_refresh_request(pcmk__request_t *request) static xmlNode * handle_sync_response_request(pcmk__request_t *request) { + pcmk__node_status_t *peer = NULL; + bool peer_won = false; + if (request->ipc_client != NULL) { return handle_unknown_request(request); - } else { - if (request->peer != NULL) { - pcmk__node_status_t *peer = - pcmk__get_node(0, request->peer, NULL, - pcmk__node_search_cluster_member); - bool peer_won = attrd_check_for_new_writer(peer, request->xml); - - if (!pcmk__str_eq(peer->name, attrd_cluster->priv->node_name, - pcmk__str_casei)) { - attrd_peer_sync_response(peer, peer_won, request->xml); - } - } + } - pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL); - return NULL; + peer = pcmk__get_node(0, request->peer, NULL, + pcmk__node_search_cluster_member); + peer_won = attrd_check_for_new_writer(peer, request->xml); + + if (!pcmk__str_eq(peer->name, attrd_cluster->priv->node_name, + pcmk__str_casei)) { + attrd_peer_sync_response(peer, peer_won, request->xml); } + + pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL); + return NULL; } static xmlNode * From 76f18b8f87bae8cbba63ef7924d5ef5985de12b5 Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Tue, 9 Dec 2025 15:53:48 -0500 Subject: [PATCH 14/25] Refactor: daemons: Don't call pcmk__assert in fenced handlers. A couple of these handlers are only meant for IPC clients - if we get a CPG client, that's an unknown request. One and only one of ipc_client or peer must be non-NULL at a time, and in general we don't assert in other daemons like this. --- daemons/fenced/fenced_commands.c | 35 +++++++++++++++++++------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c index 141ba9481f6..88d0655a3d6 100644 --- a/daemons/fenced/fenced_commands.c +++ b/daemons/fenced/fenced_commands.c @@ -3179,13 +3179,29 @@ is_privileged(const pcmk__client_t *c, const char *op) } } +static xmlNode * +handle_unknown_request(pcmk__request_t *request) +{ + crm_err("Unknown %s request %s from %s %s", + (request->ipc_client != NULL) ? "IPC" : "CPG", + request->op, pcmk__request_origin_type(request), + pcmk__request_origin(request)); + pcmk__format_result(&request->result, CRM_EX_PROTOCOL, PCMK_EXEC_INVALID, + "Unknown request type '%s' (bug?)", + pcmk__s(request->op, "")); + return fenced_construct_reply(request->xml, NULL, &request->result); +} + // CRM_OP_REGISTER static xmlNode * handle_register_request(pcmk__request_t *request) { xmlNode *reply = pcmk__xe_create(NULL, "reply"); - pcmk__assert(request->ipc_client != NULL); + if (request->peer != NULL) { + return handle_unknown_request(request); + } + pcmk__xe_set(reply, PCMK__XA_ST_OP, CRM_OP_REGISTER); pcmk__xe_set(reply, PCMK__XA_ST_CLIENTID, request->ipc_client->id); pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL); @@ -3277,7 +3293,10 @@ handle_notify_request(pcmk__request_t *request) { const char *flag_name = NULL; - pcmk__assert(request->ipc_client != NULL); + if (request->peer != NULL) { + return handle_unknown_request(request); + } + flag_name = pcmk__xe_get(request->xml, PCMK__XA_ST_NOTIFY_ACTIVATE); if (flag_name != NULL) { crm_debug("Enabling %s callbacks for client %s", @@ -3539,18 +3558,6 @@ handle_cache_request(pcmk__request_t *request) return NULL; } -static xmlNode * -handle_unknown_request(pcmk__request_t *request) -{ - crm_err("Unknown IPC request %s from %s %s", - request->op, pcmk__request_origin_type(request), - pcmk__request_origin(request)); - pcmk__format_result(&request->result, CRM_EX_PROTOCOL, PCMK_EXEC_INVALID, - "Unknown IPC request type '%s' (bug?)", - pcmk__s(request->op, "")); - return fenced_construct_reply(request->xml, NULL, &request->result); -} - static void fenced_register_handlers(void) { From eabea3f17cdefb984f165e7ec3f931a3f8de2e0a Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Tue, 9 Dec 2025 16:53:17 -0500 Subject: [PATCH 15/25] Refactor: daemons: Minor improvements to fenced_ipc_dispatch. * Add some additional checks in line with what is happening in other daemon dispatch functions. * Move a couple comments above the code they document for line length reasons. * Remove the redundant trace logging call. This is already done by call_api_dispatch. --- daemons/fenced/fenced_ipc.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/daemons/fenced/fenced_ipc.c b/daemons/fenced/fenced_ipc.c index 789ceca8372..b6dfef0dd7d 100644 --- a/daemons/fenced/fenced_ipc.c +++ b/daemons/fenced/fenced_ipc.c @@ -76,7 +76,12 @@ fenced_ipc_dispatch(qb_ipcs_connection_t *c, void *data, size_t size) const char *op = NULL; int rc = pcmk_rc_ok; + // Sanity-check, and parse XML from IPC data CRM_CHECK(client != NULL, return 0); + if (data == NULL) { + crm_debug("No IPC data from PID %d", pcmk__client_pid(c)); + return 0; + } rc = pcmk__ipc_msg_append(&client->buffer, data); @@ -107,12 +112,13 @@ fenced_ipc_dispatch(qb_ipcs_connection_t *c, void *data, size_t size) } if (msg == NULL) { + crm_debug("Unrecognizable IPC data from PID %d", pcmk__client_pid(c)); pcmk__ipc_send_ack(client, id, flags, PCMK__XE_NACK, NULL, CRM_EX_PROTOCOL); return 0; } op = pcmk__xe_get(msg, PCMK__XA_CRM_TASK); - if(pcmk__str_eq(op, CRM_OP_RM_NODE_CACHE, pcmk__str_casei)) { + if (pcmk__str_eq(op, CRM_OP_RM_NODE_CACHE, pcmk__str_casei)) { pcmk__xe_set(msg, PCMK__XA_T, PCMK__VALUE_STONITH_NG); pcmk__xe_set(msg, PCMK__XA_ST_OP, op); pcmk__xe_set(msg, PCMK__XA_ST_CLIENTID, client->id); @@ -142,15 +148,16 @@ fenced_ipc_dispatch(qb_ipcs_connection_t *c, void *data, size_t size) if (pcmk__is_set(call_options, st_opt_sync_call)) { pcmk__assert(pcmk__is_set(flags, crm_ipc_client_response)); - CRM_LOG_ASSERT(client->request_id == 0); /* This means the client has two synchronous events in-flight */ - client->request_id = id; /* Reply only to the last one */ + /* This means the client has two synchronous events in-flight */ + CRM_LOG_ASSERT(client->request_id == 0); + /* Reply only to the last one */ + client->request_id = id; } pcmk__xe_set(msg, PCMK__XA_ST_CLIENTID, client->id); pcmk__xe_set(msg, PCMK__XA_ST_CLIENTNAME, pcmk__client_name(client)); pcmk__xe_set(msg, PCMK__XA_ST_CLIENTNODE, fenced_get_local_node()); - crm_log_xml_trace(msg, "ipc-received"); stonith_command(client, id, flags, msg, NULL); pcmk__xml_free(msg); From 89ee94d898c4461d32f44e462d2f840cb63f50f3 Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Tue, 9 Dec 2025 17:02:30 -0500 Subject: [PATCH 16/25] Refactor: daemons: Don't call stonith_command in fenced_ipc_dispatch. To make this look as similar as possible to the dispatch functions in other daemons, I want to get rid of the stonith_command function. This will result in a little bit of code duplication for now, but I'm planning on eventually reducing that duplication across all daemons. --- daemons/fenced/fenced_commands.c | 2 +- daemons/fenced/fenced_ipc.c | 49 ++++++++++++++++++++++++++++++- daemons/fenced/pacemaker-fenced.h | 2 ++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c index 88d0655a3d6..97cb65fa4ef 100644 --- a/daemons/fenced/fenced_commands.c +++ b/daemons/fenced/fenced_commands.c @@ -3590,7 +3590,7 @@ fenced_unregister_handlers(void) } } -static void +void fenced_handle_request(pcmk__request_t *request) { xmlNode *reply = NULL; diff --git a/daemons/fenced/fenced_ipc.c b/daemons/fenced/fenced_ipc.c index b6dfef0dd7d..df8b1974fe0 100644 --- a/daemons/fenced/fenced_ipc.c +++ b/daemons/fenced/fenced_ipc.c @@ -22,11 +22,35 @@ #include // crm_ipc_flags, pcmk_ipc_fenced #include // pcmk_rc_*, pcmk_rc_str +#include // STONITH_OP_* #include // CRM_OP_RM_NODE_CACHE #include // stonith_call_options static qb_ipcs_service_t *ipcs = NULL; +static void +handle_ipc_reply(pcmk__client_t *client, xmlNode *request) +{ + const char *op = pcmk__xe_get(request, PCMK__XA_ST_OP); + + if (pcmk__str_eq(op, STONITH_OP_QUERY, pcmk__str_none)) { + process_remote_stonith_query(request); + + } else if (pcmk__str_any_of(op, STONITH_OP_NOTIFY, STONITH_OP_FENCE, + NULL)) { + fenced_process_fencing_reply(request); + + } else { + crm_err("Ignoring unknown %s reply from client %s", + pcmk__s(op, "untyped"), pcmk__client_name(client)); + crm_log_xml_warn(request, "UnknownOp"); + return; + } + + crm_debug("Processed %s reply from client %s", op, + pcmk__client_name(client)); +} + /*! * \internal * \brief Accept a new client IPC connection @@ -158,7 +182,30 @@ fenced_ipc_dispatch(qb_ipcs_connection_t *c, void *data, size_t size) pcmk__xe_set(msg, PCMK__XA_ST_CLIENTNAME, pcmk__client_name(client)); pcmk__xe_set(msg, PCMK__XA_ST_CLIENTNODE, fenced_get_local_node()); - stonith_command(client, id, flags, msg, NULL); + if (pcmk__xpath_find_one(msg->doc, "//" PCMK__XE_ST_REPLY, + LOG_NEVER) != NULL) { + handle_ipc_reply(client, msg); + + } else { + pcmk__request_t request = { + .ipc_client = client, + .ipc_id = id, + .ipc_flags = flags, + .peer = NULL, + .xml = msg, + .call_options = call_options, + .result = PCMK__UNKNOWN_RESULT, + }; + + request.op = pcmk__xe_get_copy(request.xml, PCMK__XA_ST_OP); + CRM_CHECK(request.op != NULL, return 0); + + if (pcmk__is_set(request.call_options, st_opt_sync_call)) { + pcmk__set_request_flags(&request, pcmk__request_sync); + } + + fenced_handle_request(&request); + } pcmk__xml_free(msg); return 0; diff --git a/daemons/fenced/pacemaker-fenced.h b/daemons/fenced/pacemaker-fenced.h index f758bb8e3dc..ef6d9ef290c 100644 --- a/daemons/fenced/pacemaker-fenced.h +++ b/daemons/fenced/pacemaker-fenced.h @@ -382,6 +382,8 @@ void fenced_ipc_cleanup(void); int fenced_cluster_connect(void); +void fenced_handle_request(pcmk__request_t *request); + /*! * \internal * \brief Get the device flag to use with a given action when searching devices From 379738789d661c886f5f351dff1875ba2ea747a2 Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Wed, 10 Dec 2025 12:56:52 -0500 Subject: [PATCH 17/25] Refactor: daemons: Don't call stonith_command in fenced_peer_message. Instead, inline the portions of stonith_command that would be used and then get rid of that function entirely. --- daemons/fenced/fenced_commands.c | 91 ------------------------------- daemons/fenced/fenced_corosync.c | 55 ++++++++++++++++++- daemons/fenced/pacemaker-fenced.h | 3 - 3 files changed, 54 insertions(+), 95 deletions(-) diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c index 97cb65fa4ef..5e43ff614a0 100644 --- a/daemons/fenced/fenced_commands.c +++ b/daemons/fenced/fenced_commands.c @@ -3644,94 +3644,3 @@ fenced_handle_request(pcmk__request_t *request) free(log_msg); pcmk__reset_request(request); } - -static void -handle_reply(pcmk__client_t *client, xmlNode *request, const char *remote_peer) -{ - const char *op = pcmk__xe_get(request, PCMK__XA_ST_OP); - - if (pcmk__str_eq(op, STONITH_OP_QUERY, pcmk__str_none)) { - process_remote_stonith_query(request); - - } else if (pcmk__str_any_of(op, STONITH_OP_NOTIFY, STONITH_OP_FENCE, - NULL)) { - fenced_process_fencing_reply(request); - - } else { - crm_err("Ignoring unknown %s reply from %s %s", - pcmk__s(op, "untyped"), ((client == NULL)? "peer" : "client"), - ((client == NULL)? remote_peer : pcmk__client_name(client))); - crm_log_xml_warn(request, "UnknownOp"); - return; - } - - crm_debug("Processed %s reply from %s %s", - op, ((client == NULL)? "peer" : "client"), - ((client == NULL)? remote_peer : pcmk__client_name(client))); -} - -/*! - * \internal - * \brief Handle a message from an IPC client or CPG peer - * - * \param[in,out] client If not NULL, IPC client that sent message - * \param[in] id If from IPC client, IPC message ID - * \param[in] flags Message flags - * \param[in,out] message Message XML - * \param[in] remote_peer If not NULL, CPG peer that sent message - */ -void -stonith_command(pcmk__client_t *client, uint32_t id, uint32_t flags, - xmlNode *message, const char *remote_peer) -{ - uint32_t call_options = st_opt_none; - int rc = pcmk_rc_ok; - bool is_reply = false; - - CRM_CHECK(message != NULL, return); - - if (pcmk__xpath_find_one(message->doc, "//" PCMK__XE_ST_REPLY, - LOG_NEVER) != NULL) { - is_reply = true; - } - - rc = pcmk__xe_get_flags(message, PCMK__XA_ST_CALLOPT, &call_options, - st_opt_none); - if (rc != pcmk_rc_ok) { - crm_warn("Couldn't parse options from message: %s", pcmk_rc_str(rc)); - } - - crm_debug("Processing %ssynchronous %s %s %u from %s %s", - pcmk__is_set(call_options, st_opt_sync_call)? "" : "a", - pcmk__xe_get(message, PCMK__XA_ST_OP), - (is_reply? "reply" : "request"), id, - ((client == NULL)? "peer" : "client"), - ((client == NULL)? remote_peer : pcmk__client_name(client))); - - if (pcmk__is_set(call_options, st_opt_sync_call)) { - pcmk__assert((client == NULL) || (client->request_id == id)); - } - - if (is_reply) { - handle_reply(client, message, remote_peer); - } else { - pcmk__request_t request = { - .ipc_client = client, - .ipc_id = id, - .ipc_flags = flags, - .peer = remote_peer, - .xml = message, - .call_options = call_options, - .result = PCMK__UNKNOWN_RESULT, - }; - - request.op = pcmk__xe_get_copy(request.xml, PCMK__XA_ST_OP); - CRM_CHECK(request.op != NULL, return); - - if (pcmk__is_set(request.call_options, st_opt_sync_call)) { - pcmk__set_request_flags(&request, pcmk__request_sync); - } - - fenced_handle_request(&request); - } -} diff --git a/daemons/fenced/fenced_corosync.c b/daemons/fenced/fenced_corosync.c index 8a204e21a92..cba169eaf8a 100644 --- a/daemons/fenced/fenced_corosync.c +++ b/daemons/fenced/fenced_corosync.c @@ -19,21 +19,74 @@ #include // pcmk_cluster_connect #include // pcmk_ipc_server #include // pcmk_rc_* +#include // st_opt_* #include "pacemaker-fenced.h" pcmk_cluster_t *fenced_cluster = NULL; +static void +handle_cpg_reply(const char *remote_peer, xmlNode *request) +{ + const char *op = pcmk__xe_get(request, PCMK__XA_ST_OP); + + if (pcmk__str_eq(op, STONITH_OP_QUERY, pcmk__str_none)) { + process_remote_stonith_query(request); + + } else if (pcmk__str_any_of(op, STONITH_OP_NOTIFY, STONITH_OP_FENCE, + NULL)) { + fenced_process_fencing_reply(request); + + } else { + crm_err("Ignoring unknown %s reply from peer %s", pcmk__s(op, "untyped"), + remote_peer); + crm_log_xml_warn(request, "UnknownOp"); + return; + } + + crm_debug("Processed %s reply from peer %s", op, remote_peer); +} + static void fenced_peer_message(pcmk__node_status_t *peer, xmlNode *xml) { const char *op = pcmk__xe_get(xml, PCMK__XA_ST_OP); + int rc = pcmk_rc_ok; if (pcmk__str_eq(op, STONITH_OP_POKE, pcmk__str_none)) { return; } - stonith_command(NULL, 0, 0, xml, peer->name); + if (pcmk__xpath_find_one(xml->doc, "//" PCMK__XE_ST_REPLY, + LOG_NEVER) != NULL) { + handle_cpg_reply(peer->name, xml); + + } else { + pcmk__request_t request = { + .ipc_client = NULL, + .ipc_id = 0, + .ipc_flags = 0, + .peer = peer->name, + .xml = xml, + .call_options = st_opt_none, + .result = PCMK__UNKNOWN_RESULT, + }; + + rc = pcmk__xe_get_flags(xml, PCMK__XA_ST_CALLOPT, + (uint32_t *) &request.call_options, st_opt_none); + if (rc != pcmk_rc_ok) { + crm_warn("Couldn't parse options from request: %s", pcmk_rc_str(rc)); + } + + request.op = pcmk__xe_get_copy(request.xml, PCMK__XA_ST_OP); + CRM_CHECK(request.op != NULL, return); + + if (pcmk__is_set(request.call_options, st_opt_sync_call)) { + pcmk__set_request_flags(&request, pcmk__request_sync); + } + + fenced_handle_request(&request); + } } /*! diff --git a/daemons/fenced/pacemaker-fenced.h b/daemons/fenced/pacemaker-fenced.h index ef6d9ef290c..8571b82c4a2 100644 --- a/daemons/fenced/pacemaker-fenced.h +++ b/daemons/fenced/pacemaker-fenced.h @@ -309,9 +309,6 @@ void init_stonith_remote_op_hash_table(GHashTable **table); void free_metadata_cache(void); void fenced_unregister_handlers(void); -void stonith_command(pcmk__client_t *client, uint32_t id, uint32_t flags, - xmlNode *op_request, const char *remote_peer); - int fenced_device_register(const xmlNode *dev, bool from_cib); void stonith_device_remove(const char *id, bool from_cib); From f6b6fe30879cf32fc6de2b251c70de61b5edc0d8 Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Wed, 10 Dec 2025 13:55:05 -0500 Subject: [PATCH 18/25] Low: daemons: Call pcmk_cluster_disconnect at the end of fenced. --- daemons/fenced/pacemaker-fenced.c | 1 + 1 file changed, 1 insertion(+) diff --git a/daemons/fenced/pacemaker-fenced.c b/daemons/fenced/pacemaker-fenced.c index e70a73faa0e..5780d96fa14 100644 --- a/daemons/fenced/pacemaker-fenced.c +++ b/daemons/fenced/pacemaker-fenced.c @@ -444,6 +444,7 @@ main(int argc, char **argv) g_strfreev(options.log_files); stonith_cleanup(); + pcmk_cluster_disconnect(fenced_cluster); pcmk_cluster_free(fenced_cluster); fenced_scheduler_cleanup(); From 01fcd834ea95763faf299025c9f413b64f4992e9 Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Wed, 10 Dec 2025 14:12:51 -0500 Subject: [PATCH 19/25] Refactor: daemons: Split out checking for a previous instance. This does lose some of the existing error handling - if there's an OOM condition, this code will no longer abort and it will instead be up to whatever next allocates memory to fail. However, this is almost exactly what's happening in attrd and OOM should be extremely rare. It's expected that eventually all daemons will use identical code for this purpose, at which point we can handle these rare error cases better. --- daemons/fenced/pacemaker-fenced.c | 52 +++++++++++++++++++------------ 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/daemons/fenced/pacemaker-fenced.c b/daemons/fenced/pacemaker-fenced.c index 5780d96fa14..c6fdbd2baf4 100644 --- a/daemons/fenced/pacemaker-fenced.c +++ b/daemons/fenced/pacemaker-fenced.c @@ -324,11 +324,37 @@ build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) return context; } +static bool +ipc_already_running(void) +{ + crm_ipc_t *old_instance = NULL; + int rc = pcmk_rc_ok; + + old_instance = crm_ipc_new("stonith-ng", 0); + if (old_instance == NULL) { + /* This is an error - memory allocation failed, etc. - but crm_ipc_new + * will have already logged an error message. + */ + return false; + } + + rc = pcmk__connect_generic_ipc(old_instance); + if (rc != pcmk_rc_ok) { + crm_debug("No existing stonith-ng instance found: %s", + pcmk_rc_str(rc)); + crm_ipc_destroy(old_instance); + return false; + } + + crm_ipc_close(old_instance); + crm_ipc_destroy(old_instance); + return true; +} + int main(int argc, char **argv) { int rc = pcmk_rc_ok; - crm_ipc_t *old_instance = NULL; GError *error = NULL; @@ -379,26 +405,12 @@ main(int argc, char **argv) crm_notice("Starting Pacemaker fencer"); - old_instance = crm_ipc_new("stonith-ng", 0); - if (old_instance == NULL) { - /* crm_ipc_new() will have already logged an error message with - * crm_err() - */ - exit_code = CRM_EX_FATAL; - goto done; - } - - if (pcmk__connect_generic_ipc(old_instance) == pcmk_rc_ok) { - // IPC endpoint already up - crm_ipc_close(old_instance); - crm_ipc_destroy(old_instance); - crm_crit("Aborting start-up because another fencer instance is " - "already active"); + if (ipc_already_running()) { + exit_code = CRM_EX_OK; + g_set_error(&error, PCMK__EXITC_ERROR, exit_code, + "Aborting start-up because a fencer instance is already active"); + crm_crit("%s", error->message); goto done; - } else { - // Not up or not authentic, we'll proceed either way - crm_ipc_destroy(old_instance); - old_instance = NULL; } mainloop_add_signal(SIGTERM, stonith_shutdown); From dfb10fc22976565bcc66d02202308b222ec34e21 Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Wed, 10 Dec 2025 14:17:38 -0500 Subject: [PATCH 20/25] Refactor: daemons: Add fenced_cluster_disconnect. --- daemons/fenced/fenced_corosync.c | 7 +++++++ daemons/fenced/pacemaker-fenced.c | 3 +-- daemons/fenced/pacemaker-fenced.h | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/daemons/fenced/fenced_corosync.c b/daemons/fenced/fenced_corosync.c index cba169eaf8a..3888da7671b 100644 --- a/daemons/fenced/fenced_corosync.c +++ b/daemons/fenced/fenced_corosync.c @@ -197,3 +197,10 @@ fenced_cluster_connect(void) return rc; } + +void +fenced_cluster_disconnect(void) +{ + pcmk_cluster_disconnect(fenced_cluster); + pcmk_cluster_free(fenced_cluster); +} diff --git a/daemons/fenced/pacemaker-fenced.c b/daemons/fenced/pacemaker-fenced.c index c6fdbd2baf4..94441959e37 100644 --- a/daemons/fenced/pacemaker-fenced.c +++ b/daemons/fenced/pacemaker-fenced.c @@ -456,8 +456,7 @@ main(int argc, char **argv) g_strfreev(options.log_files); stonith_cleanup(); - pcmk_cluster_disconnect(fenced_cluster); - pcmk_cluster_free(fenced_cluster); + fenced_cluster_disconnect(); fenced_scheduler_cleanup(); pcmk__output_and_clear_error(&error, out); diff --git a/daemons/fenced/pacemaker-fenced.h b/daemons/fenced/pacemaker-fenced.h index 8571b82c4a2..d29fbf422a9 100644 --- a/daemons/fenced/pacemaker-fenced.h +++ b/daemons/fenced/pacemaker-fenced.h @@ -378,6 +378,7 @@ void fenced_ipc_init(void); void fenced_ipc_cleanup(void); int fenced_cluster_connect(void); +void fenced_cluster_disconnect(void); void fenced_handle_request(pcmk__request_t *request); From 4d21015df0f6a381736be4039eb653fd8cbdb541 Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Wed, 10 Dec 2025 14:25:59 -0500 Subject: [PATCH 21/25] Refactor: daemons: Add attrd_cluster_disconnect. And move the definition of attrd_cluster into attrd_corosync.c where it belongs. --- daemons/attrd/attrd_corosync.c | 9 +++++++++ daemons/attrd/pacemaker-attrd.c | 4 +--- daemons/attrd/pacemaker-attrd.h | 1 + 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/daemons/attrd/attrd_corosync.c b/daemons/attrd/attrd_corosync.c index d741824e4b4..fbda13eb90e 100644 --- a/daemons/attrd/attrd_corosync.c +++ b/daemons/attrd/attrd_corosync.c @@ -23,6 +23,8 @@ #include "pacemaker-attrd.h" +pcmk_cluster_t *attrd_cluster = NULL; + /*! * \internal * \brief Nodes removed by \c attrd_peer_remove() @@ -499,6 +501,13 @@ attrd_cluster_connect(void) return rc; } +void +attrd_cluster_disconnect(void) +{ + pcmk_cluster_disconnect(attrd_cluster); + pcmk_cluster_free(attrd_cluster); +} + void attrd_peer_clear_failure(pcmk__request_t *request) { diff --git a/daemons/attrd/pacemaker-attrd.c b/daemons/attrd/pacemaker-attrd.c index 3f14772ba5d..5578624b9a8 100644 --- a/daemons/attrd/pacemaker-attrd.c +++ b/daemons/attrd/pacemaker-attrd.c @@ -56,7 +56,6 @@ static pcmk__supported_format_t formats[] = { }; lrmd_t *the_lrmd = NULL; -pcmk_cluster_t *attrd_cluster = NULL; crm_trigger_t *attrd_config_read = NULL; crm_exit_t attrd_exit_status = CRM_EX_OK; @@ -204,8 +203,7 @@ main(int argc, char **argv) attrd_free_removed_peers(); attrd_free_waitlist(); - pcmk_cluster_disconnect(attrd_cluster); - pcmk_cluster_free(attrd_cluster); + attrd_cluster_disconnect(); g_hash_table_destroy(attributes); } diff --git a/daemons/attrd/pacemaker-attrd.h b/daemons/attrd/pacemaker-attrd.h index e7e980af768..7c07a8fb651 100644 --- a/daemons/attrd/pacemaker-attrd.h +++ b/daemons/attrd/pacemaker-attrd.h @@ -191,6 +191,7 @@ void attrd_free_removed_peers(void); void attrd_erase_removed_peer_attributes(void); int attrd_cluster_connect(void); +void attrd_cluster_disconnect(void); void attrd_broadcast_value(const attribute_t *a, const attribute_value_t *v); void attrd_peer_update(const pcmk__node_status_t *peer, xmlNode *xml, const char *host, bool filter); From 4360b697c13bb57cb8b8243f7eaa32381d347a96 Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Fri, 12 Dec 2025 10:57:34 -0500 Subject: [PATCH 22/25] Low: daemons: Fix a typo if no existing attrd is found. --- daemons/attrd/pacemaker-attrd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemons/attrd/pacemaker-attrd.c b/daemons/attrd/pacemaker-attrd.c index 5578624b9a8..363fd6cb351 100644 --- a/daemons/attrd/pacemaker-attrd.c +++ b/daemons/attrd/pacemaker-attrd.c @@ -72,7 +72,7 @@ ipc_already_running(void) rc = pcmk__connect_ipc(old_instance, pcmk_ipc_dispatch_sync, 2); if (rc != pcmk_rc_ok) { - crm_debug("No existing %s manager instance found: %s", + crm_debug("No existing %s instance found: %s", pcmk_ipc_name(old_instance, true), pcmk_rc_str(rc)); pcmk_free_ipc_api(old_instance); return false; From fa75762655eb6aa41201cf7788b1d5e058148a41 Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Fri, 12 Dec 2025 11:08:54 -0500 Subject: [PATCH 23/25] Refactor: daemons: Make unknown request messages more similar. Some (but not all) daemons can handle both IPC and CPG message types, so the unknown request message should be able to print both. I'm doing this even on daemons that only handle one type in the interest of making these functions as similar as possible. Other daemons have a different style of unknown request function. Rather than sort that out right now (I think we'll need to figure out the ACK vs NACK thing first), I'm just removing the message type detail from the result. --- daemons/attrd/attrd_messages.c | 3 ++- daemons/execd/execd_messages.c | 2 +- daemons/pacemakerd/pcmkd_messages.c | 2 +- daemons/schedulerd/schedulerd_messages.c | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/daemons/attrd/attrd_messages.c b/daemons/attrd/attrd_messages.c index 50e7f5c420a..5b9f06976c4 100644 --- a/daemons/attrd/attrd_messages.c +++ b/daemons/attrd/attrd_messages.c @@ -55,7 +55,8 @@ remove_unsupported_sync_points(pcmk__request_t *request) static xmlNode * handle_unknown_request(pcmk__request_t *request) { - crm_err("Unknown IPC request %s from %s %s", + crm_err("Unknown %s request %s from %s %s", + (request->ipc_client != NULL) ? "IPC" : "CPG", request->op, pcmk__request_origin_type(request), pcmk__request_origin(request)); pcmk__format_result(&request->result, CRM_EX_PROTOCOL, PCMK_EXEC_INVALID, diff --git a/daemons/execd/execd_messages.c b/daemons/execd/execd_messages.c index 9f9229e77e0..a37d4ebeeff 100644 --- a/daemons/execd/execd_messages.c +++ b/daemons/execd/execd_messages.c @@ -402,7 +402,7 @@ handle_unknown_request(pcmk__request_t *request) PCMK__XE_NACK, NULL, CRM_EX_PROTOCOL); pcmk__format_result(&request->result, CRM_EX_PROTOCOL, PCMK_EXEC_INVALID, - "Unknown IPC request type '%s' (bug?)", + "Unknown request type '%s' (bug?)", pcmk__s(request->op, "")); return NULL; } diff --git a/daemons/pacemakerd/pcmkd_messages.c b/daemons/pacemakerd/pcmkd_messages.c index 1fc0e57897d..de96edddb50 100644 --- a/daemons/pacemakerd/pcmkd_messages.c +++ b/daemons/pacemakerd/pcmkd_messages.c @@ -153,7 +153,7 @@ handle_unknown_request(pcmk__request_t *request) PCMK__XE_ACK, NULL, CRM_EX_PROTOCOL); pcmk__format_result(&request->result, CRM_EX_PROTOCOL, PCMK_EXEC_INVALID, - "Unknown IPC request type '%s' (bug?)", + "Unknown request type '%s' (bug?)", pcmk__s(request->op, "")); return NULL; } diff --git a/daemons/schedulerd/schedulerd_messages.c b/daemons/schedulerd/schedulerd_messages.c index a004db00074..bce27a0af48 100644 --- a/daemons/schedulerd/schedulerd_messages.c +++ b/daemons/schedulerd/schedulerd_messages.c @@ -190,7 +190,7 @@ handle_unknown_request(pcmk__request_t *request) PCMK__XE_ACK, NULL, CRM_EX_PROTOCOL); pcmk__format_result(&request->result, CRM_EX_PROTOCOL, PCMK_EXEC_INVALID, - "Unknown IPC request type '%s' (bug?)", + "Unknown request type '%s' (bug?)", pcmk__s(request->op, "")); return NULL; } From 1feccdee51f46b5f39a76e99d3ca83cea367bacd Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Fri, 12 Dec 2025 11:27:30 -0500 Subject: [PATCH 24/25] Low: daemons: Fix typos in IPC doxygen blocks. --- daemons/pacemakerd/pcmkd_ipc.c | 2 +- daemons/schedulerd/schedulerd_ipc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/daemons/pacemakerd/pcmkd_ipc.c b/daemons/pacemakerd/pcmkd_ipc.c index 54e59347ecf..88da9c77fe7 100644 --- a/daemons/pacemakerd/pcmkd_ipc.c +++ b/daemons/pacemakerd/pcmkd_ipc.c @@ -99,7 +99,7 @@ pacemakerd_ipc_destroy(qb_ipcs_connection_t *c) * \param[in] data The message data read from the connection - this can be * a complete IPC message or just a part of one if it's * very large - * \param[size] size Unused + * \param[in] size Unused * * \return 0 in all cases */ diff --git a/daemons/schedulerd/schedulerd_ipc.c b/daemons/schedulerd/schedulerd_ipc.c index 81d96a05d17..95468664bc1 100644 --- a/daemons/schedulerd/schedulerd_ipc.c +++ b/daemons/schedulerd/schedulerd_ipc.c @@ -53,7 +53,7 @@ schedulerd_ipc_accept(qb_ipcs_connection_t *c, uid_t uid, gid_t gid) * \param[in] data The message data read from the connection - this can be * a complete IPC message or just a part of one if it's * very large - * \param[size] size Unused + * \param[in] size Unused * * \return 0 in all cases */ From 6bdf2de00bb764dfe405b55990de453cba5da6bd Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Fri, 12 Dec 2025 11:59:45 -0500 Subject: [PATCH 25/25] Low: daemons: Add SUPPORT_COROSYNC guards to attrd. --- daemons/attrd/attrd_corosync.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/daemons/attrd/attrd_corosync.c b/daemons/attrd/attrd_corosync.c index fbda13eb90e..67614977082 100644 --- a/daemons/attrd/attrd_corosync.c +++ b/daemons/attrd/attrd_corosync.c @@ -135,6 +135,7 @@ attrd_peer_message(pcmk__node_status_t *peer, xmlNode *xml) } } +#if SUPPORT_COROSYNC /*! * \internal * \brief Callback for when a peer message is received @@ -190,6 +191,7 @@ attrd_cpg_destroy(gpointer unused) attrd_shutdown(0); } } +#endif // SUPPORT_COROSYNC /*! * \internal @@ -487,9 +489,13 @@ attrd_cluster_connect(void) attrd_cluster = pcmk_cluster_new(); - pcmk_cluster_set_destroy_fn(attrd_cluster, attrd_cpg_destroy); - pcmk_cpg_set_deliver_fn(attrd_cluster, attrd_cpg_dispatch); - pcmk_cpg_set_confchg_fn(attrd_cluster, pcmk__cpg_confchg_cb); +#if SUPPORT_COROSYNC + if (pcmk_get_cluster_layer() == pcmk_cluster_layer_corosync) { + pcmk_cluster_set_destroy_fn(attrd_cluster, attrd_cpg_destroy); + pcmk_cpg_set_deliver_fn(attrd_cluster, attrd_cpg_dispatch); + pcmk_cpg_set_confchg_fn(attrd_cluster, pcmk__cpg_confchg_cb); + } +#endif // SUPPORT_COROSYNC pcmk__cluster_set_status_callback(&attrd_peer_change_cb);