core: Check unit start rate limiting earlier

Fixes #17433. Currently, if any of the validations we do before we
check start rate limiting fail, we can still enter a busy loop as
no rate limiting gets applied. A common occurence of this scenario
is path units triggering a service that fails a condition check.

To fix the issue, we simply move up start rate limiting checks to
be the first thing we do when starting a unit. To achieve this,
we add a new method to the unit vtable and implement it for the
relevant unit types so that we can do the start rate limit checks
earlier on.
This commit is contained in:
Daan De Meyer
2021-08-25 13:26:14 +01:00
parent a243128d1f
commit 9727f2427f
16 changed files with 169 additions and 43 deletions
+1
View File
@@ -0,0 +1 @@
../TEST-01-BASIC/Makefile
+9
View File
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
set -e
TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/17433"
# shellcheck source=test/test-functions
. "${TEST_BASE_DIR:?}/test-functions"
do_test "$@"
+2
View File
@@ -33,6 +33,8 @@ if install_tests
install_dir : testdata_dir)
install_subdir('testsuite-52.units',
install_dir : testdata_dir)
install_subdir('testsuite-63.units',
install_dir : testdata_dir)
testsuite08_dir = testdata_dir + '/testsuite-08.units'
install_data('testsuite-08.units/-.mount',
+3
View File
@@ -1,6 +1,9 @@
[Unit]
Requires=test10.socket
ConditionPathExistsGlob=/tmp/nonexistent
# Make sure we hit the socket trigger limit in the test and not the service start limit.
StartLimitInterval=1000
StartLimitBurst=1000
[Service]
ExecStart=true
+2
View File
@@ -0,0 +1,2 @@
[Path]
PathExists=/tmp/test63
+5
View File
@@ -0,0 +1,5 @@
[Unit]
ConditionPathExists=!/tmp/nonexistent
[Service]
ExecStart=true
+16
View File
@@ -0,0 +1,16 @@
[Unit]
Description=TEST-63-ISSUE-17433
[Service]
ExecStartPre=rm -f /failed /testok
Type=oneshot
ExecStart=rm -f /tmp/nonexistent
ExecStart=systemctl start test63.path
ExecStart=touch /tmp/test63
# Make sure systemd has sufficient time to hit the start limit for test63.service.
ExecStart=sleep 2
ExecStart=sh -x -c 'test "$(systemctl show test63.service -P ActiveState)" = failed'
ExecStart=sh -x -c 'test "$(systemctl show test63.service -P Result)" = start-limit-hit'
ExecStart=sh -x -c 'test "$(systemctl show test63.path -P ActiveState)" = failed'
ExecStart=sh -x -c 'test "$(systemctl show test63.path -P Result)" = unit-start-limit-hit'
ExecStart=sh -x -c 'echo OK >/testok'