From 39b828f6b769d28f67a53a5811d81e0c1b13a3e8 Mon Sep 17 00:00:00 2001 From: Yan Gao Date: Tue, 7 Jul 2026 18:39:00 +0200 Subject: [PATCH 1/4] Fix: controller: Check for watchdog-based self-fencing device only if "fencing-watchdog-timeout" is enabled With 14e9b3e1b5, stonith__watchdog_fencing_enabled_for_node_api() was called only if "stonith-watchdog-timeout" was enabled (non-zero). But with a4f2db39c8, the function is again always called even if the cluster option is not enabled, so that it again keeps logging the confusing notice "Cluster does not have watchdog fencing". This commit fixes the regression by anyway parsing the value of the cluster option first and avoiding calling stonith__watchdog_fencing_enabled_for_node_api() if the cluster option is not even enabled. --- daemons/controld/controld_fencing.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/daemons/controld/controld_fencing.c b/daemons/controld/controld_fencing.c index 281aa0f6fba..0f22ed02182 100644 --- a/daemons/controld/controld_fencing.c +++ b/daemons/controld/controld_fencing.c @@ -995,6 +995,16 @@ void controld_validate_fencing_watchdog_timeout(const char *value) { const char *our_nodename = controld_globals.cluster->priv->node_name; + long long timeout_ms = 0; + + if (value == NULL) { + return; + } + + if ((pcmk__parse_ms(value, &timeout_ms) == pcmk_rc_ok) + && (timeout_ms == 0)) { + return; + } // Validate only if the timeout will be used if ((fencer_api != NULL) && (fencer_api->state != stonith_disconnected) From a69067b6c066285f7f54cfc22a6c89030e0296dc Mon Sep 17 00:00:00 2001 From: Yan Gao Date: Wed, 8 Jul 2026 17:03:01 +0200 Subject: [PATCH 2/4] Fix: liblrmd: Check watchdog-based self-fencing device for remote nodes only if "fencing-watchdog-timeout" is enabled Previously, stonith__watchdog_fencing_enabled_for_node_api() was always called even when "fencing-watchdog-timeout" was disabled. This resulted in a constant, confusing log notice: "Cluster does not have watchdog fencing device". This commit fixes it by ensuring the watchdog-based self-fencing device for remote nodes is only checked when the cluster option is actually enabled. --- lib/lrmd/lrmd_client.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/lrmd/lrmd_client.c b/lib/lrmd/lrmd_client.c index ecaac78903a..6b9169c7fd5 100644 --- a/lib/lrmd/lrmd_client.c +++ b/lib/lrmd/lrmd_client.c @@ -1029,11 +1029,14 @@ lrmd__validate_remote_settings(lrmd_t *lrmd, GHashTable *hash) const char *value; lrmd_private_t *native = lrmd->lrmd_private; xmlNode *data = pcmk__xe_create(NULL, PCMK__XA_LRMD_OP); + long long timeout_ms = 0; pcmk__xe_set(data, PCMK__XA_LRMD_ORIGIN, __func__); value = pcmk__cluster_option(hash, PCMK_OPT_FENCING_WATCHDOG_TIMEOUT); if ((value) && + (pcmk__parse_ms(value, &timeout_ms) == pcmk_rc_ok) && + (timeout_ms != 0) && (stonith__watchdog_fencing_enabled_for_node(native->remote_nodename))) { pcmk__xe_set(data, PCMK__XA_LRMD_WATCHDOG, value); } From fb2c0268df9f7b6aee2fd63eadf19e07f84685cd Mon Sep 17 00:00:00 2001 From: Yan Gao Date: Wed, 8 Jul 2026 10:29:35 +0200 Subject: [PATCH 3/4] Refactor: libcrmcommon: Functionize parsing "fencing-watchdog-timeout" --- daemons/controld/controld_fencing.c | 10 +++------- daemons/execd/execd_messages.c | 4 +++- daemons/fenced/fenced_cib.c | 12 +----------- include/crm/common/options_internal.h | 3 ++- lib/common/watchdog.c | 24 ++++++++++++++---------- lib/lrmd/lrmd_client.c | 5 ++--- 6 files changed, 25 insertions(+), 33 deletions(-) diff --git a/daemons/controld/controld_fencing.c b/daemons/controld/controld_fencing.c index 0f22ed02182..7c50e2ebcd8 100644 --- a/daemons/controld/controld_fencing.c +++ b/daemons/controld/controld_fencing.c @@ -997,12 +997,8 @@ controld_validate_fencing_watchdog_timeout(const char *value) const char *our_nodename = controld_globals.cluster->priv->node_name; long long timeout_ms = 0; - if (value == NULL) { - return; - } - - if ((pcmk__parse_ms(value, &timeout_ms) == pcmk_rc_ok) - && (timeout_ms == 0)) { + timeout_ms = pcmk__parse_fencing_watchdog_timeout(value); + if (timeout_ms == 0) { return; } @@ -1011,7 +1007,7 @@ controld_validate_fencing_watchdog_timeout(const char *value) && stonith__watchdog_fencing_enabled_for_node_api(fencer_api, our_nodename)) { - pcmk__valid_fencing_watchdog_timeout(value); + pcmk__valid_fencing_watchdog_timeout(timeout_ms); } } diff --git a/daemons/execd/execd_messages.c b/daemons/execd/execd_messages.c index 52384cf79be..49b98401cfc 100644 --- a/daemons/execd/execd_messages.c +++ b/daemons/execd/execd_messages.c @@ -134,6 +134,7 @@ handle_check_request(pcmk__request_t *request) xmlNode *wrapper = NULL; xmlNode *data = NULL; const char *timeout = NULL; + long long timeout_ms = 0; if (!allowed) { pcmk__set_result(&request->result, CRM_EX_INSUFFICIENT_PRIV, @@ -158,7 +159,8 @@ handle_check_request(pcmk__request_t *request) /* FIXME: This just exits on certain conditions, which seems like a pretty * extreme reaction for a daemon to take. */ - pcmk__valid_fencing_watchdog_timeout(timeout); + timeout_ms = pcmk__parse_fencing_watchdog_timeout(timeout); + pcmk__valid_fencing_watchdog_timeout(timeout_ms); pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL); return NULL; diff --git a/daemons/fenced/fenced_cib.c b/daemons/fenced/fenced_cib.c index 803cad11e33..4b62db1e2e0 100644 --- a/daemons/fenced/fenced_cib.c +++ b/daemons/fenced/fenced_cib.c @@ -159,8 +159,6 @@ get_fencing_watchdog_timeout(xmlNode *cib) { xmlNode *stonith_watchdog_xml = NULL; const char *value = NULL; - int rc = pcmk_rc_ok; - long long timeout_ms = 0; // @TODO An XPath search can't handle multiple instances or rules stonith_watchdog_xml = pcmk__xpath_find_one(cib->doc, @@ -182,16 +180,8 @@ get_fencing_watchdog_timeout(xmlNode *cib) } value = pcmk__xe_get(stonith_watchdog_xml, PCMK_XA_VALUE); - if (value == NULL) { - return 0; - } - - rc = pcmk__parse_ms(value, &timeout_ms); - if ((rc == pcmk_rc_ok) && (timeout_ms >= 0)) { - return timeout_ms; - } - return pcmk__auto_fencing_watchdog_timeout(); + return pcmk__parse_fencing_watchdog_timeout(value);; } /*! diff --git a/include/crm/common/options_internal.h b/include/crm/common/options_internal.h index 22b8e303a21..bf3f3676a73 100644 --- a/include/crm/common/options_internal.h +++ b/include/crm/common/options_internal.h @@ -134,7 +134,8 @@ bool pcmk__valid_placement_strategy(const char *value); long pcmk__get_sbd_watchdog_timeout(void); bool pcmk__get_sbd_sync_resource_startup(void); long pcmk__auto_fencing_watchdog_timeout(void); -bool pcmk__valid_fencing_watchdog_timeout(const char *value); +long long pcmk__parse_fencing_watchdog_timeout(const char *value); +bool pcmk__valid_fencing_watchdog_timeout(long long st_timeout); // @COMPAT Deprecated cluster options #define PCMK__OPT_CANCEL_REMOVED_ACTIONS "cancel-removed-actions" diff --git a/lib/common/watchdog.c b/lib/common/watchdog.c index 7ae02b1933d..21bbc154b60 100644 --- a/lib/common/watchdog.c +++ b/lib/common/watchdog.c @@ -271,8 +271,8 @@ pcmk__auto_fencing_watchdog_timeout(void) return (long) QB_MIN(st_timeout, LONG_MAX); } -bool -pcmk__valid_fencing_watchdog_timeout(const char *value) +long long +pcmk__parse_fencing_watchdog_timeout(const char *value) { /* @COMPAT At a compatibility break, accept either negative values or a * specific string like "auto" (but not both) to mean "auto-calculate the @@ -293,15 +293,20 @@ pcmk__valid_fencing_watchdog_timeout(const char *value) st_timeout, value); } + return st_timeout; +} + +bool +pcmk__valid_fencing_watchdog_timeout(long long st_timeout) +{ if (st_timeout == 0) { pcmk__debug("Watchdog may be enabled but " - PCMK_OPT_FENCING_WATCHDOG_TIMEOUT " is disabled (%s)", - pcmk__s(value, "default")); + PCMK_OPT_FENCING_WATCHDOG_TIMEOUT " is disabled (%lldms)", + st_timeout); } else if (pcmk__locate_sbd() == 0) { pcmk__emerg("Shutting down: " PCMK_OPT_FENCING_WATCHDOG_TIMEOUT - " configured (%s) but SBD not active", - pcmk__s(value, "auto")); + " configured (%lldms) but SBD not active", st_timeout); crm_exit(CRM_EX_FATAL); return false; @@ -313,14 +318,13 @@ pcmk__valid_fencing_watchdog_timeout(const char *value) * parsable, positive, and less than the SBD_WATCHDOG_TIMEOUT */ pcmk__emerg("Shutting down: " PCMK_OPT_FENCING_WATCHDOG_TIMEOUT - " (%s) too short (must be >%ldms)", - value, sbd_timeout); + " (%lldms) too short (must be >%ldms)", + st_timeout, sbd_timeout); crm_exit(CRM_EX_FATAL); return false; } pcmk__info("Watchdog configured with " PCMK_OPT_FENCING_WATCHDOG_TIMEOUT - " %s and SBD timeout %ldms", - value, sbd_timeout); + " %lldms and SBD timeout %ldms", st_timeout, sbd_timeout); } return true; } diff --git a/lib/lrmd/lrmd_client.c b/lib/lrmd/lrmd_client.c index 6b9169c7fd5..6eb9bfd873a 100644 --- a/lib/lrmd/lrmd_client.c +++ b/lib/lrmd/lrmd_client.c @@ -1034,9 +1034,8 @@ lrmd__validate_remote_settings(lrmd_t *lrmd, GHashTable *hash) pcmk__xe_set(data, PCMK__XA_LRMD_ORIGIN, __func__); value = pcmk__cluster_option(hash, PCMK_OPT_FENCING_WATCHDOG_TIMEOUT); - if ((value) && - (pcmk__parse_ms(value, &timeout_ms) == pcmk_rc_ok) && - (timeout_ms != 0) && + timeout_ms = pcmk__parse_fencing_watchdog_timeout(value); + if ((timeout_ms != 0) && (stonith__watchdog_fencing_enabled_for_node(native->remote_nodename))) { pcmk__xe_set(data, PCMK__XA_LRMD_WATCHDOG, value); } From 78301d50c348070731efeb19c13d59ece8630440 Mon Sep 17 00:00:00 2001 From: Yan Gao Date: Wed, 8 Jul 2026 10:49:08 +0200 Subject: [PATCH 4/4] Refactor: libcrmcommon: Make pcmk__auto_fencing_watchdog_timeout() static Now it's only used within the file. --- include/crm/common/options_internal.h | 1 - lib/common/watchdog.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/include/crm/common/options_internal.h b/include/crm/common/options_internal.h index bf3f3676a73..3a97b4dcc69 100644 --- a/include/crm/common/options_internal.h +++ b/include/crm/common/options_internal.h @@ -133,7 +133,6 @@ bool pcmk__valid_placement_strategy(const char *value); // from watchdog.c long pcmk__get_sbd_watchdog_timeout(void); bool pcmk__get_sbd_sync_resource_startup(void); -long pcmk__auto_fencing_watchdog_timeout(void); long long pcmk__parse_fencing_watchdog_timeout(const char *value); bool pcmk__valid_fencing_watchdog_timeout(long long st_timeout); diff --git a/lib/common/watchdog.c b/lib/common/watchdog.c index 21bbc154b60..4c00b8de6b1 100644 --- a/lib/common/watchdog.c +++ b/lib/common/watchdog.c @@ -262,7 +262,7 @@ pcmk__get_sbd_sync_resource_startup(void) } // 0 <= return value <= min(LONG_MAX, (2 * SBD timeout)) -long +static long pcmk__auto_fencing_watchdog_timeout(void) { long sbd_timeout = pcmk__get_sbd_watchdog_timeout();