]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: mworker: can't use signals after a failed reload
authorWilliam Lallemand <wlallemand@haproxy.com>
Tue, 6 Jan 2026 12:59:41 +0000 (13:59 +0100)
committerWilliam Lallemand <wlallemand@haproxy.com>
Tue, 6 Jan 2026 13:27:53 +0000 (14:27 +0100)
In issue #3229 it was reported that the master couldn't reload after a
failed reload following a wrong configuration.

It is still possible to do a reload using the "reload" command of the
master CLI. But every signals are blocked.

The problem was introduced in 709cde6d0 ("BUG/MEDIUM: mworker: signals
inconsistencies during startup and reload") which fixes the blocking of
signals during the reload.

However the patch missed a case, indeed, the
run_master_in_recovery_mode() is not being called when the worker failed
to parse the configuration, it is only failing when the master is
failing.

To handle this case, the mworker_unblock_signals() function must be
called upon mworker_on_new_child_failure(). But since this is called in
an haproxy signal handler it would mess with the signals.

Instead, the patch adds a task which is started by the signal handler,
and restores the signals outside of it.

This must be backported as far as 3.1.

src/mworker.c

index cdf9a9332c26ab36ac44622061f63d257519655f..956ffc041df3625d86a3ff7feaab230603b710f2 100644 (file)
@@ -508,6 +508,14 @@ void mworker_catch_sigterm(struct sig_handler *sh)
        mworker_kill(sig);
 }
 
+/* handle operations that can't be done in the signal handler */
+static struct task *mworker_task_child_failure(struct task *task, void *context, unsigned int state)
+{
+       mworker_unblock_signals();
+       task_destroy(task);
+       return NULL;
+}
+
 /*
  * Performs some routines for the worker process, which has failed the reload,
  * updates the global load_status.
@@ -515,6 +523,7 @@ void mworker_catch_sigterm(struct sig_handler *sh)
 static void mworker_on_new_child_failure(int exitpid, int status)
 {
        struct mworker_proc *child;
+       struct task *t;
 
        /* increment the number of failed reloads */
        list_for_each_entry(child, &proc_list, list) {
@@ -531,6 +540,15 @@ static void mworker_on_new_child_failure(int exitpid, int status)
         * the READY=1 signal still need to be sent */
        if (global.tune.options & GTUNE_USE_SYSTEMD)
                sd_notify(0, "READY=1\nSTATUS=Reload failed!\n");
+
+       /* call a task to unblock the signals from outside the sig handler */
+       if ((t = task_new_here()) == NULL) {
+               ha_warning("Can't restore HAProxy signals!\n");
+               return;
+       }
+
+       t->process = mworker_task_child_failure;
+       task_wakeup(t, TASK_WOKEN_MSG);
 }
 
 /*