backport: sync patches from systemd community; Fix compilation failure with - O0 option

(cherry picked from commit 112d69b7c80bafc341b94dbc98d8efd8c288f7a3)
This commit is contained in:
wangyuhang 2023-08-15 15:15:02 +08:00 committed by openeuler-sync-bot
parent 186cf19a70
commit 5304d4b4cc
14 changed files with 1588 additions and 7 deletions

View File

@ -0,0 +1,128 @@
From aaae822b37aa3ca39aebb516fdc6bef36d730c25 Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Fri, 17 Dec 2021 20:01:31 +0100
Subject: [PATCH] core: Add trigger limit for path units
When conditions fail on a service unit, a path unit can cause
PID 1 to busy loop as it keeps trying to activate the service unit.
To avoid this from happening, add a trigger limit to the path unit,
identical to the trigger limit we have for socket units.
Initially, let's start with a high limit and not make it configurable.
If needed, we can add properties to configure the rate limit similar
to the ones we have for socket units.
Conflict:code context adaptation
Reference:https://github.com/systemd/systemd-stable/commit/aaae822b37aa3ca39aebb516fdc6bef36d730c25
---
src/core/path.c | 10 ++++++++++
src/core/path.h | 3 +++
test/testsuite-63.units/test63.service | 2 +-
test/units/testsuite-63.service | 21 +++++++++++++++++----
4 files changed, 31 insertions(+), 5 deletions(-)
diff --git a/src/core/path.c b/src/core/path.c
index 1b0f115dd8..f89e35a001 100644
--- a/src/core/path.c
+++ b/src/core/path.c
@@ -265,6 +265,9 @@ static void path_init(Unit *u) {
assert(u->load_state == UNIT_STUB);
p->directory_mode = 0755;
+
+ p->trigger_limit.interval = 2 * USEC_PER_SEC;
+ p->trigger_limit.burst = 200;
}
void path_free_specs(Path *p) {
@@ -494,6 +497,12 @@ static void path_enter_running(Path *p) {
if (unit_stop_pending(UNIT(p)))
return;
+ if (!ratelimit_below(&p->trigger_limit)) {
+ log_unit_warning(UNIT(p), "Trigger limit hit, refusing further activation.");
+ path_enter_dead(p, PATH_FAILURE_TRIGGER_LIMIT_HIT);
+ return;
+ }
+
trigger = UNIT_TRIGGER(UNIT(p));
if (!trigger) {
log_unit_error(UNIT(p), "Unit to trigger vanished.");
@@ -836,6 +845,7 @@ static const char* const path_result_table[_PATH_RESULT_MAX] = {
[PATH_FAILURE_RESOURCES] = "resources",
[PATH_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
[PATH_FAILURE_UNIT_START_LIMIT_HIT] = "unit-start-limit-hit",
+ [PATH_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit",
};
DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult);
diff --git a/src/core/path.h b/src/core/path.h
index 66ae857dc4..d835c24166 100644
--- a/src/core/path.h
+++ b/src/core/path.h
@@ -46,6 +46,7 @@ typedef enum PathResult {
PATH_FAILURE_RESOURCES,
PATH_FAILURE_START_LIMIT_HIT,
PATH_FAILURE_UNIT_START_LIMIT_HIT,
+ PATH_FAILURE_TRIGGER_LIMIT_HIT,
_PATH_RESULT_MAX,
_PATH_RESULT_INVALID = -EINVAL,
} PathResult;
@@ -61,6 +62,8 @@ struct Path {
mode_t directory_mode;
PathResult result;
+
+ RateLimit trigger_limit;
};
void path_free_specs(Path *p);
diff --git a/test/testsuite-63.units/test63.service b/test/testsuite-63.units/test63.service
index c838018..6292434 100644
--- a/test/testsuite-63.units/test63.service
+++ b/test/testsuite-63.units/test63.service
@@ -1,5 +1,5 @@
[Unit]
-ConditionPathExists=!/tmp/nonexistent
+ConditionPathExists=/tmp/nonexistent
[Service]
ExecStart=true
diff --git a/test/units/testsuite-63.service b/test/units/testsuite-63.service
index 0a8d143be9..40422127ff 100644
--- a/test/units/testsuite-63.service
+++ b/test/units/testsuite-63.service
@@ -5,13 +5,26 @@ Description=TEST-63-ISSUE-17433
[Service]
ExecStartPre=rm -f /failed /testok
Type=oneshot
+
+# Test that a path unit continuously triggering a service that fails condition checks eventually fails with
+# the trigger-limit-hit error.
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.
+# Make sure systemd has sufficient time to hit the trigger limit for test63.path.
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.service -P ActiveState)" = inactive'
+ExecStart=sh -x -c 'test "$(systemctl show test63.service -P Result)" = success'
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 'test "$(systemctl show test63.path -P Result)" = trigger-limit-hit'
+
+# Test that starting the service manually doesn't affect the path unit.
+ExecStart=rm -f /tmp/test63
+ExecStart=systemctl reset-failed
+ExecStart=systemctl start test63.path
+ExecStart=systemctl start test63.service
+ExecStart=sh -x -c 'test "$(systemctl show test63.service -P ActiveState)" = inactive'
+ExecStart=sh -x -c 'test "$(systemctl show test63.service -P Result)" = success'
+ExecStart=sh -x -c 'test "$(systemctl show test63.path -P ActiveState)" = active'
+ExecStart=sh -x -c 'test "$(systemctl show test63.path -P Result)" = success'
ExecStart=sh -x -c 'echo OK >/testok'
--
2.33.0

View File

@ -0,0 +1,493 @@
From 9727f2427ff6b2e1f4ab927cc57ad8e888f04e95 Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Tue, 24 Aug 2021 16:46:47 +0100
Subject: [PATCH] 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.
Conflict:code context adaptation
Reference:https://github.com/systemd/systemd-stable/commit/9727f2427ff6b2e1f4ab927cc57ad8e888f04e95
---
src/core/automount.c | 23 +++++++++++++++++------
src/core/mount.c | 23 +++++++++++++++++------
src/core/path.c | 23 +++++++++++++++++------
src/core/service.c | 25 ++++++++++++++++++-------
src/core/socket.c | 23 +++++++++++++++++------
src/core/swap.c | 23 +++++++++++++++++------
src/core/timer.c | 23 +++++++++++++++++------
src/core/unit.c | 7 +++++++
src/core/unit.h | 4 ++++
test/TEST-63-ISSUE-17433/Makefile | 1 +
test/TEST-63-ISSUE-17433/test.sh | 9 +++++++++
test/meson.build | 2 ++
test/testsuite-10.units/test10.service | 3 +++
test/testsuite-63.units/test63.path | 2 ++
test/testsuite-63.units/test63.service | 5 +++++
test/units/testsuite-63.service | 16 ++++++++++++++++
16 files changed, 169 insertions(+), 43 deletions(-)
create mode 120000 test/TEST-63-ISSUE-17433/Makefile
create mode 100755 test/TEST-63-ISSUE-17433/test.sh
create mode 100644 test/testsuite-63.units/test63.path
create mode 100644 test/testsuite-63.units/test63.service
create mode 100644 test/units/testsuite-63.service
diff --git a/src/core/automount.c b/src/core/automount.c
index 30226b9bde..11eb352b9b 100644
--- a/src/core/automount.c
+++ b/src/core/automount.c
@@ -813,12 +813,6 @@ static int automount_start(Unit *u) {
if (r < 0)
return r;
- r = unit_test_start_limit(u);
- if (r < 0) {
- automount_enter_dead(a, AUTOMOUNT_FAILURE_START_LIMIT_HIT);
- return r;
- }
-
r = unit_acquire_invocation_id(u);
if (r < 0)
return r;
@@ -1064,6 +1058,21 @@ static bool automount_supported(void) {
return supported;
}
+static int automount_test_start_limit(Unit *u) {
+ Automount *a = AUTOMOUNT(u);
+ int r;
+
+ assert(a);
+
+ r = unit_test_start_limit(u);
+ if (r < 0) {
+ automount_enter_dead(a, AUTOMOUNT_FAILURE_START_LIMIT_HIT);
+ return r;
+ }
+
+ return 0;
+}
+
static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = {
[AUTOMOUNT_SUCCESS] = "success",
[AUTOMOUNT_FAILURE_RESOURCES] = "resources",
@@ -1126,4 +1135,6 @@ const UnitVTable automount_vtable = {
[JOB_FAILED] = "Failed to unset automount %s.",
},
},
+
+ .test_start_limit = automount_test_start_limit,
};
diff --git a/src/core/mount.c b/src/core/mount.c
index fb8f72e257..35b56426d4 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -1167,12 +1167,6 @@ static int mount_start(Unit *u) {
assert(IN_SET(m->state, MOUNT_DEAD, MOUNT_FAILED));
- r = unit_test_start_limit(u);
- if (r < 0) {
- mount_enter_dead(m, MOUNT_FAILURE_START_LIMIT_HIT);
- return r;
- }
-
r = unit_acquire_invocation_id(u);
if (r < 0)
return r;
@@ -2138,6 +2132,21 @@ static int mount_can_clean(Unit *u, ExecCleanMask *ret) {
return exec_context_get_clean_mask(&m->exec_context, ret);
}
+static int mount_test_start_limit(Unit *u) {
+ Mount *m = MOUNT(u);
+ int r;
+
+ assert(m);
+
+ r = unit_test_start_limit(u);
+ if (r < 0) {
+ mount_enter_dead(m, MOUNT_FAILURE_START_LIMIT_HIT);
+ return r;
+ }
+
+ return 0;
+}
+
static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = {
[MOUNT_EXEC_MOUNT] = "ExecMount",
[MOUNT_EXEC_UNMOUNT] = "ExecUnmount",
@@ -2235,4 +2244,6 @@ const UnitVTable mount_vtable = {
[JOB_TIMEOUT] = "Timed out unmounting %s.",
},
},
+
+ .test_start_limit = mount_test_start_limit,
};
diff --git a/src/core/path.c b/src/core/path.c
index 800524a308..693636b0ee 100644
--- a/src/core/path.c
+++ b/src/core/path.c
@@ -590,12 +590,6 @@ static int path_start(Unit *u) {
if (r < 0)
return r;
- r = unit_test_start_limit(u);
- if (r < 0) {
- path_enter_dead(p, PATH_FAILURE_START_LIMIT_HIT);
- return r;
- }
-
r = unit_acquire_invocation_id(u);
if (r < 0)
return r;
@@ -812,6 +806,21 @@ static void path_reset_failed(Unit *u) {
p->result = PATH_SUCCESS;
}
+static int path_test_start_limit(Unit *u) {
+ Path *p = PATH(u);
+ int r;
+
+ assert(p);
+
+ r = unit_test_start_limit(u);
+ if (r < 0) {
+ path_enter_dead(p, PATH_FAILURE_START_LIMIT_HIT);
+ return r;
+ }
+
+ return 0;
+}
+
static const char* const path_type_table[_PATH_TYPE_MAX] = {
[PATH_EXISTS] = "PathExists",
[PATH_EXISTS_GLOB] = "PathExistsGlob",
@@ -866,4 +875,6 @@ const UnitVTable path_vtable = {
.reset_failed = path_reset_failed,
.bus_set_property = bus_path_set_property,
+
+ .test_start_limit = path_test_start_limit,
};
diff --git a/src/core/service.c b/src/core/service.c
index c55304d170..9d8eef1f74 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -2436,13 +2436,6 @@ static int service_start(Unit *u) {
assert(IN_SET(s->state, SERVICE_DEAD, SERVICE_FAILED));
- /* Make sure we don't enter a busy loop of some kind. */
- r = unit_test_start_limit(u);
- if (r < 0) {
- service_enter_dead(s, SERVICE_FAILURE_START_LIMIT_HIT, false);
- return r;
- }
-
r = unit_acquire_invocation_id(u);
if (r < 0)
return r;
@@ -4445,6 +4438,22 @@ static const char *service_finished_job(Unit *u, JobType t, JobResult result) {
return NULL;
}
+static int service_test_start_limit(Unit *u) {
+ Service *s = SERVICE(u);
+ int r;
+
+ assert(s);
+
+ /* Make sure we don't enter a busy loop of some kind. */
+ r = unit_test_start_limit(u);
+ if (r < 0) {
+ service_enter_dead(s, SERVICE_FAILURE_START_LIMIT_HIT, false);
+ return r;
+ }
+
+ return 0;
+}
+
static const char* const service_restart_table[_SERVICE_RESTART_MAX] = {
[SERVICE_RESTART_NO] = "no",
[SERVICE_RESTART_ON_SUCCESS] = "on-success",
@@ -4608,4 +4617,6 @@ const UnitVTable service_vtable = {
},
.finished_job = service_finished_job,
},
+
+ .test_start_limit = service_test_start_limit,
};
diff --git a/src/core/socket.c b/src/core/socket.c
index ceaf39bdd3..177068eed4 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -2513,12 +2513,6 @@ static int socket_start(Unit *u) {
assert(IN_SET(s->state, SOCKET_DEAD, SOCKET_FAILED));
- r = unit_test_start_limit(u);
- if (r < 0) {
- socket_enter_dead(s, SOCKET_FAILURE_START_LIMIT_HIT);
- return r;
- }
-
r = unit_acquire_invocation_id(u);
if (r < 0)
return r;
@@ -3425,6 +3419,21 @@ static int socket_can_clean(Unit *u, ExecCleanMask *ret) {
return exec_context_get_clean_mask(&s->exec_context, ret);
}
+static int socket_test_start_limit(Unit *u) {
+ Socket *s = SOCKET(u);
+ int r;
+
+ assert(s);
+
+ r = unit_test_start_limit(u);
+ if (r < 0) {
+ socket_enter_dead(s, SOCKET_FAILURE_START_LIMIT_HIT);
+ return r;
+ }
+
+ return 0;
+}
+
static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = {
[SOCKET_EXEC_START_PRE] = "ExecStartPre",
[SOCKET_EXEC_START_CHOWN] = "ExecStartChown",
@@ -3551,4 +3560,6 @@ const UnitVTable socket_vtable = {
[JOB_TIMEOUT] = "Timed out stopping %s.",
},
},
+
+ .test_start_limit = socket_test_start_limit,
};
diff --git a/src/core/swap.c b/src/core/swap.c
index 48ba5c7664..29c63118ac 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -932,12 +932,6 @@ static int swap_start(Unit *u) {
if (UNIT(other)->job && UNIT(other)->job->state == JOB_RUNNING)
return -EAGAIN;
- r = unit_test_start_limit(u);
- if (r < 0) {
- swap_enter_dead(s, SWAP_FAILURE_START_LIMIT_HIT);
- return r;
- }
-
r = unit_acquire_invocation_id(u);
if (r < 0)
return r;
@@ -1588,6 +1582,21 @@ static int swap_can_clean(Unit *u, ExecCleanMask *ret) {
return exec_context_get_clean_mask(&s->exec_context, ret);
}
+static int swap_test_start_limit(Unit *u) {
+ Swap *s = SWAP(u);
+ int r;
+
+ assert(s);
+
+ r = unit_test_start_limit(u);
+ if (r < 0) {
+ swap_enter_dead(s, SWAP_FAILURE_START_LIMIT_HIT);
+ return r;
+ }
+
+ return 0;
+}
+
static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = {
[SWAP_EXEC_ACTIVATE] = "ExecActivate",
[SWAP_EXEC_DEACTIVATE] = "ExecDeactivate",
@@ -1683,4 +1692,6 @@ const UnitVTable swap_vtable = {
[JOB_TIMEOUT] = "Timed out deactivating swap %s.",
},
},
+
+ .test_start_limit = swap_test_start_limit,
};
diff --git a/src/core/timer.c b/src/core/timer.c
index 12515a6a75..8853121c00 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -627,12 +627,6 @@ static int timer_start(Unit *u) {
if (r < 0)
return r;
- r = unit_test_start_limit(u);
- if (r < 0) {
- timer_enter_dead(t, TIMER_FAILURE_START_LIMIT_HIT);
- return r;
- }
-
r = unit_acquire_invocation_id(u);
if (r < 0)
return r;
@@ -890,6 +884,21 @@ static int timer_can_clean(Unit *u, ExecCleanMask *ret) {
return 0;
}
+static int timer_test_start_limit(Unit *u) {
+ Timer *t = TIMER(u);
+ int r;
+
+ assert(t);
+
+ r = unit_test_start_limit(u);
+ if (r < 0) {
+ timer_enter_dead(t, TIMER_FAILURE_START_LIMIT_HIT);
+ return r;
+ }
+
+ return 0;
+}
+
static const char* const timer_base_table[_TIMER_BASE_MAX] = {
[TIMER_ACTIVE] = "OnActiveSec",
[TIMER_BOOT] = "OnBootSec",
@@ -949,4 +958,6 @@ const UnitVTable timer_vtable = {
.timezone_change = timer_timezone_change,
.bus_set_property = bus_timer_set_property,
+
+ .test_start_limit = timer_test_start_limit,
};
diff --git a/src/core/unit.c b/src/core/unit.c
index 7d72dfa864..48e7b95e56 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -1857,6 +1857,13 @@ int unit_start(Unit *u) {
assert(u);
+ /* Check start rate limiting early so that failure conditions don't cause us to enter a busy loop. */
+ if (UNIT_VTABLE(u)->test_start_limit) {
+ int r = UNIT_VTABLE(u)->test_start_limit(u);
+ if (r < 0)
+ return r;
+ }
+
/* If this is already started, then this will succeed. Note that this will even succeed if this unit
* is not startable by the user. This is relied on to detect when we need to wait for units and when
* waiting is finished. */
diff --git a/src/core/unit.h b/src/core/unit.h
index b3e9c2106f..b689f29f8f 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -658,6 +658,10 @@ typedef struct UnitVTable {
* of this type will immediately fail. */
bool (*supported)(void);
+ /* If this function is set, it's invoked first as part of starting a unit to allow start rate
+ * limiting checks to occur before we do anything else. */
+ int (*test_start_limit)(Unit *u);
+
/* The strings to print in status messages */
UnitStatusMessageFormats status_message_formats;
diff --git a/test/TEST-63-ISSUE-17433/Makefile b/test/TEST-63-ISSUE-17433/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-63-ISSUE-17433/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile
\ No newline at end of file
diff --git a/test/TEST-63-ISSUE-17433/test.sh b/test/TEST-63-ISSUE-17433/test.sh
new file mode 100755
index 0000000000..c595a9f2de
--- /dev/null
+++ b/test/TEST-63-ISSUE-17433/test.sh
@@ -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 "$@"
diff --git a/test/meson.build b/test/meson.build
index a21230a4a8..b8335fb50f 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -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',
diff --git a/test/testsuite-10.units/test10.service b/test/testsuite-10.units/test10.service
index d0be786b01..2fb476b986 100644
--- a/test/testsuite-10.units/test10.service
+++ b/test/testsuite-10.units/test10.service
@@ -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
diff --git a/test/testsuite-63.units/test63.path b/test/testsuite-63.units/test63.path
new file mode 100644
index 0000000000..a6573bda0a
--- /dev/null
+++ b/test/testsuite-63.units/test63.path
@@ -0,0 +1,2 @@
+[Path]
+PathExists=/tmp/test63
diff --git a/test/testsuite-63.units/test63.service b/test/testsuite-63.units/test63.service
new file mode 100644
index 0000000000..c83801874d
--- /dev/null
+++ b/test/testsuite-63.units/test63.service
@@ -0,0 +1,5 @@
+[Unit]
+ConditionPathExists=!/tmp/nonexistent
+
+[Service]
+ExecStart=true
diff --git a/test/units/testsuite-63.service b/test/units/testsuite-63.service
new file mode 100644
index 0000000000..04122723d4
--- /dev/null
+++ b/test/units/testsuite-63.service
@@ -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'
--
2.33.0

View File

@ -0,0 +1,51 @@
From ce2146f5256659c7fb53a7d5b9dc551252e27e7e Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Tue, 19 Oct 2021 10:45:48 +0100
Subject: [PATCH] core: Delay start rate limit check when starting a unit
Doing start rate limit checks before doing condition checks made
condition check failures count towards the start rate limit which
broke existing assumptions (see #21025). Run the rate limit checks
after the condition checks again to restore the previous behaviour.
Conflict:NA
Reference:https://github.com/systemd/systemd-stable/commit/ce2146f5256659c7fb53a7d5b9dc551252e27e7e
---
src/core/unit.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/src/core/unit.c b/src/core/unit.c
index a2944c1917..a6403002a6 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -1855,13 +1855,6 @@ int unit_start(Unit *u) {
assert(u);
- /* Check start rate limiting early so that failure conditions don't cause us to enter a busy loop. */
- if (UNIT_VTABLE(u)->test_start_limit) {
- r = UNIT_VTABLE(u)->test_start_limit(u);
- if (r < 0)
- return r;
- }
-
/* If this is already started, then this will succeed. Note that this will even succeed if this unit
* is not startable by the user. This is relied on to detect when we need to wait for units and when
* waiting is finished. */
@@ -1911,6 +1904,13 @@ int unit_start(Unit *u) {
return unit_start(following);
}
+ /* Check start rate limiting early so that failure conditions don't cause us to enter a busy loop. */
+ if (UNIT_VTABLE(u)->test_start_limit) {
+ r = UNIT_VTABLE(u)->test_start_limit(u);
+ if (r < 0)
+ return r;
+ }
+
/* If it is stopped, but we cannot start it, then fail */
if (!UNIT_VTABLE(u)->start)
return -EBADR;
--
2.33.0

View File

@ -0,0 +1,33 @@
From 5f37c1a955e399756c4137d22f7f0f45a619f425 Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Sat, 30 Oct 2021 22:12:06 +0100
Subject: [PATCH] core: Move 'r' variable declaration to start of unit_start()
Conflict:NA
Reference:https://github.com/systemd/systemd-stable/commit/5f37c1a955e399756c4137d22f7f0f45a619f425
---
src/core/unit.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/core/unit.c b/src/core/unit.c
index 4c55827a65..a2944c1917 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -1851,12 +1851,13 @@ static bool unit_verify_deps(Unit *u) {
int unit_start(Unit *u) {
UnitActiveState state;
Unit *following;
+ int r;
assert(u);
/* Check start rate limiting early so that failure conditions don't cause us to enter a busy loop. */
if (UNIT_VTABLE(u)->test_start_limit) {
- int r = UNIT_VTABLE(u)->test_start_limit(u);
+ r = UNIT_VTABLE(u)->test_start_limit(u);
if (r < 0)
return r;
}
--
2.33.0

View File

@ -0,0 +1,265 @@
From 705578c3b9d794097233aa66010cf67b2a444716 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Mon, 4 Oct 2021 17:51:52 +0200
Subject: [PATCH] core: rename/generalize UNIT(u)->test_start_limit() hook
Up until now the main reason why we didn't proceed with starting the
unit was exceed start limit burst. However, for unit types like mounts
the other reason could be effective ratelimit on /proc/self/mountinfo
event source. That means our mount unit state may not reflect current
kernel state. Hence, we need to attempt to re-run the start job again
after ratelimit on event source expires.
As we will be introducing another reason than start limit let's rename
the virtual function that implements the check.
Conflict:NA
Reference:https://github.com/systemd/systemd-stable/commit/705578c3b9d794097233aa66010cf67b2a444716
---
src/core/automount.c | 6 +++---
src/core/mount.c | 6 +++---
src/core/path.c | 6 +++---
src/core/service.c | 6 +++---
src/core/socket.c | 6 +++---
src/core/swap.c | 6 +++---
src/core/timer.c | 6 +++---
src/core/unit.c | 6 +++---
src/core/unit.h | 2 +-
9 files changed, 25 insertions(+), 25 deletions(-)
diff --git a/src/core/automount.c b/src/core/automount.c
index de470935c7..1fc3fc0f82 100644
--- a/src/core/automount.c
+++ b/src/core/automount.c
@@ -1063,7 +1063,7 @@ static bool automount_supported(void) {
return supported;
}
-static int automount_test_start_limit(Unit *u) {
+static int automount_can_start(Unit *u) {
Automount *a = AUTOMOUNT(u);
int r;
@@ -1075,7 +1075,7 @@ static int automount_test_start_limit(Unit *u) {
return r;
}
- return 0;
+ return 1;
}
static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = {
@@ -1142,5 +1142,5 @@ const UnitVTable automount_vtable = {
},
},
- .test_start_limit = automount_test_start_limit,
+ .can_start = automount_can_start,
};
diff --git a/src/core/mount.c b/src/core/mount.c
index 321c7986b3..2ebae752b6 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -2135,7 +2135,7 @@ static int mount_can_clean(Unit *u, ExecCleanMask *ret) {
return exec_context_get_clean_mask(&m->exec_context, ret);
}
-static int mount_test_start_limit(Unit *u) {
+static int mount_can_start(Unit *u) {
Mount *m = MOUNT(u);
int r;
@@ -2147,7 +2147,7 @@ static int mount_test_start_limit(Unit *u) {
return r;
}
- return 0;
+ return 1;
}
static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = {
@@ -2248,5 +2248,5 @@ const UnitVTable mount_vtable = {
},
},
- .test_start_limit = mount_test_start_limit,
+ .can_start = mount_can_start,
};
diff --git a/src/core/path.c b/src/core/path.c
index 0a3d86e9db..cdab9dcf8c 100644
--- a/src/core/path.c
+++ b/src/core/path.c
@@ -811,7 +811,7 @@ static void path_reset_failed(Unit *u) {
p->result = PATH_SUCCESS;
}
-static int path_test_start_limit(Unit *u) {
+static int path_can_start(Unit *u) {
Path *p = PATH(u);
int r;
@@ -823,7 +823,7 @@ static int path_test_start_limit(Unit *u) {
return r;
}
- return 0;
+ return 1;
}
static const char* const path_type_table[_PATH_TYPE_MAX] = {
@@ -882,5 +882,5 @@ const UnitVTable path_vtable = {
.bus_set_property = bus_path_set_property,
- .test_start_limit = path_test_start_limit,
+ .can_start = path_can_start,
};
diff --git a/src/core/service.c b/src/core/service.c
index 83cbc9f489..17c19a2c4a 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -4482,7 +4482,7 @@ static const char *service_finished_job(Unit *u, JobType t, JobResult result) {
return NULL;
}
-static int service_test_start_limit(Unit *u) {
+static int service_can_start(Unit *u) {
Service *s = SERVICE(u);
int r;
@@ -4495,7 +4495,7 @@ static int service_test_start_limit(Unit *u) {
return r;
}
- return 0;
+ return 1;
}
static const char* const service_restart_table[_SERVICE_RESTART_MAX] = {
@@ -4669,5 +4669,5 @@ const UnitVTable service_vtable = {
.finished_job = service_finished_job,
},
- .test_start_limit = service_test_start_limit,
+ .can_start = service_can_start,
};
diff --git a/src/core/socket.c b/src/core/socket.c
index 6534311bef..f265aab594 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -3427,7 +3427,7 @@ static int socket_can_clean(Unit *u, ExecCleanMask *ret) {
return exec_context_get_clean_mask(&s->exec_context, ret);
}
-static int socket_test_start_limit(Unit *u) {
+static int socket_can_start(Unit *u) {
Socket *s = SOCKET(u);
int r;
@@ -3439,7 +3439,7 @@ static int socket_test_start_limit(Unit *u) {
return r;
}
- return 0;
+ return 1;
}
static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = {
@@ -3570,5 +3570,5 @@ const UnitVTable socket_vtable = {
},
},
- .test_start_limit = socket_test_start_limit,
+ .can_start = socket_can_start,
};
diff --git a/src/core/swap.c b/src/core/swap.c
index de72ac9232..3b28235194 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -1581,7 +1581,7 @@ static int swap_can_clean(Unit *u, ExecCleanMask *ret) {
return exec_context_get_clean_mask(&s->exec_context, ret);
}
-static int swap_test_start_limit(Unit *u) {
+static int swap_can_start(Unit *u) {
Swap *s = SWAP(u);
int r;
@@ -1593,7 +1593,7 @@ static int swap_test_start_limit(Unit *u) {
return r;
}
- return 0;
+ return 1;
}
static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = {
@@ -1692,5 +1692,5 @@ const UnitVTable swap_vtable = {
},
},
- .test_start_limit = swap_test_start_limit,
+ .can_start = swap_can_start,
};
diff --git a/src/core/timer.c b/src/core/timer.c
index 240a2f473b..b22168fad5 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -889,7 +889,7 @@ static int timer_can_clean(Unit *u, ExecCleanMask *ret) {
return 0;
}
-static int timer_test_start_limit(Unit *u) {
+static int timer_can_start(Unit *u) {
Timer *t = TIMER(u);
int r;
@@ -901,7 +901,7 @@ static int timer_test_start_limit(Unit *u) {
return r;
}
- return 0;
+ return 1;
}
static const char* const timer_base_table[_TIMER_BASE_MAX] = {
@@ -965,5 +965,5 @@ const UnitVTable timer_vtable = {
.bus_set_property = bus_timer_set_property,
- .test_start_limit = timer_test_start_limit,
+ .can_start = timer_can_start,
};
diff --git a/src/core/unit.c b/src/core/unit.c
index 77d4ceaf24..929cc85e13 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -1904,9 +1904,9 @@ int unit_start(Unit *u) {
return unit_start(following);
}
- /* Check start rate limiting early so that failure conditions don't cause us to enter a busy loop. */
- if (UNIT_VTABLE(u)->test_start_limit) {
- r = UNIT_VTABLE(u)->test_start_limit(u);
+ /* Check our ability to start early so that failure conditions don't cause us to enter a busy loop. */
+ if (UNIT_VTABLE(u)->can_start) {
+ r = UNIT_VTABLE(u)->can_start(u);
if (r < 0)
return r;
}
diff --git a/src/core/unit.h b/src/core/unit.h
index 3f3a75d33b..76701519c2 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -665,7 +665,7 @@ typedef struct UnitVTable {
/* If this function is set, it's invoked first as part of starting a unit to allow start rate
* limiting checks to occur before we do anything else. */
- int (*test_start_limit)(Unit *u);
+ int (*can_start)(Unit *u);
/* The strings to print in status messages */
UnitStatusMessageFormats status_message_formats;
--
2.33.0

View File

@ -0,0 +1,29 @@
From a7c93dfe91e88a5a561341c523a45c7f8d71a588 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Mon, 4 Oct 2021 19:41:34 +0200
Subject: [PATCH] mount: make mount units start jobs not runnable if
/p/s/mountinfo ratelimit is in effect
Conflict:NA
Reference:https://github.com/systemd/systemd-stable/commit/a7c93dfe91e88a5a561341c523a45c7f8d71a588
---
src/core/mount.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/core/mount.c b/src/core/mount.c
index 2ebae752b6..88a670dc2a 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -2141,6 +2141,9 @@ static int mount_can_start(Unit *u) {
assert(m);
+ if (sd_event_source_is_ratelimited(u->manager->mount_event_source))
+ return -EAGAIN;
+
r = unit_test_start_limit(u);
if (r < 0) {
mount_enter_dead(m, MOUNT_FAILURE_START_LIMIT_HIT);
--
2.33.0

View File

@ -0,0 +1,56 @@
From edc027b4f1cfaa49e8ecdde763eb8c623402d464 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Mon, 4 Oct 2021 20:31:49 +0200
Subject: [PATCH] mount: retrigger run queue after ratelimit expired to run
delayed mount start jobs
Fixes #20329
Conflict:NA
Reference:https://github.com/systemd/systemd-stable/commit/edc027b4f1cfaa49e8ecdde763eb8c623402d464
---
src/core/mount.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/src/core/mount.c b/src/core/mount.c
index 88a670dc2a..3463641c6c 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -1838,6 +1838,21 @@ static bool mount_is_mounted(Mount *m) {
return UNIT(m)->perpetual || FLAGS_SET(m->proc_flags, MOUNT_PROC_IS_MOUNTED);
}
+static int mount_on_ratelimit_expire(sd_event_source *s, void *userdata) {
+ Manager *m = userdata;
+ int r;
+
+ assert(m);
+
+ /* By entering ratelimited state we made all mount start jobs not runnable, now rate limit is over so let's
+ * make sure we dispatch them in the next iteration. */
+ r = sd_event_source_set_enabled(m->run_queue_event_source, SD_EVENT_ONESHOT);
+ if (r < 0)
+ log_debug_errno(r, "Failed to enable run queue event source, ignoring: %m");
+
+ return 0;
+}
+
static void mount_enumerate(Manager *m) {
int r;
@@ -1891,6 +1906,12 @@ static void mount_enumerate(Manager *m) {
goto fail;
}
+ r = sd_event_source_set_ratelimit_expire_callback(m->mount_event_source, mount_on_ratelimit_expire);
+ if (r < 0) {
+ log_error_errno(r, "Failed to enable rate limit for mount events: %m");
+ goto fail;
+ }
+
(void) sd_event_source_set_description(m->mount_event_source, "mount-monitor-dispatch");
}
--
2.33.0

View File

@ -0,0 +1,106 @@
From b0c4b2824693fe6a27ea9439ec7a6328a0e23704 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Fri, 12 Nov 2021 09:43:07 +0100
Subject: [PATCH] pid1: add a manager_trigger_run_queue() helper
We have two different places where we re-trigger the run queue now.
let's unify it under a common function, that is part of the Manager
code.
Follow-up for #20953
Conflict:code context adaptation
Reference:https://github.com/systemd/systemd-stable/commit/b0c4b2824693fe6a27ea9439ec7a6328a0e23704
---
src/core/job.c | 8 ++------
src/core/manager.c | 12 ++++++++++++
src/core/manager.h | 2 ++
src/core/mount.c | 9 +++------
4 files changed, 19 insertions(+), 12 deletions(-)
diff --git a/src/core/job.c b/src/core/job.c
index 6dd01a6f49..b7ac75ac71 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -1107,17 +1107,13 @@ void job_add_to_run_queue(Job *j) {
if (j->in_run_queue)
return;
- if (prioq_isempty(j->manager->run_queue)) {
- r = sd_event_source_set_enabled(j->manager->run_queue_event_source, SD_EVENT_ONESHOT);
- if (r < 0)
- log_warning_errno(r, "Failed to enable job run queue event source, ignoring: %m");
- }
-
r = prioq_put(j->manager->run_queue, j, &j->run_queue_idx);
if (r < 0)
log_warning_errno(r, "Failed put job in run queue, ignoring: %m");
else
j->in_run_queue = true;
+
+ manager_trigger_run_queue(j->manager);
}
void job_add_to_dbus_queue(Job *j) {
diff --git a/src/core/manager.c b/src/core/manager.c
index 61895ab092..b21747daea 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -2248,6 +2248,18 @@ static int manager_dispatch_run_queue(sd_event_source *source, void *userdata) {
return 1;
}
+void manager_trigger_run_queue(Manager *m) {
+ int r;
+
+ assert(m);
+
+ r = sd_event_source_set_enabled(
+ m->run_queue_event_source,
+ prioq_isempty(m->run_queue) ? SD_EVENT_OFF : SD_EVENT_ONESHOT);
+ if (r < 0)
+ log_warning_errno(r, "Failed to enable job run queue event source, ignoring: %m");
+}
+
static unsigned manager_dispatch_dbus_queue(Manager *m) {
unsigned n = 0, budget;
Unit *u;
diff --git a/src/core/manager.h b/src/core/manager.h
index 29ce812121..c9230cb5c4 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -507,6 +507,8 @@ int manager_get_effective_environment(Manager *m, char ***ret);
int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit);
+void manager_trigger_run_queue(Manager *m);
+
int manager_loop(Manager *m);
int manager_open_serialization(Manager *m, FILE **_f);
diff --git a/src/core/mount.c b/src/core/mount.c
index 3463641c6c..4f76b552c2 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -1840,15 +1840,12 @@ static bool mount_is_mounted(Mount *m) {
static int mount_on_ratelimit_expire(sd_event_source *s, void *userdata) {
Manager *m = userdata;
- int r;
assert(m);
- /* By entering ratelimited state we made all mount start jobs not runnable, now rate limit is over so let's
- * make sure we dispatch them in the next iteration. */
- r = sd_event_source_set_enabled(m->run_queue_event_source, SD_EVENT_ONESHOT);
- if (r < 0)
- log_debug_errno(r, "Failed to enable run queue event source, ignoring: %m");
+ /* By entering ratelimited state we made all mount start jobs not runnable, now rate limit is over so
+ * let's make sure we dispatch them in the next iteration. */
+ manager_trigger_run_queue(m);
return 0;
}
--
2.33.0

View File

@ -0,0 +1,282 @@
From fd69f2247520b0be3190ded96d646a415edc97b7 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Mon, 4 Oct 2021 19:44:06 +0200
Subject: [PATCH] sd-event: introduce callback invoked when event source
ratelimit expires
Conflict:code context adaptation
Reference:https://github.com/systemd/systemd-stable/commit/fd69f2247520b0be3190ded96d646a415edc97b7
---
man/sd_event_source_set_ratelimit.xml | 22 +++++++---
src/libsystemd/libsystemd.sym | 1 +
src/libsystemd/sd-event/event-source.h | 1 +
src/libsystemd/sd-event/sd-event.c | 61 ++++++++++++++++++++++----
src/libsystemd/sd-event/test-event.c | 12 +++++
src/systemd/sd-event.h | 1 +
6 files changed, 85 insertions(+), 13 deletions(-)
diff --git a/man/sd_event_source_set_ratelimit.xml b/man/sd_event_source_set_ratelimit.xml
index ac8529074a..37354a09f6 100644
--- a/man/sd_event_source_set_ratelimit.xml
+++ b/man/sd_event_source_set_ratelimit.xml
@@ -19,6 +19,7 @@
<refname>sd_event_source_set_ratelimit</refname>
<refname>sd_event_source_get_ratelimit</refname>
<refname>sd_event_source_is_ratelimited</refname>
+ <refname>sd_event_source_set_ratelimit_expire_callback</refname>
<refpurpose>Configure rate limiting on event sources</refpurpose>
</refnamediv>
@@ -46,6 +47,12 @@
<paramdef>sd_event_source *<parameter>source</parameter></paramdef>
</funcprototype>
+ <funcprototype>
+ <funcdef>int <function>sd_event_source_set_ratelimit_expire_callback</function></funcdef>
+ <paramdef>sd_event_source *<parameter>source</parameter></paramdef>
+ <paramdef>sd_event_handler_t<parameter>callback</parameter></paramdef>
+ </funcprototype>
+
</funcsynopsis>
</refsynopsisdiv>
@@ -78,6 +85,10 @@
is currently affected by rate limiting, i.e. it has recently hit the rate limit and is currently
temporarily disabled due to that.</para>
+ <para><function>sd_event_source_set_ratelimit_expire_callback</function> may be used to set a callback
+ function that is invoked every time the event source leaves rate limited state. Note that function is
+ called in the same event loop iteration in which state transition occured.</para>
+
<para>Rate limiting is currently implemented for I/O, timer, signal, defer and inotify event
sources.</para>
</refsect1>
@@ -85,11 +96,12 @@
<refsect1>
<title>Return Value</title>
- <para>On success, <function>sd_event_source_set_ratelimit()</function> and
- <function>sd_event_source_get_ratelimit()</function> return a non-negative integer. On failure, they
- return a negative errno-style error code. <function>sd_event_source_is_ratelimited</function> returns
- zero if rate limiting is currently not in effect and greater than zero if it is in effect; it returns a
- negative errno-style error code on failure.</para>
+ <para>On success, <function>sd_event_source_set_ratelimit()</function>,
+ <function>sd_event_source_set_ratelimit_expire_callback</function> and
+ <function>sd_event_source_get_ratelimit()</function> return a non-negative integer. On failure, they return
+ a negative errno-style error code. <function>sd_event_source_is_ratelimited</function> returns zero if rate
+ limiting is currently not in effect and greater than zero if it is in effect; it returns a negative
+ errno-style error code on failure.</para>
<refsect2>
<title>Errors</title>
diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym
index 5e2fc9e231..2178668d11 100644
--- a/src/libsystemd/libsystemd.sym
+++ b/src/libsystemd/libsystemd.sym
@@ -767,4 +767,5 @@ LIBSYSTEMD_249 {
sd_device_get_trigger_uuid;
sd_device_new_from_ifname;
sd_device_new_from_ifindex;
+ sd_event_source_set_ratelimit_expire_callback;
} LIBSYSTEMD_248;
diff --git a/src/libsystemd/sd-event/event-source.h b/src/libsystemd/sd-event/event-source.h
index 41845c0bb5..74cbc26962 100644
--- a/src/libsystemd/sd-event/event-source.h
+++ b/src/libsystemd/sd-event/event-source.h
@@ -71,6 +71,7 @@ struct sd_event_source {
uint64_t prepare_iteration;
sd_event_destroy_t destroy_callback;
+ sd_event_handler_t ratelimit_expire_callback;
LIST_FIELDS(sd_event_source, sources);
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index 0ca0248510..d8f84d9ba7 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -2908,7 +2908,7 @@ fail:
return r;
}
-static int event_source_leave_ratelimit(sd_event_source *s) {
+static int event_source_leave_ratelimit(sd_event_source *s, bool run_callback) {
int r;
assert(s);
@@ -2940,6 +2940,30 @@ static int event_source_leave_ratelimit(sd_event_source *s) {
ratelimit_reset(&s->rate_limit);
log_debug("Event source %p (%s) left rate limit state.", s, strna(s->description));
+
+ if (run_callback && s->ratelimit_expire_callback) {
+ s->dispatching = true;
+ r = s->ratelimit_expire_callback(s, s->userdata);
+ s->dispatching = false;
+
+ if (r < 0) {
+ log_debug_errno(r, "Ratelimit expiry callback of event source %s (type %s) returned error, %s: %m",
+ strna(s->description),
+ event_source_type_to_string(s->type),
+ s->exit_on_failure ? "exiting" : "disabling");
+
+ if (s->exit_on_failure)
+ (void) sd_event_exit(s->event, r);
+ }
+
+ if (s->n_ref == 0)
+ source_free(s);
+ else if (r < 0)
+ sd_event_source_set_enabled(s, SD_EVENT_OFF);
+
+ return 1;
+ }
+
return 0;
fail:
@@ -3139,6 +3163,7 @@ static int process_timer(
struct clock_data *d) {
sd_event_source *s;
+ bool callback_invoked = false;
int r;
assert(e);
@@ -3156,9 +3181,11 @@ static int process_timer(
* again. */
assert(s->ratelimited);
- r = event_source_leave_ratelimit(s);
+ r = event_source_leave_ratelimit(s, /* run_callback */ true);
if (r < 0)
return r;
+ else if (r == 1)
+ callback_invoked = true;
continue;
}
@@ -3173,7 +3200,7 @@ static int process_timer(
event_source_time_prioq_reshuffle(s);
}
- return 0;
+ return callback_invoked;
}
static int process_child(sd_event *e, int64_t threshold, int64_t *ret_min_priority) {
@@ -4097,15 +4124,15 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
if (r < 0)
goto finish;
- r = process_timer(e, e->timestamp.realtime, &e->realtime);
+ r = process_inotify(e);
if (r < 0)
goto finish;
- r = process_timer(e, e->timestamp.boottime, &e->boottime);
+ r = process_timer(e, e->timestamp.realtime, &e->realtime);
if (r < 0)
goto finish;
- r = process_timer(e, e->timestamp.monotonic, &e->monotonic);
+ r = process_timer(e, e->timestamp.boottime, &e->boottime);
if (r < 0)
goto finish;
@@ -4117,9 +4144,20 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
if (r < 0)
goto finish;
- r = process_inotify(e);
+ r = process_timer(e, e->timestamp.monotonic, &e->monotonic);
if (r < 0)
goto finish;
+ else if (r == 1) {
+ /* Ratelimit expiry callback was called. Let's postpone processing pending sources and
+ * put loop in the initial state in order to evaluate (in the next iteration) also sources
+ * there were potentially re-enabled by the callback.
+ *
+ * Wondering why we treat only this invocation of process_timer() differently? Once event
+ * source is ratelimited we essentially transform it into CLOCK_MONOTONIC timer hence
+ * ratelimit expiry callback is never called for any other timer type. */
+ r = 0;
+ goto finish;
+ }
if (event_next_pending(e)) {
e->state = SD_EVENT_PENDING;
@@ -4488,7 +4526,7 @@ _public_ int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval
/* When ratelimiting is configured we'll always reset the rate limit state first and start fresh,
* non-ratelimited. */
- r = event_source_leave_ratelimit(s);
+ r = event_source_leave_ratelimit(s, /* run_callback */ false);
if (r < 0)
return r;
@@ -4496,6 +4534,13 @@ _public_ int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval
return 0;
}
+_public_ int sd_event_source_set_ratelimit_expire_callback(sd_event_source *s, sd_event_handler_t callback) {
+ assert_return(s, -EINVAL);
+
+ s->ratelimit_expire_callback = callback;
+ return 0;
+}
+
_public_ int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval, unsigned *ret_burst) {
assert_return(s, -EINVAL);
diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c
index b637639f26..0ac23c1118 100644
--- a/src/libsystemd/sd-event/test-event.c
+++ b/src/libsystemd/sd-event/test-event.c
@@ -623,6 +623,11 @@ static int ratelimit_time_handler(sd_event_source *s, uint64_t usec, void *userd
return 0;
}
+static int expired = -1;
+static int ratelimit_expired(sd_event_source *s, void *userdata) {
+ return ++expired;
+}
+
static void test_ratelimit(void) {
_cleanup_close_pair_ int p[2] = {-1, -1};
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
@@ -686,12 +691,19 @@ static void test_ratelimit(void) {
assert_se(sd_event_source_set_ratelimit(s, 1 * USEC_PER_SEC, 10) >= 0);
+ /* Set callback that will be invoked when we leave rate limited state. */
+ assert_se(sd_event_source_set_ratelimit_expire_callback(s, ratelimit_expired) >= 0);
+
do {
assert_se(sd_event_run(e, UINT64_MAX) >= 0);
} while (!sd_event_source_is_ratelimited(s));
log_info("ratelimit_time_handler: called 10 more times, event source got ratelimited");
assert_se(count == 20);
+
+ /* Dispatch the event loop once more and check that ratelimit expiration callback got called */
+ assert_se(sd_event_run(e, UINT64_MAX) >= 0);
+ assert_se(expired == 0);
}
static void test_simple_timeout(void) {
diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h
index f4357aa593..63984eef15 100644
--- a/src/systemd/sd-event.h
+++ b/src/systemd/sd-event.h
@@ -166,6 +166,7 @@ int sd_event_source_set_exit_on_failure(sd_event_source *s, int b);
int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval_usec, unsigned burst);
int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval_usec, unsigned *ret_burst);
int sd_event_source_is_ratelimited(sd_event_source *s);
+int sd_event_source_set_ratelimit_expire_callback(sd_event_source *s, sd_event_handler_t callback);
/* Define helpers so that __attribute__((cleanup(sd_event_unrefp))) and similar may be used. */
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_event, sd_event_unref);
--
2.33.0

View File

@ -0,0 +1,47 @@
From c29e6a9530316823b0455cd83eb6d0bb8dd664f4 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Thu, 25 Nov 2021 18:28:25 +0100
Subject: [PATCH] unit: add jobs that were skipped because of ratelimit back to
run_queue
Assumption in edc027b was that job we first skipped because of active
ratelimit is still in run_queue. Hence we trigger the queue and dispatch
it in the next iteration. Actually we remove jobs from run_queue in
job_run_and_invalidate() before we call unit_start(). Hence if we want
to attempt to run the job again in the future we need to add it back
to run_queue.
Fixes #21458
Conflict:NA
Reference:https://github.com/systemd/systemd-stable/commit/c29e6a9530316823b0455cd83eb6d0bb8dd664f4
---
src/core/mount.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/src/core/mount.c b/src/core/mount.c
index 90b11347f7..35368fe8e6 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -1840,9 +1840,18 @@ static bool mount_is_mounted(Mount *m) {
static int mount_on_ratelimit_expire(sd_event_source *s, void *userdata) {
Manager *m = userdata;
+ Job *j;
assert(m);
+ /* Let's enqueue all start jobs that were previously skipped because of active ratelimit. */
+ HASHMAP_FOREACH(j, m->jobs) {
+ if (j->unit->type != UNIT_MOUNT)
+ continue;
+
+ job_add_to_run_queue(j);
+ }
+
/* By entering ratelimited state we made all mount start jobs not runnable, now rate limit is over so
* let's make sure we dispatch them in the next iteration. */
manager_trigger_run_queue(m);
--
2.33.0

View File

@ -0,0 +1,54 @@
From b161bc394b2cc8b271dda9208e310cc2af0cc29d Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Mon, 30 May 2022 11:55:41 +0200
Subject: [PATCH] unit: check for mount rate limiting before checking active
state
Having this check as part of mount_can_start() is too late because
UNIT(u)->can_start() virtual method is called after checking the active
state of unit in unit_start().
We need to hold off running mount start jobs when /p/s/mountinfo monitor
is rate limited even when given mount unit is already active.
Fixes #20329
Conflict:NA
Reference:https://github.com/systemd/systemd-stable/commit/b161bc394b2cc8b271dda9208e310cc2af0cc29d
---
src/core/mount.c | 3 ---
src/core/unit.c | 4 ++++
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/core/mount.c b/src/core/mount.c
index 20b4bb6d2b..a2fd9c2a99 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -2170,9 +2170,6 @@ static int mount_can_start(Unit *u) {
assert(m);
- if (sd_event_source_is_ratelimited(u->manager->mount_event_source))
- return -EAGAIN;
-
r = unit_test_start_limit(u);
if (r < 0) {
mount_enter_dead(m, MOUNT_FAILURE_START_LIMIT_HIT);
diff --git a/src/core/unit.c b/src/core/unit.c
index b0756bc6f4..d7f5245ca3 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -1868,6 +1868,10 @@ int unit_start(Unit *u) {
assert(u);
+ /* Let's hold off running start jobs for mount units when /proc/self/mountinfo monitor is rate limited. */
+ if (u->type == UNIT_MOUNT && sd_event_source_is_ratelimited(u->manager->mount_event_source))
+ return -EAGAIN;
+
/* If this is already started, then this will succeed. Note that this will even succeed if this unit
* is not startable by the user. This is relied on to detect when we need to wait for units and when
* waiting is finished. */
--
2.33.0

View File

@ -10,12 +10,13 @@ logs). Therefore, when the journal~ file is generated, delete all journal files
except system.journal, to ensure that the sd_journal_next function meets user
expectations.
---
meson.build | 2 ++
meson.build | 3 ++-
src/basic/dirent-util.c | 24 ++++++++++++++++
src/basic/dirent-util.h | 2 ++
src/libsystemd/sd-journal/journal-file.c | 35 ++++++++++++++++++++++++
src/libsystemd/sd-journal/sd-journal.c | 22 ---------------
5 files changed, 63 insertions(+), 22 deletions(-)
src/test/meson.build | 2 +-
6 files changed, 64 insertions(+), 23 deletions(-)
diff --git a/meson.build b/meson.build
index 278e264..9ab40b6 100644
@ -30,6 +31,15 @@ index 278e264..9ab40b6 100644
'.')
libsystemd_includes = [basic_includes, include_directories(
@@ -1801,7 +1801,7 @@ test_dlopen = executable(
test_dlopen_c,
disable_mempool_c,
include_directories : includes,
- link_with : [libbasic],
+ link_with : [libbasic, libsystemd_static],
dependencies : [libdl],
build_by_default : want_tests != 'false')
diff --git a/src/basic/dirent-util.c b/src/basic/dirent-util.c
index f6213a3..b227cae 100644
--- a/src/basic/dirent-util.c
@ -181,6 +191,19 @@ index 1a76bb6..56e1398 100644
static int directory_open(sd_journal *j, const char *path, DIR **ret) {
DIR *d;
diff --git a/src/test/meson.build b/src/test/meson.build
index 7f7d8b7..9b1fb87 100644
--- a/src/test/meson.build
+++ b/src/test/meson.build
@@ -364,7 +364,7 @@ tests += [
[], [], [], '', 'timeout=90'],
[['src/test/test-set.c'],
- [libbasic]],
+ [libbasic, libsystemd_static]],
[['src/test/test-ordered-set.c']],
--
2.23.0

View File

@ -29,7 +29,7 @@ index 053deac..de5b745 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -1895,6 +1895,10 @@ static void mount_enumerate(Manager *m) {
goto fail;
goto fail;
}
+ r = sd_event_source_set_preempt_dispatch_count(m->mount_event_source, 5);
@ -53,8 +53,8 @@ index d2dc214..0fa41aa 100644
+ unsigned preempt_dispatch_count; /*Will be preempted by lower priority if dispatched count reaches to this*/
+
sd_event_destroy_t destroy_callback;
sd_event_handler_t ratelimit_expire_callback;
LIST_FIELDS(sd_event_source, sources);
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index e9199de..46f8aff 100644
--- a/src/libsystemd/sd-event/sd-event.c
@ -211,10 +211,10 @@ diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h
index 2ae2a0d..f113aba 100644
--- a/src/systemd/sd-event.h
+++ b/src/systemd/sd-event.h
@@ -165,6 +165,7 @@ int sd_event_source_set_exit_on_failure(sd_event_source *s, int b);
int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval_usec, unsigned burst);
@@ -165,6 +165,7 @@ int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval_usec, unsigned burst);
int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval_usec, unsigned *ret_burst);
int sd_event_source_is_ratelimited(sd_event_source *s);
int sd_event_source_set_ratelimit_expire_callback(sd_event_source *s, sd_event_handler_t callback);
+int sd_event_source_set_preempt_dispatch_count(sd_event_source *s, unsigned count);
/* Define helpers so that __attribute__((cleanup(sd_event_unrefp))) and similar may be used. */

View File

@ -21,7 +21,7 @@
Name: systemd
Url: https://www.freedesktop.org/wiki/Software/systemd
Version: 249
Release: 52
Release: 53
License: MIT and LGPLv2+ and GPLv2+
Summary: System and Service Manager
@ -517,6 +517,17 @@ Patch6469: backport-core-device-verify-device-syspath-on-switching-root.pat
Patch6470: backport-sd-lldp-use-memcpy_safe-as-the-buffer-size-may-be-ze.patch
Patch6471: backport-shared-bootspec-avoid-crashing-on-config-without-a-v.patch
Patch6472: backport-sysext-refuse-empty-release-ID-to-avoid-triggering-a.patch
Patch6473: backport-core-Check-unit-start-rate-limiting-earlier.patch
Patch6474: backport-core-Move-r-variable-declaration-to-start-of-unit_st.patch
Patch6475: backport-core-Delay-start-rate-limit-check-when-starting-a-un.patch
Patch6476: backport-core-Add-trigger-limit-for-path-units.patch
Patch6477: backport-sd-event-introduce-callback-invoked-when-event-sourc.patch
Patch6478: backport-core-rename-generalize-UNIT-u-test_start_limit-hook.patch
Patch6479: backport-mount-make-mount-units-start-jobs-not-runnable-if-p-.patch
Patch6480: backport-mount-retrigger-run-queue-after-ratelimit-expired-to.patch
Patch6481: backport-pid1-add-a-manager_trigger_run_queue-helper.patch
Patch6482: backport-unit-add-jobs-that-were-skipped-because-of-ratelimit.patch
Patch6483: backport-unit-check-for-mount-rate-limiting-before-checking-a.patch
Patch9001: update-rtc-with-system-clock-when-shutdown.patch
Patch9002: udev-add-actions-while-rename-netif-failed.patch
@ -1988,6 +1999,9 @@ fi
%{_libdir}/security/pam_systemd.so
%changelog
* Tue Aug 15 2023 wangyuhang <wangyuhang27@huawei.com> - 249-53
- backport: sync patches from systemd community
* Thu Jun 15 2023 hongjinghao <hongjinghao@huawei.com> - 249-52
- backport: sync patches from systemd community