diff --git a/daemons/based/based_callbacks.c b/daemons/based/based_callbacks.c index d2e59a67373..71679d43275 100644 --- a/daemons/based/based_callbacks.c +++ b/daemons/based/based_callbacks.c @@ -28,7 +28,7 @@ #include // crm_ipc_*, pcmk_ipc_* #include // CRM_LOG_ASSERT, CRM_CHECK #include // mainloop_* -#include // CRM_EX_OK, crm_exit_t, pcmk_rc_* +#include // pcmk_rc_* #include // PCMK_XA_*, PCMK_XE_* #include // CRM_OP_* @@ -39,6 +39,85 @@ static long long ping_seq = 0; static char *ping_digest = NULL; static bool ping_modified_since = false; +/*! + * \internal + * \brief Request CIB digests from all peer nodes + * + * This is used as a callback that runs 5 seconds after we modify the CIB on the + * DC. It sends a ping request to all cluster nodes. They will respond by + * sending their current digests and version info, which we will validate in + * process_ping_reply(). If their digest doesn't match, we'll sync our own CIB + * to them. This helps ensure consistency across the cluster after a CIB update. + * + * \param[in] data Ignored + * + * \return \c G_SOURCE_REMOVE (to destroy the timeout) + * + * \note It's not clear why we wait 5 seconds rather than sending the ping + * request immediately after a performing a modifying op. Perhaps it's to + * avoid overwhelming other nodes with ping requests when there are a lot + * of modifying requests in a short period. The timer restarts after + * every successful modifying op, so we send ping requests **at most** + * every 5 seconds. Or perhaps it's a remnant of legacy mode (pre-1.1.12). + * In any case, the other nodes shouldn't need time to process the + * modifying op before responding to the ping request. The ping request is + * sent after the op is sent, so it should also be received after the op + * is received. + */ +static gboolean +digest_timer_cb(void *data) +{ + xmlNode *ping = NULL; + + if (!based_get_local_node_dc()) { + // Only the DC sends a ping + return G_SOURCE_REMOVE; + } + + if (++ping_seq < 0) { + ping_seq = 0; + } + + g_clear_pointer(&ping_digest, free); + ping_modified_since = false; + + ping = pcmk__xe_create(NULL, PCMK__XE_PING); + pcmk__xe_set(ping, PCMK__XA_T, PCMK__VALUE_CIB); + pcmk__xe_set(ping, PCMK__XA_CIB_OP, CRM_OP_PING); + pcmk__xe_set_ll(ping, PCMK__XA_CIB_PING_ID, ping_seq); + pcmk__xe_set(ping, PCMK_XA_CRM_FEATURE_SET, CRM_FEATURE_SET); + + pcmk__trace("Requesting peer digests (%lld)", ping_seq); + pcmk__cluster_send_message(NULL, pcmk_ipc_based, ping); + + pcmk__xml_free(ping); + return G_SOURCE_REMOVE; +} + +/*! + * \internal + * \brief Initialize data structures used for CIB manager callbacks + */ +void +based_callbacks_init(void) +{ + if (digest_timer == NULL) { + digest_timer = mainloop_timer_add("based_digest_timer", 5000, false, + digest_timer_cb, NULL); + } +} + +/*! + * \internal + * \brief Free data structures used for CIB manager callbacks + */ +void +based_callbacks_cleanup(void) +{ + g_clear_pointer(&digest_timer, mainloop_timer_del); + g_clear_pointer(&ping_digest, free); +} + /*! * \internal * \brief Create reply XML for a CIB request @@ -148,61 +227,6 @@ do_local_notify(const xmlNode *xml, const char *client_id, bool sync_reply, } } -/*! - * \internal - * \brief Request CIB digests from all peer nodes - * - * This is used as a callback that runs 5 seconds after we modify the CIB on the - * DC. It sends a ping request to all cluster nodes. They will respond by - * sending their current digests and version info, which we will validate in - * process_ping_reply(). If their digest doesn't match, we'll sync our own CIB - * to them. This helps ensure consistency across the cluster after a CIB update. - * - * \param[in] data Ignored - * - * \return \c G_SOURCE_REMOVE (to destroy the timeout) - * - * \note It's not clear why we wait 5 seconds rather than sending the ping - * request immediately after a performing a modifying op. Perhaps it's to - * avoid overwhelming other nodes with ping requests when there are a lot - * of modifying requests in a short period. The timer restarts after - * every successful modifying op, so we send ping requests **at most** - * every 5 seconds. Or perhaps it's a remnant of legacy mode (pre-1.1.12). - * In any case, the other nodes shouldn't need time to process the - * modifying op before responding to the ping request. The ping request is - * sent after the op is sent, so it should also be received after the op - * is received. - */ -static gboolean -digest_timer_cb(void *data) -{ - xmlNode *ping = NULL; - - if (!based_get_local_node_dc()) { - // Only the DC sends a ping - return G_SOURCE_REMOVE; - } - - if (++ping_seq < 0) { - ping_seq = 0; - } - - g_clear_pointer(&ping_digest, free); - ping_modified_since = false; - - ping = pcmk__xe_create(NULL, PCMK__XE_PING); - pcmk__xe_set(ping, PCMK__XA_T, PCMK__VALUE_CIB); - pcmk__xe_set(ping, PCMK__XA_CIB_OP, CRM_OP_PING); - pcmk__xe_set_ll(ping, PCMK__XA_CIB_PING_ID, ping_seq); - pcmk__xe_set(ping, PCMK_XA_CRM_FEATURE_SET, CRM_FEATURE_SET); - - pcmk__trace("Requesting peer digests (%lld)", ping_seq); - pcmk__cluster_send_message(NULL, pcmk_ipc_based, ping); - - pcmk__xml_free(ping); - return G_SOURCE_REMOVE; -} - /*! * \internal * \brief Process a reply to a \c CRM_OP_PING request @@ -542,11 +566,6 @@ based_perform_op_rw(xmlNode *request, const cib__operation_t *operation, ping_modified_since = true; } - if (digest_timer == NULL) { - digest_timer = mainloop_timer_add("based_digest_timer", 5000, false, - digest_timer_cb, NULL); - } - mainloop_timer_start(digest_timer); done: @@ -812,35 +831,3 @@ based_process_request(xmlNode *request, bool privileged, pcmk__xml_free(reply); return rc; } - -/*! - * \internal - * \brief Close remote sockets, free the global CIB and quit - * - * \param[in] exit_status Exit code - */ -void -based_terminate(crm_exit_t exit_status) -{ - based_ipc_cleanup(); - based_remote_cleanup(); - - g_clear_pointer(&digest_timer, mainloop_timer_del); - g_clear_pointer(&ping_digest, free); - g_clear_pointer(&based_cib, pcmk__xml_free); - - // Exit immediately on error - if (exit_status != CRM_EX_OK) { - crm_exit(exit_status); - return; - } - - based_cluster_disconnect(); - - if ((mainloop != NULL) && g_main_loop_is_running(mainloop)) { - g_main_loop_quit(mainloop); - return; - } - - crm_exit(CRM_EX_OK); -} diff --git a/daemons/based/based_callbacks.h b/daemons/based/based_callbacks.h index 3e71e2f2984..7363e7ab2d6 100644 --- a/daemons/based/based_callbacks.h +++ b/daemons/based/based_callbacks.h @@ -15,10 +15,11 @@ #include // xmlNode #include // pcmk__client_t -#include // crm_exit_t + +void based_callbacks_init(void); +void based_callbacks_cleanup(void); int based_process_request(xmlNode *request, bool privileged, const pcmk__client_t *client); -void based_terminate(crm_exit_t exit_status); #endif // BASED_CALLBACKS__H diff --git a/daemons/based/based_corosync.c b/daemons/based/based_corosync.c index a6d4229b50a..cf8fc547d6c 100644 --- a/daemons/based/based_corosync.c +++ b/daemons/based/based_corosync.c @@ -15,7 +15,7 @@ #include // free #include // cpg_* -#include // gpointer +#include // g_clear_pointer #include // xmlNode #include // SUPPORT_COROSYNC diff --git a/daemons/based/based_io.c b/daemons/based/based_io.c index 2f30e4d522c..5e6a12153ab 100644 --- a/daemons/based/based_io.c +++ b/daemons/based/based_io.c @@ -31,7 +31,7 @@ #include // createEmptyCib #include // pcmk__assert_asprintf, PCMK__XE_*, etc. #include // CRM_CHECK -#include // mainloop_add_signal +#include // mainloop_* #include // pcmk_legacy2rc, pcmk_rc_* #include // pcmk_common_cleanup #include // PCMK_XA_*, PCMK_XE_* @@ -176,7 +176,7 @@ based_enable_writes(int nsig) /*! * \internal - * \brief Initialize data structures for \c pacemaker-based I/O + * \brief Initialize data structures used for CIB manager I/O */ void based_io_init(void) @@ -198,6 +198,16 @@ based_io_init(void) write_trigger = mainloop_add_trigger(G_PRIORITY_LOW, write_cib_async, NULL); } +/*! + * \internal + * \brief Free data structures used for CIB manager I/O + */ +void +based_io_cleanup(void) +{ + g_clear_pointer(&write_trigger, mainloop_destroy_trigger); +} + /*! * \internal * \brief Rename a CIB or digest file after digest mismatch diff --git a/daemons/based/based_io.h b/daemons/based/based_io.h index f9bb5011a1a..706d476d026 100644 --- a/daemons/based/based_io.h +++ b/daemons/based/based_io.h @@ -15,6 +15,8 @@ #include // xmlNode void based_io_init(void); +void based_io_cleanup(void); + void based_enable_writes(int nsig); xmlNode *based_read_cib(void); int based_activate_cib(xmlNode *new_cib, bool to_disk, const char *op); diff --git a/daemons/based/based_ipc.c b/daemons/based/based_ipc.c index 9f1af42b97b..9e32dfdbd5f 100644 --- a/daemons/based/based_ipc.c +++ b/daemons/based/based_ipc.c @@ -30,7 +30,6 @@ static qb_ipcs_service_t *ipcs_ro = NULL; static qb_ipcs_service_t *ipcs_rw = NULL; -static qb_ipcs_service_t *ipcs_shm = NULL; /*! * \internal @@ -305,7 +304,7 @@ static struct qb_ipcs_service_handlers ipc_rw_callbacks = { void based_ipc_init(void) { - pcmk__serve_based_ipc(&ipcs_ro, &ipcs_rw, &ipcs_shm, &ipc_ro_callbacks, + pcmk__serve_based_ipc(&ipcs_ro, &ipcs_rw, &ipc_ro_callbacks, &ipc_rw_callbacks); } @@ -322,9 +321,6 @@ based_ipc_cleanup(void) pcmk__drop_all_clients(ipcs_rw); g_clear_pointer(&ipcs_rw, qb_ipcs_destroy); - pcmk__drop_all_clients(ipcs_shm); - g_clear_pointer(&ipcs_shm, qb_ipcs_destroy); - /* Drop remote clients here because they're part of the IPC client table and * must be dropped before \c pcmk__client_cleanup() */ diff --git a/daemons/based/based_remote.c b/daemons/based/based_remote.c index 035ece5d3bd..7695ea8947b 100644 --- a/daemons/based/based_remote.c +++ b/daemons/based/based_remote.c @@ -48,8 +48,8 @@ static pcmk__tls_t *tls = NULL; -static int remote_fd = -1; -static int remote_tls_fd = -1; +static mainloop_io_t *tcp_listener = NULL; +static mainloop_io_t *tls_listener = NULL; // @TODO This is rather short for someone to type their password #define REMOTE_AUTH_TIMEOUT 10000 @@ -547,13 +547,15 @@ based_remote_client_destroy(void *user_data) } static int -cib_remote_listen(void *data) +cib_remote_listen(void *user_data) { + int ssock = GPOINTER_TO_INT(user_data); + const bool is_tls = (tls_listener != NULL) && (ssock == tls_listener->fd); + int csock = -1; unsigned laddr; struct sockaddr_storage addr; char ipstr[INET6_ADDRSTRLEN]; - int ssock = *(int *)data; int rc; pcmk__client_t *new_client = NULL; @@ -587,7 +589,7 @@ cib_remote_listen(void *data) new_client = pcmk__new_unauth_client(NULL); new_client->remote = pcmk__assert_alloc(1, sizeof(pcmk__remote_t)); - if (ssock == remote_tls_fd) { + if (is_tls) { pcmk__set_client_flags(new_client, pcmk__client_tls); /* create gnutls session for the server socket */ @@ -610,8 +612,7 @@ cib_remote_listen(void *data) remote_auth_timeout_cb, new_client); pcmk__info("%s connection from %s pending authentication for client %s", - ((ssock == remote_tls_fd)? "Encrypted" : "Clear-text"), ipstr, - new_client->id); + (is_tls? "Encrypted" : "Clear-text"), ipstr, new_client->id); new_client->remote->source = mainloop_add_fd("cib-remote-client", G_PRIORITY_DEFAULT, csock, new_client, @@ -626,13 +627,14 @@ based_remote_listener_destroy(void *user_data) pcmk__info("No longer listening for remote connections"); } -static int +static mainloop_io_t * init_remote_listener(int port) { int rc; - int *ssock = NULL; + int ssock = -1; struct sockaddr_in saddr; int optval; + mainloop_io_t *listener = NULL; static struct mainloop_fd_callbacks remote_listen_fd_callbacks = { .dispatch = cib_remote_listen, @@ -645,20 +647,18 @@ init_remote_listener(int port) #endif /* create server socket */ - ssock = pcmk__assert_alloc(1, sizeof(int)); - *ssock = socket(AF_INET, SOCK_STREAM, 0); - if (*ssock == -1) { - pcmk__err("Listener socket creation failed: %s", pcmk_rc_str(errno)); - free(ssock); - return -1; + ssock = socket(AF_INET, SOCK_STREAM, 0); + if (ssock == -1) { + pcmk__err("Listener socket creation failed: %s", strerror(errno)); + return NULL; } /* reuse address */ optval = 1; - rc = setsockopt(*ssock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + rc = setsockopt(ssock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); if (rc < 0) { pcmk__err("Local address reuse not allowed on listener socket: %s", - pcmk_rc_str(errno)); + strerror(errno)); } /* bind server socket */ @@ -666,23 +666,28 @@ init_remote_listener(int port) saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = INADDR_ANY; saddr.sin_port = htons(port); - if (bind(*ssock, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) { - pcmk__err("Cannot bind to listener socket: %s", pcmk_rc_str(errno)); - close(*ssock); - free(ssock); - return -2; + if (bind(ssock, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) { + pcmk__err("Cannot bind to listener socket: %s", strerror(errno)); + close(ssock); + return NULL; } - if (listen(*ssock, 10) == -1) { - pcmk__err("Cannot listen on socket: %s", pcmk_rc_str(errno)); - close(*ssock); - free(ssock); - return -3; + if (listen(ssock, 10) == -1) { + pcmk__err("Cannot listen on socket: %s", strerror(errno)); + close(ssock); + return NULL; } - mainloop_add_fd("cib-remote", G_PRIORITY_DEFAULT, *ssock, ssock, &remote_listen_fd_callbacks); - pcmk__debug("Started listener on port %d", port); + listener = mainloop_add_fd("based-remote-listener", G_PRIORITY_DEFAULT, + ssock, GINT_TO_POINTER(ssock), + &remote_listen_fd_callbacks); + if (listener == NULL) { + pcmk__err("Cannot add pacemaker-based remote listener (port %d) to " + "mainloop: %s", port, strerror(errno)); + return NULL; + } - return *ssock; + pcmk__debug("Started pacemaker-based remote listener on port %d", port); + return listener; } /*! @@ -734,8 +739,6 @@ based_remote_init(void) if (rc != pcmk_rc_ok) { pcmk__err("Failed to initialize TLS: %s. Not starting TLS listener ", "on port %d", pcmk_rc_str(rc), port); - - remote_tls_fd = -1; goto try_clear_port; } @@ -745,7 +748,7 @@ based_remote_init(void) } pcmk__notice("Starting TLS listener on port %d", port); - remote_tls_fd = init_remote_listener(port); + tls_listener = init_remote_listener(port); try_clear_port: /* Regardless of whether or not we successfully enabled remote-tls-port, @@ -757,7 +760,7 @@ based_remote_init(void) pcmk__warn("Starting clear-text listener on port %d. This is insecure " "and will be removed in a future release. Use " PCMK_XA_REMOTE_TLS_PORT " instead.", port); - remote_fd = init_remote_listener(port); + tcp_listener = init_remote_listener(port); } } @@ -772,15 +775,8 @@ based_remote_init(void) void based_remote_cleanup(void) { - if (remote_fd >= 0) { - close(remote_fd); - remote_fd = -1; - } - - if (remote_tls_fd >= 0) { - close(remote_tls_fd); - remote_tls_fd = -1; - } + g_clear_pointer(&tcp_listener, mainloop_del_fd); + g_clear_pointer(&tls_listener, mainloop_del_fd); } /*! diff --git a/daemons/based/pacemaker-based.c b/daemons/based/pacemaker-based.c index 65653ab517c..bb5f767225a 100644 --- a/daemons/based/pacemaker-based.c +++ b/daemons/based/pacemaker-based.c @@ -23,10 +23,11 @@ #include // CRM_CONFIG_DIR, CRM_DAEMON_USER #include // pcmk__node_update, etc. +#include // PCMK__EXITC_ERROR, pcmk__err, etc. #include // crm_ipc_* #include // crm_log_* #include // mainloop_add_signal -#include // CRM_EX_*, pcmk_rc_* +#include // CRM_EX_*, crm_exit_t, pcmk_rc_* #include "pacemaker-based.h" @@ -48,14 +49,13 @@ xmlNode *based_cib = NULL; int cib_status = pcmk_rc_ok; - -GMainLoop *mainloop = NULL; gchar *cib_root = NULL; static bool local_node_dc = false; static bool shutting_down = false; static gboolean stand_alone = FALSE; static crm_exit_t exit_code = CRM_EX_OK; +static GMainLoop *mainloop = NULL; /*! * \internal @@ -221,6 +221,56 @@ build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) return context; } +/*! + * \internal + * \brief Clean up CIB manager data structures + */ +static void +based_cleanup(void) +{ + based_callbacks_cleanup(); + based_io_cleanup(); + based_ipc_cleanup(); + based_remote_cleanup(); + + g_clear_pointer(&based_cib, pcmk__xml_free); + g_clear_pointer(&cib_root, g_free); +} + +/*! + * \internal + * \brief Clean up data structures and exit + * + * \param[in] exit_status Exit code + */ +void +based_terminate(crm_exit_t exit_status) +{ + shutting_down = true; + based_cleanup(); + + if (exit_status != CRM_EX_OK) { + /* After calling g_main_loop_quit(), sources that have already been + * dispatched are still executed. On error, skip that and exit + * immediately after cleaning up data structures. + * + * @TODO Is this necessary? It would be nice to do the cleanup at the + * end of main(). If so, then one (complicated) option would be to keep + * track of all main loop sources and destroy them so that + * g_main_dispatch() ignores them. + */ + crm_exit(exit_status); + } + + based_cluster_disconnect(); + + // There should be no way to get here without the main loop running + CRM_CHECK((mainloop != NULL) && g_main_loop_is_running(mainloop), + crm_exit(exit_status)); + + g_main_loop_quit(mainloop); +} + static void based_shutdown(int nsig) { @@ -368,9 +418,8 @@ main(int argc, char **argv) g_strfreev(processed_args); pcmk__free_arg_context(context); - pcmk__client_cleanup(); based_cluster_disconnect(); - g_free(cib_root); + based_cleanup(); pcmk__output_and_clear_error(&error, out); diff --git a/daemons/based/pacemaker-based.h b/daemons/based/pacemaker-based.h index 9922ee462e6..b4c53ded680 100644 --- a/daemons/based/pacemaker-based.h +++ b/daemons/based/pacemaker-based.h @@ -12,7 +12,9 @@ #include -#include // gchar, GMainLoop +#include // gchar + +#include // crm_exit_t #include "based_callbacks.h" #include "based_corosync.h" @@ -25,8 +27,6 @@ #include "based_transaction.h" extern xmlNode *based_cib; - -extern GMainLoop *mainloop; extern gchar *cib_root; extern int cib_status; @@ -36,4 +36,6 @@ void based_set_local_node_dc(bool value); bool based_shutting_down(void); bool based_stand_alone(void); +void based_terminate(crm_exit_t exit_status); + #endif // PACEMAKER_BASED__H diff --git a/daemons/controld/controld_cib.c b/daemons/controld/controld_cib.c index f88fc0492d1..cadda850a80 100644 --- a/daemons/controld/controld_cib.c +++ b/daemons/controld/controld_cib.c @@ -155,13 +155,11 @@ do_cib_control(long long action, enum crmd_fsa_cause cause, return; } - rc = cib_conn->cmds->signon(cib_conn, crm_system_name, - cib_command_nonblocking); + rc = cib_conn->cmds->signon(cib_conn, crm_system_name, cib_command); if (rc != pcmk_ok) { // A short wait that usually avoids stalling the FSA sleep(1); - rc = cib_conn->cmds->signon(cib_conn, crm_system_name, - cib_command_nonblocking); + rc = cib_conn->cmds->signon(cib_conn, crm_system_name, cib_command); } if (rc != pcmk_ok) { diff --git a/daemons/execd/remoted_proxy.c b/daemons/execd/remoted_proxy.c index d4432284291..7c64d4675d1 100644 --- a/daemons/execd/remoted_proxy.c +++ b/daemons/execd/remoted_proxy.c @@ -30,7 +30,6 @@ static qb_ipcs_service_t *cib_ro = NULL; static qb_ipcs_service_t *cib_rw = NULL; -static qb_ipcs_service_t *cib_shm = NULL; static qb_ipcs_service_t *attrd_ipcs = NULL; static qb_ipcs_service_t *crmd_ipcs = NULL; @@ -520,7 +519,7 @@ ipc_proxy_init(void) { ipc_clients = pcmk__strkey_table(NULL, NULL); - pcmk__serve_based_ipc(&cib_ro, &cib_rw, &cib_shm, &cib_proxy_callbacks_ro, + pcmk__serve_based_ipc(&cib_ro, &cib_rw, &cib_proxy_callbacks_ro, &cib_proxy_callbacks_rw); pcmk__serve_attrd_ipc(&attrd_ipcs, &attrd_proxy_callbacks); pcmk__serve_fenced_ipc(&fencer_ipcs, &fencer_proxy_callbacks); @@ -541,14 +540,10 @@ ipc_proxy_cleanup(void) g_clear_pointer(&ipc_providers, g_list_free); g_clear_pointer(&ipc_clients, g_hash_table_destroy); - pcmk__stop_based_ipc(cib_ro, cib_rw, cib_shm); - g_clear_pointer(&attrd_ipcs, qb_ipcs_destroy); + g_clear_pointer(&cib_ro, qb_ipcs_destroy); + g_clear_pointer(&cib_rw, qb_ipcs_destroy); + g_clear_pointer(&crmd_ipcs, qb_ipcs_destroy); g_clear_pointer(&fencer_ipcs, qb_ipcs_destroy); g_clear_pointer(&pacemakerd_ipcs, qb_ipcs_destroy); - g_clear_pointer(&crmd_ipcs, qb_ipcs_destroy); - - cib_ro = NULL; - cib_rw = NULL; - cib_shm = NULL; } diff --git a/etc/sysconfig/pacemaker.in b/etc/sysconfig/pacemaker.in index a7763f6d180..fe65ee30576 100644 --- a/etc/sysconfig/pacemaker.in +++ b/etc/sysconfig/pacemaker.in @@ -337,20 +337,6 @@ # Default: PCMK_dh_max_bits="0" (no maximum) -## Inter-process Communication - -# PCMK_ipc_type (Advanced Use Only) -# -# Force use of a particular IPC method. Allowed values: -# -# shared-mem -# socket -# posix -# sysv -# -# Default: PCMK_ipc_type="shared-mem" - - ## Cluster type # PCMK_cluster_type (Advanced Use Only) diff --git a/include/crm/cib/cib_types.h b/include/crm/cib/cib_types.h index 172439bbf29..41fd6094b87 100644 --- a/include/crm/cib/cib_types.h +++ b/include/crm/cib/cib_types.h @@ -53,6 +53,8 @@ enum cib_conn_type { cib_query, cib_no_connection, + + //! \deprecated Use \c cib_command instead cib_command_nonblocking, }; diff --git a/include/crm/common/ipc_internal.h b/include/crm/common/ipc_internal.h index eecc8bb612a..4fc29087420 100644 --- a/include/crm/common/ipc_internal.h +++ b/include/crm/common/ipc_internal.h @@ -251,14 +251,9 @@ qb_ipcs_service_t *pcmk__serve_controld_ipc(struct qb_ipcs_service_handlers *cb) void pcmk__serve_based_ipc(qb_ipcs_service_t **ipcs_ro, qb_ipcs_service_t **ipcs_rw, - qb_ipcs_service_t **ipcs_shm, struct qb_ipcs_service_handlers *ro_cb, struct qb_ipcs_service_handlers *rw_cb); -void pcmk__stop_based_ipc(qb_ipcs_service_t *ipcs_ro, - qb_ipcs_service_t *ipcs_rw, - qb_ipcs_service_t *ipcs_shm); - static inline const char * pcmk__ipc_sys_name(const char *ipc_name, const char *fallback) { diff --git a/include/crm/common/mainloop.h b/include/crm/common/mainloop.h index 680d251994e..17a0ea1cc12 100644 --- a/include/crm/common/mainloop.h +++ b/include/crm/common/mainloop.h @@ -118,7 +118,7 @@ qb_ipcs_service_t *mainloop_add_ipc_server(const char *name, enum qb_ipc_type ty * \brief Start server-side API end-point, hooked into the internal event loop * * \param[in] name name of the IPC end-point ("address" for the client) - * \param[in] type selects libqb's IPC back-end (or use #QB_IPC_NATIVE) + * \param[in] type Ignored * \param[in] callbacks defines libqb's IPC service-level handlers * \param[in] priority priority relative to other events handled in the * abstract handling loop, use #QB_LOOP_MED when unsure diff --git a/include/crm/common/mainloop_internal.h b/include/crm/common/mainloop_internal.h index d16aab01fbb..70cf3da79bb 100644 --- a/include/crm/common/mainloop_internal.h +++ b/include/crm/common/mainloop_internal.h @@ -38,6 +38,20 @@ struct mainloop_child_s { pcmk__mainloop_child_exit_fn_t exit_fn; }; +struct mainloop_io_s { + char *name; + void *userdata; + + int fd; + unsigned int source; + crm_ipc_t *ipc; + GIOChannel *channel; + + int (*dispatch_fn_ipc)(const char *buffer, ssize_t length, void *user_data); + int (*dispatch_fn_io)(void *user_data); + void (*destroy_fn)(void *user_data); +}; + int pcmk__add_mainloop_ipc(crm_ipc_t *ipc, int priority, void *userdata, const struct ipc_client_callbacks *callbacks, mainloop_io_t **source); diff --git a/include/crm/common/options_internal.h b/include/crm/common/options_internal.h index 22b8e303a21..b1b2085db7f 100644 --- a/include/crm/common/options_internal.h +++ b/include/crm/common/options_internal.h @@ -152,7 +152,6 @@ bool pcmk__valid_fencing_watchdog_timeout(const char *value); #define PCMK__ENV_CRL_FILE "crl_file" #define PCMK__ENV_DEBUG "debug" #define PCMK__ENV_FAIL_FAST "fail_fast" -#define PCMK__ENV_IPC_TYPE "ipc_type" #define PCMK__ENV_KEY_FILE "key_file" #define PCMK__ENV_LOGFACILITY "logfacility" #define PCMK__ENV_LOGFILE "logfile" diff --git a/include/crm_internal.h b/include/crm_internal.h index 277fe824830..407737bb7d9 100644 --- a/include/crm_internal.h +++ b/include/crm_internal.h @@ -1,5 +1,5 @@ /* - * Copyright 2006-2025 the Pacemaker project contributors + * Copyright 2006-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -61,7 +61,6 @@ extern "C" { #define PCMK__SERVER_BASED_RO "cib_ro" #define PCMK__SERVER_BASED_RW "cib_rw" -#define PCMK__SERVER_BASED_SHM "cib_shm" /* * IPC commands that can be sent to Pacemaker daemons diff --git a/lib/cib/cib_native.c b/lib/cib/cib_native.c index f5e59415d9a..39524166492 100644 --- a/lib/cib/cib_native.c +++ b/lib/cib/cib_native.c @@ -297,20 +297,21 @@ cib_native_signon(cib_t *cib, const char *name, enum cib_conn_type type) cib->call_timeout = PCMK__IPC_TIMEOUT; - if (type == cib_command) { - cib->state = cib_connected_command; - channel = PCMK__SERVER_BASED_RW; - - } else if (type == cib_command_nonblocking) { - cib->state = cib_connected_command; - channel = PCMK__SERVER_BASED_SHM; + switch (type) { + case cib_command: + case cib_command_nonblocking: + // @COMPAT cib_command_nonblocking is deprecated since 3.0.2 + cib->state = cib_connected_command; + channel = PCMK__SERVER_BASED_RW; + break; - } else if (type == cib_query) { - cib->state = cib_connected_query; - channel = PCMK__SERVER_BASED_RO; + case cib_query: + cib->state = cib_connected_query; + channel = PCMK__SERVER_BASED_RO; + break; - } else { - return -ENOTCONN; + default: + return -ENOTCONN; } pcmk__trace("Connecting %s channel", channel); diff --git a/lib/cluster/corosync.c b/lib/cluster/corosync.c index 071360662bf..5b1c9136745 100644 --- a/lib/cluster/corosync.c +++ b/lib/cluster/corosync.c @@ -23,7 +23,7 @@ #include // cmap_* #include // cs_*, CS_* #include // quorum_* -#include // gboolean, gpointer, g_*, G_PRIORITY_HIGH +#include // gboolean, g_*, G_PRIORITY_HIGH #include // xmlNode #include // QB_XS diff --git a/lib/common/ipc_server.c b/lib/common/ipc_server.c index 212d43bef6e..21fc876873f 100644 --- a/lib/common/ipc_server.c +++ b/lib/common/ipc_server.c @@ -1021,30 +1021,26 @@ pcmk__ipc_send_ack_as(const char *function, int line, pcmk__client_t *c, * * \param[out] ipcs_ro New IPC server for read-only CIB manager API * \param[out] ipcs_rw New IPC server for read/write CIB manager API - * \param[out] ipcs_shm New IPC server for shared-memory CIB manager API * \param[in] ro_cb IPC callbacks for read-only API * \param[in] rw_cb IPC callbacks for read/write and shared-memory APIs * * \note This function exits fatally on error. - * \note There is no actual difference between the three IPC endpoints other - * than their names. */ -void pcmk__serve_based_ipc(qb_ipcs_service_t **ipcs_ro, - qb_ipcs_service_t **ipcs_rw, - qb_ipcs_service_t **ipcs_shm, - struct qb_ipcs_service_handlers *ro_cb, - struct qb_ipcs_service_handlers *rw_cb) +void +pcmk__serve_based_ipc(qb_ipcs_service_t **ipcs_ro, qb_ipcs_service_t **ipcs_rw, + struct qb_ipcs_service_handlers *ro_cb, + struct qb_ipcs_service_handlers *rw_cb) { - *ipcs_ro = mainloop_add_ipc_server(PCMK__SERVER_BASED_RO, - QB_IPC_NATIVE, ro_cb); + pcmk__assert((ipcs_ro != NULL) && (*ipcs_ro == NULL) && (ro_cb != NULL) + && (ipcs_rw != NULL) && (*ipcs_rw == NULL) && (rw_cb != NULL)); - *ipcs_rw = mainloop_add_ipc_server(PCMK__SERVER_BASED_RW, - QB_IPC_NATIVE, rw_cb); + *ipcs_ro = mainloop_add_ipc_server(PCMK__SERVER_BASED_RO, QB_IPC_SHM, + ro_cb); - *ipcs_shm = mainloop_add_ipc_server(PCMK__SERVER_BASED_SHM, - QB_IPC_SHM, rw_cb); + *ipcs_rw = mainloop_add_ipc_server(PCMK__SERVER_BASED_RW, QB_IPC_SHM, + rw_cb); - if (*ipcs_ro == NULL || *ipcs_rw == NULL || *ipcs_shm == NULL) { + if ((*ipcs_ro == NULL) || (*ipcs_rw == NULL)) { pcmk__crit("Failed to create %s IPC server; shutting down", pcmk__server_log_name(pcmk_ipc_based)); pcmk__crit("Verify pacemaker and pacemaker_remote are not both " @@ -1053,27 +1049,6 @@ void pcmk__serve_based_ipc(qb_ipcs_service_t **ipcs_ro, } } -/*! - * \internal - * \brief Destroy IPC servers for the CIB manager API - * - * \param[out] ipcs_ro IPC server for read-only the CIB manager API - * \param[out] ipcs_rw IPC server for read/write the CIB manager API - * \param[out] ipcs_shm IPC server for shared-memory the CIB manager API - * - * \note This is a convenience function for calling qb_ipcs_destroy() for each - * argument. - */ -void -pcmk__stop_based_ipc(qb_ipcs_service_t *ipcs_ro, - qb_ipcs_service_t *ipcs_rw, - qb_ipcs_service_t *ipcs_shm) -{ - qb_ipcs_destroy(ipcs_ro); - qb_ipcs_destroy(ipcs_rw); - qb_ipcs_destroy(ipcs_shm); -} - /*! * \internal * \brief Add an IPC server to the main loop for the controller API @@ -1085,7 +1060,9 @@ pcmk__stop_based_ipc(qb_ipcs_service_t *ipcs_ro, qb_ipcs_service_t * pcmk__serve_controld_ipc(struct qb_ipcs_service_handlers *cb) { - return mainloop_add_ipc_server(CRM_SYSTEM_CRMD, QB_IPC_NATIVE, cb); + pcmk__assert(cb != NULL); + + return mainloop_add_ipc_server(CRM_SYSTEM_CRMD, QB_IPC_SHM, cb); } /*! @@ -1101,8 +1078,10 @@ void pcmk__serve_attrd_ipc(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb) { + pcmk__assert((ipcs != NULL) && (*ipcs == NULL) && (cb != NULL)); + *ipcs = mainloop_add_ipc_server(pcmk__server_ipc_name(pcmk_ipc_attrd), - QB_IPC_NATIVE, cb); + QB_IPC_SHM, cb); if (*ipcs == NULL) { pcmk__crit("Failed to create %s IPC server; shutting down", @@ -1149,8 +1128,10 @@ void pcmk__serve_fenced_ipc(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb) { + pcmk__assert((ipcs != NULL) && (*ipcs == NULL) && (cb != NULL)); + *ipcs = mainloop_add_ipc_server_with_prio(pcmk__server_ipc_name(pcmk_ipc_fenced), - QB_IPC_NATIVE, cb, QB_LOOP_HIGH); + QB_IPC_SHM, cb, QB_LOOP_HIGH); if (*ipcs == NULL) { pcmk__crit("Failed to create %s IPC server; shutting down", @@ -1174,8 +1155,10 @@ void pcmk__serve_pacemakerd_ipc(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb) { + pcmk__assert((ipcs != NULL) && (*ipcs == NULL) && (cb != NULL)); + *ipcs = mainloop_add_ipc_server(pcmk__server_ipc_name(pcmk_ipc_pacemakerd), - QB_IPC_NATIVE, cb); + QB_IPC_SHM, cb); if (*ipcs == NULL) { pcmk__crit("Failed to create %s IPC server; shutting down", @@ -1205,8 +1188,10 @@ void pcmk__serve_schedulerd_ipc(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb) { + pcmk__assert((ipcs != NULL) && (*ipcs == NULL) && (cb != NULL)); + *ipcs = mainloop_add_ipc_server(pcmk__server_ipc_name(pcmk_ipc_schedulerd), - QB_IPC_NATIVE, cb); + QB_IPC_SHM, cb); if (*ipcs == NULL) { pcmk__crit("Failed to create %s IPC server; shutting down", diff --git a/lib/common/mainloop.c b/lib/common/mainloop.c index 530175cfe16..ca650284a95 100644 --- a/lib/common/mainloop.c +++ b/lib/common/mainloop.c @@ -29,7 +29,6 @@ struct trigger_s { gboolean trigger; void *user_data; unsigned int id; - }; struct mainloop_timer_s { @@ -41,6 +40,21 @@ struct mainloop_timer_s { void *userdata; }; +static GHashTable *mainloop_children = NULL; +static qb_array_t *gio_map = NULL; + +static void +child_free(mainloop_child_t *child) +{ + if (child->timerid != 0) { + pcmk__trace("Removing timer %d", child->timerid); + g_source_remove(child->timerid); + child->timerid = 0; + } + free(child->desc); + free(child); +} + static gboolean crm_trigger_prepare(GSource *source, int *timeout) { @@ -335,6 +349,8 @@ mainloop_destroy_signal_entry(int sig) * \note The true signal handler merely sets a mainloop trigger to call this * dispatch function via the mainloop. Therefore, the dispatch function * does not need to be async-safe. + * \note The added signal handler gets freed by \c mainloop_cleanup() if it is + * not freed manually using \c mainloop_destroy_signal(). */ gboolean mainloop_add_signal(int sig, void (*dispatch) (int sig)) @@ -398,11 +414,16 @@ mainloop_destroy_signal(int sig) return TRUE; } -static qb_array_t *gio_map = NULL; - +/*! + * \internal + * \brief Free data structures used for the mainloop + * + * \todo This is incomplete. Free other data structures created in this file. + */ void mainloop_cleanup(void) { + g_clear_pointer(&mainloop_children, g_hash_table_destroy); g_clear_pointer(&gio_map, qb_array_free); for (int sig = 0; sig < NSIG; ++sig) { @@ -592,31 +613,6 @@ struct qb_ipcs_poll_handlers gio_poll_funcs = { .dispatch_del = gio_poll_dispatch_del, }; -static enum qb_ipc_type -pick_ipc_type(enum qb_ipc_type requested) -{ - const char *env = pcmk__env_option(PCMK__ENV_IPC_TYPE); - - if (env && strcmp("shared-mem", env) == 0) { - return QB_IPC_SHM; - } else if (env && strcmp("socket", env) == 0) { - return QB_IPC_SOCKET; - } else if (env && strcmp("posix", env) == 0) { - return QB_IPC_POSIX_MQ; - } else if (env && strcmp("sysv", env) == 0) { - return QB_IPC_SYSV_MQ; - } else if (requested == QB_IPC_NATIVE) { - /* We prefer shared memory because the server never blocks on - * send. If part of a message fits into the socket, libqb - * needs to block until the remainder can be sent also. - * Otherwise the client will wait forever for the remaining - * bytes. - */ - return QB_IPC_SHM; - } - return requested; -} - qb_ipcs_service_t * mainloop_add_ipc_server(const char *name, enum qb_ipc_type type, struct qb_ipcs_service_handlers *callbacks) @@ -636,7 +632,7 @@ mainloop_add_ipc_server_with_prio(const char *name, enum qb_ipc_type type, gio_map = qb_array_create_2(64, sizeof(struct gio_to_qb_poll), 1); } - server = qb_ipcs_create(name, 0, pick_ipc_type(type), callbacks); + server = qb_ipcs_create(name, 0, QB_IPC_NATIVE, callbacks); if (server == NULL) { pcmk__err("Could not create %s IPC server: %s (%d)", name, @@ -670,20 +666,6 @@ mainloop_del_ipc_server(qb_ipcs_service_t * server) } } -struct mainloop_io_s { - char *name; - void *userdata; - - int fd; - unsigned int source; - crm_ipc_t *ipc; - GIOChannel *channel; - - int (*dispatch_fn_ipc)(const char *buffer, ssize_t length, void *userdata); - int (*dispatch_fn_io)(void *userdata); - void (*destroy_fn)(void *userdata); -}; - /*! * \internal * \brief I/O watch callback function (GIOFunc) @@ -1006,8 +988,6 @@ mainloop_del_fd(mainloop_io_t *client) g_source_remove(client->source); } -static GList *child_list = NULL; - pid_t mainloop_child_pid(mainloop_child_t * child) { @@ -1038,48 +1018,41 @@ mainloop_clear_child_userdata(mainloop_child_t * child) child->privatedata = NULL; } -/* good function name */ -static void -child_free(mainloop_child_t *child) -{ - if (child->timerid != 0) { - pcmk__trace("Removing timer %d", child->timerid); - g_source_remove(child->timerid); - child->timerid = 0; - } - free(child->desc); - free(child); -} - -/* terrible function name */ static int -child_kill_helper(mainloop_child_t *child) +child_kill_helper(const mainloop_child_t *child) { - int rc; - if (child->flags & mainloop_leave_pid_group) { + int rc = 0; + + if (pcmk__is_set(child->flags, mainloop_leave_pid_group)) { pcmk__debug("Killing PID %lld only. Leaving its process group intact.", (long long) child->pid); rc = kill(child->pid, SIGKILL); + } else { pcmk__debug("Killing PID %lld's entire process group", (long long) child->pid); rc = kill(-child->pid, SIGKILL); } - if (rc < 0) { - if (errno != ESRCH) { - pcmk__err("kill(%d, KILL) failed: %s", child->pid, strerror(errno)); - } - return -errno; + if (rc == 0) { + return pcmk_rc_ok; } - return 0; + + rc = errno; + if (rc == ESRCH) { + return rc; + } + + pcmk__err("kill(%lld, KILL) failed: %s", (long long) child->pid, + strerror(rc)); + return rc; } static gboolean child_timeout_callback(void *p) { mainloop_child_t *child = p; - int rc = 0; + int rc = pcmk_rc_ok; child->timerid = 0; if (child->timeout) { @@ -1089,7 +1062,7 @@ child_timeout_callback(void *p) } rc = child_kill_helper(child); - if (rc == -ESRCH) { + if (rc == ESRCH) { /* Nothing left to do. pid doesn't exist */ return FALSE; } @@ -1110,15 +1083,16 @@ child_waitpid(mainloop_child_t *child, int flags) int signo = 0; int status = 0; int exitcode = 0; - bool callback_needed = true; rc = waitpid(child->pid, &status, flags); + if (rc == 0) { // WNOHANG in flags, and child status is not available pcmk__trace("Child process %lld (%s) still active", (long long) child->pid, child->desc); - callback_needed = false; + return false; + } - } else if (rc != child->pid) { + if (rc != child->pid) { /* According to POSIX, possible conditions: * - child->pid was non-positive (process group or any child), * and rc is specific child @@ -1130,8 +1104,8 @@ child_waitpid(mainloop_child_t *child, int flags) */ signo = SIGCHLD; exitcode = 1; - pcmk__notice("Wait for child process %d (%s) interrupted: %s", - child->pid, child->desc, pcmk_rc_str(errno)); + pcmk__notice("Wait for child process %lld (%s) interrupted: %s", + (long long) child->pid, child->desc, strerror(errno)); } else if (WIFEXITED(status)) { exitcode = WEXITSTATUS(status); @@ -1147,37 +1121,45 @@ child_waitpid(mainloop_child_t *child, int flags) #ifdef WCOREDUMP // AIX, SunOS, maybe others } else if (WCOREDUMP(status)) { core = 1; - pcmk__err("Child process %d (%s) dumped core", child->pid, child->desc); + pcmk__err("Child process %lld (%s) dumped core", (long long) child->pid, + child->desc); #endif } else { // flags must contain WUNTRACED and/or WCONTINUED to reach this pcmk__trace("Child process %lld (%s) stopped or continued", (long long) child->pid, child->desc); - callback_needed = false; + return false; } - if (callback_needed && child->exit_fn) { + if (child->exit_fn != NULL) { child->exit_fn(child, core, signo, exitcode); } - return callback_needed; + + return true; +} + +static gboolean +child_waitpid_no_hang(void *key, void *value, void *user_data) +{ + mainloop_child_t *child = value; + + if (!child_waitpid(child, WNOHANG)) { + return FALSE; + } + + pcmk__trace("Removing completed process %lld from child table", + (long long) child->pid); + return TRUE; } static void child_death_dispatch(int signal) { - for (GList *iter = child_list; iter; ) { - GList *saved = iter; - mainloop_child_t *child = iter->data; - - iter = iter->next; - if (child_waitpid(child, WNOHANG)) { - pcmk__trace("Removing completed process %lld from child list", - (long long) child->pid); - child_list = g_list_remove_link(child_list, saved); - g_list_free(saved); - child_free(child); - } + if (mainloop_children == NULL) { + return; } + + g_hash_table_foreach_remove(mainloop_children, child_waitpid_no_hang, NULL); } static gboolean @@ -1195,55 +1177,79 @@ child_signal_init(void *p) gboolean mainloop_child_kill(pid_t pid) { - GList *iter; + /* It is impossible to block SIGKILL. This allows us to call waitpid() + * without the WNOHANG flag. + */ + int waitflags = 0; + int rc = pcmk_rc_ok; + char *pid_s = NULL; mainloop_child_t *child = NULL; - mainloop_child_t *match = NULL; - /* It is impossible to block SIGKILL, this allows us to - * call waitpid without WNOHANG flag.*/ - int waitflags = 0, rc = 0; - - for (iter = child_list; iter != NULL && match == NULL; iter = iter->next) { - child = iter->data; - if (pid == child->pid) { - match = child; - } + gboolean killed = FALSE; + + if (mainloop_children == NULL) { + // We're not tracking any children, so don't kill this PID + goto done; } - if (match == NULL) { - return FALSE; + pid_s = pcmk__assert_asprintf("%lld", (long long) pid); + child = g_hash_table_lookup(mainloop_children, pid_s); + + if (child == NULL) { + // We're not tracking a child with this PID, so don't kill it + goto done; } - rc = child_kill_helper(match); - if(rc == -ESRCH) { - /* It's gone, but hasn't shown up in waitpid() yet. Wait until we get - * SIGCHLD and let handler clean it up as normal (so we get the correct - * return code/status). The blocking alternative would be to call - * child_waitpid(match, 0). + rc = child_kill_helper(child); + if (rc == ESRCH) { + /* kill() didn't find the PID. Assume this means the process is in some + * intermediate stage of exiting. Wait until we get SIGCHLD and let + * the handler clean it up as normal, so that we get the correct return + * code/status. The blocking alternative would be to call + * child_waitpid(child, 0). + * + * Treat this as success in the meantime. */ pcmk__trace("Waiting for signal that child process %lld completed", - (long long) match->pid); - return TRUE; + (long long) child->pid); + killed = TRUE; + goto done; + } - } else if(rc != 0) { - /* If KILL for some other reason set the WNOHANG flag since we - * can't be certain what happened. + if (rc != pcmk_rc_ok) { + /* If kill() failed for some other reason, set the WNOHANG flag, since + * we can't be certain what happened. */ waitflags = WNOHANG; } - if (!child_waitpid(match, waitflags)) { - /* not much we can do if this occurs */ - return FALSE; + if (!child_waitpid(child, waitflags)) { + /* waitpid() didn't find the child. This shouldn't happen if kill() + * succeeded. In any case, there's no obviously good way to proceed. + * Treat this as a failure. + * + * @TODO Should we call the child's exit_fn with a failure here, and/or + * free the mainloop_child_t? We can hope that we successfully wait on + * it in response to a SIGCHLD that comes later. But we might just never + * do anything with this child again. + * + * @TODO Consider using GSubprocess for all subprocess tracking. + */ + goto done; } - child_list = g_list_remove(child_list, match); - child_free(match); - return TRUE; + g_hash_table_remove(mainloop_children, pid_s); + killed = TRUE; + +done: + free(pid_s); + return killed; } /* Create/Log a new tracked process * To track a process group, use -pid * + * Newly created child will be freed by mainloop_cleanup(), if not sooner. + * * @TODO Using a non-positive pid (i.e. any child, or process group) would * likely not be useful since we will free the child after the first * completed process. @@ -1255,6 +1261,7 @@ mainloop_child_add_with_flags(pid_t pid, int timeout, const char *desc, pcmk__mainloop_child_exit_fn_t exit_fn) { static bool need_init = TRUE; + bool is_new = false; mainloop_child_t *child = pcmk__assert_alloc(1, sizeof(mainloop_child_t)); child->pid = pid; @@ -1269,7 +1276,17 @@ mainloop_child_add_with_flags(pid_t pid, int timeout, const char *desc, child->timerid = pcmk__create_timer(timeout, child_timeout_callback, child); } - child_list = g_list_append(child_list, child); + if (mainloop_children == NULL) { + mainloop_children = pcmk__strkey_table(free, + (GDestroyNotify) child_free); + } + + is_new = g_hash_table_insert(mainloop_children, + pcmk__assert_asprintf("%lld", (long long) pid), + child); + + // It should be impossible to have this PID in mainloop_children already + CRM_LOG_ASSERT(is_new); if(need_init) { need_init = FALSE; @@ -1281,6 +1298,7 @@ mainloop_child_add_with_flags(pid_t pid, int timeout, const char *desc, } } +// Newly created child will be freed by mainloop_cleanup(), if not sooner void mainloop_child_add(pid_t pid, int timeout, const char *desc, void *privatedata, pcmk__mainloop_child_exit_fn_t exit_fn) diff --git a/lib/common/servers.c b/lib/common/servers.c index f2e6d79ef50..6a4fdc7405b 100644 --- a/lib/common/servers.c +++ b/lib/common/servers.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 the Pacemaker project contributors + * Copyright 2024-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -33,63 +33,62 @@ static struct { const char *log_name; // Readable server name for use in logs const char *system_names[2]; // crm_system_name values (subdaemon names) - const char *ipc_names[3]; // libqb IPC names used to contact server + const char *ipc_names[2]; // libqb IPC names used to contact server const char *message_types[3]; // IPC/cluster message types sent to server } server_info[] = { [pcmk_ipc_unknown] = { NULL, { NULL, NULL, }, - { NULL, NULL, NULL, }, + { NULL, NULL, }, { NULL, NULL, NULL, }, }, [pcmk_ipc_attrd] = { "attribute manager", { PCMK__SERVER_ATTRD, NULL, }, - { PCMK__VALUE_ATTRD, NULL, NULL, }, + { PCMK__VALUE_ATTRD, NULL, }, { PCMK__VALUE_ATTRD, NULL, NULL, }, }, [pcmk_ipc_based] = { "CIB manager", { PCMK__SERVER_BASED, NULL, }, - { PCMK__SERVER_BASED_RW, PCMK__SERVER_BASED_RO, - PCMK__SERVER_BASED_SHM, }, + { PCMK__SERVER_BASED_RW, PCMK__SERVER_BASED_RO, }, { CRM_SYSTEM_CIB, NULL, NULL, }, }, [pcmk_ipc_controld] = { "controller", { PCMK__SERVER_CONTROLD, NULL, }, - { PCMK__VALUE_CRMD, NULL, NULL, }, + { PCMK__VALUE_CRMD, NULL, }, { PCMK__VALUE_CRMD, CRM_SYSTEM_DC, CRM_SYSTEM_TENGINE, }, }, [pcmk_ipc_execd] = { "executor", { PCMK__SERVER_EXECD, PCMK__SERVER_REMOTED, }, - { PCMK__VALUE_LRMD, NULL, NULL, }, + { PCMK__VALUE_LRMD, NULL, }, { PCMK__VALUE_LRMD, NULL, NULL, }, }, [pcmk_ipc_fenced] = { "fencer", { PCMK__SERVER_FENCED, NULL, }, - { PCMK__VALUE_STONITH_NG, NULL, NULL, }, + { PCMK__VALUE_STONITH_NG, NULL, }, { PCMK__VALUE_STONITH_NG, NULL, NULL, }, }, [pcmk_ipc_pacemakerd] = { "launcher", { PCMK__SERVER_PACEMAKERD, NULL, }, - { CRM_SYSTEM_MCP, NULL, NULL, }, + { CRM_SYSTEM_MCP, NULL, }, { CRM_SYSTEM_MCP, NULL, NULL, }, }, [pcmk_ipc_schedulerd] = { "scheduler", { PCMK__SERVER_SCHEDULERD, NULL, }, - { CRM_SYSTEM_PENGINE, NULL, NULL, }, + { CRM_SYSTEM_PENGINE, NULL, }, { CRM_SYSTEM_PENGINE, NULL, NULL, }, }, }; @@ -193,7 +192,7 @@ pcmk__parse_server(const char *text) } } for (name = 0; - (name < 3) && (server_info[server].ipc_names[name] != NULL); + (name < 2) && (server_info[server].ipc_names[name] != NULL); ++name) { if (strcmp(text, server_info[server].ipc_names[name]) == 0) { return server;