From bbe19f68846bb3cd5fcf3e4f612268064df53b53 Mon Sep 17 00:00:00 2001 From: Peter Morrow Date: Tue, 13 Apr 2021 17:20:42 +0100 Subject: [PATCH 1/2] core: allow services stuck in reloading state to exit If a service is in reloading state but has exited do not delay the final exit until the service reload timer expires. Instead allow the service to exit immediately since we can't expect the service to ever transition out of reloading state. For example if a service sent RELOADING=1 but crashed before it could send READY=1 then it should be restarted if the service had Restart= configured. Signed-off-by: Peter Morrow --- src/core/service.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/core/service.c b/src/core/service.c index fb97bbeaae..d5f79d274e 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -3474,6 +3474,15 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { case SERVICE_START_POST: case SERVICE_RELOAD: + /* If neither main nor control processes are running then + * the current state can never exit cleanly, hence immediately + * terminate the service. */ + if (control_pid_good(s) <= 0) + service_enter_stop(s, f); + + /* Otherwise need to wait untill the operation is done. */ + break; + case SERVICE_STOP: /* Need to wait until the operation is * done */ From f209d8f50c7412bf70c35033dd97277e5df53e19 Mon Sep 17 00:00:00 2001 From: Peter Morrow Date: Tue, 13 Apr 2021 17:22:52 +0100 Subject: [PATCH 2/2] test: add a test to cover restarting services in reloading state Cover the case where a service is recovered out of reloading state via a restart Restart= configuration. Signed-off-by: Peter Morrow --- test/TEST-59-RELOADING-RESTART/Makefile | 1 + test/TEST-59-RELOADING-RESTART/test.sh | 9 +++ test/units/testsuite-59.service | 6 ++ test/units/testsuite-59.sh | 90 +++++++++++++++++++++++++ 4 files changed, 106 insertions(+) create mode 120000 test/TEST-59-RELOADING-RESTART/Makefile create mode 100755 test/TEST-59-RELOADING-RESTART/test.sh create mode 100644 test/units/testsuite-59.service create mode 100755 test/units/testsuite-59.sh diff --git a/test/TEST-59-RELOADING-RESTART/Makefile b/test/TEST-59-RELOADING-RESTART/Makefile new file mode 120000 index 0000000000..e9f93b1104 --- /dev/null +++ b/test/TEST-59-RELOADING-RESTART/Makefile @@ -0,0 +1 @@ +../TEST-01-BASIC/Makefile \ No newline at end of file diff --git a/test/TEST-59-RELOADING-RESTART/test.sh b/test/TEST-59-RELOADING-RESTART/test.sh new file mode 100755 index 0000000000..ad990963b8 --- /dev/null +++ b/test/TEST-59-RELOADING-RESTART/test.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -e +TEST_DESCRIPTION="Test auto restart of exited services which are stuck in reloading state" + +TEST_NO_QEMU=1 + +. $TEST_BASE_DIR/test-functions + +do_test "$@" 59 diff --git a/test/units/testsuite-59.service b/test/units/testsuite-59.service new file mode 100644 index 0000000000..66d06866c8 --- /dev/null +++ b/test/units/testsuite-59.service @@ -0,0 +1,6 @@ +[Unit] +Description=TEST-59-RELOADING-RESTART + +[Service] +Type=oneshot +ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh diff --git a/test/units/testsuite-59.sh b/test/units/testsuite-59.sh new file mode 100755 index 0000000000..459d6e6403 --- /dev/null +++ b/test/units/testsuite-59.sh @@ -0,0 +1,90 @@ +#!/usr/bin/env bash +set -eux +set -o pipefail + +fail () { + systemd-analyze log-level info + exit 1 +} + +# Wait for a service to enter a state within a timeout period, if it doesn't +# enter the desired state within the timeout period then this function will +# exit the test case with a non zero exit code. +wait_on_state_or_fail () { + service=$1 + expected_state=$2 + timeout=$3 + + state=$(systemctl show "$service" --property=ActiveState --value) + while [ "$state" != "$expected_state" ]; do + if [ "$timeout" = "0" ]; then + fail + fi + timeout=$((timeout - 1)) + sleep 1 + state=$(systemctl show "$service" --property=ActiveState --value) + done +} + +systemd-analyze log-level debug +systemd-analyze log-target console + + +cat >/run/systemd/system/testservice-fail-59.service </run/systemd/system/testservice-fail-restart-59.service </run/systemd/system/testservice-abort-restart-59.service </testok + +exit 0