1
0
mirror of https://github.com/systemd/systemd synced 2026-03-18 11:04:46 +01:00

Compare commits

...

9 Commits

Author SHA1 Message Date
Luca Boccassi
7ad9bad71b
Merge pull request #19811 from anitazha/revert_mount_rl
sd-event: fix failure to exit rate limiting state
2021-06-10 23:41:55 +01:00
Luca Boccassi
390a22f4b1
Merge pull request #19864 from keszybz/serialization-cleanup
Serialization cleanup
2021-06-10 23:40:23 +01:00
nl6720
9dfb429a44 kbd-model-map: add Latvian keyboard layout mapping 2021-06-10 23:29:32 +01:00
Zbigniew Jędrzejewski-Szmek
ab18976b35 core/serialize: drop bogus deserialization of ipcns sockets
a70581ffb5c13c91c76ff73ba6f5f3ff59c5a915 added ExecRuntime.ipcns_storage_socket[], and
serialization in exec_runtime_serialize(), and deserialization in exec_runtime_deserialize_one(),
but also deserialization in exec_runtime_deserialize_compat(). exec_runtime_deserialize_compat()
is for deserializating ExecRuntime when it was serialized as part of the unit before
e8a565cb660a7a11f76180fe441ba8e4f9383771. There was never any code which would serialize
ExecRuntime.ipcns_storage_socket[] this way, so the deserialization attempts are pointless.
2021-06-10 14:17:58 +02:00
Zbigniew Jędrzejewski-Szmek
cbc165d17e core/serialization: shorten code, treat all oom error the same 2021-06-10 14:17:58 +02:00
Zbigniew Jędrzejewski-Szmek
1085c0eb69 core/serialization: drop misleadingly-named unit_can_serialize()
All unit types can be serialized. This function was really checking whether the
unit type has custom serialization/deserialization code. But we don't need a
function for this.

Also, the check that both .serialize() and .deserialize_item() are defined is
better written as an assert. Not we have a function which would skip
serialization/deserializaton for the unit if we forgot to set either of the
fields.
2021-06-10 14:17:58 +02:00
Lennart Poettering
81107b8419 sd-event: change ordering of pending/ratelimited events
Instead of ordering non-pending before pending we should order
"non-pending OR ratelimited" before "pending AND not-ratelimited".
This fixes a bug where ratelimited events were ordered at the end of the
priority queue and could be stuck there for an indeterminate amount of
time.
2021-06-09 21:02:22 -07:00
Anita Zhang
0c81900965 test: add extended test for triggering mount rate limit
It's hard to trigger the failure to exit the rate limit state in
isolation as it needs multiple event sources in order to show that it
gets stuck in the queue. Hence why this is an extended test.
2021-06-09 12:04:56 -07:00
Zbigniew Jędrzejewski-Szmek
fe50aae5e1 core/serialization: call exec_runtime_deserialize_compat() independently of whether .serialize is defined
There is no reason to tie the two together: in principle we may have
in the future a unit type which does not define .serialize/.deserialize_item,
but we would still want to call the compat deserialization code for it.
2021-06-09 12:54:27 +02:00
10 changed files with 127 additions and 84 deletions

View File

@ -6371,38 +6371,24 @@ int exec_runtime_deserialize_compat(Unit *u, const char *key, const char *value,
return 0;
}
r = hashmap_ensure_allocated(&u->manager->exec_runtime_by_id, &string_hash_ops);
if (r < 0) {
log_unit_debug_errno(u, r, "Failed to allocate storage for runtime parameter: %m");
return 0;
}
if (hashmap_ensure_allocated(&u->manager->exec_runtime_by_id, &string_hash_ops) < 0)
return log_oom();
rt = hashmap_get(u->manager->exec_runtime_by_id, u->id);
if (!rt) {
r = exec_runtime_allocate(&rt_create, u->id);
if (r < 0)
if (exec_runtime_allocate(&rt_create, u->id) < 0)
return log_oom();
rt = rt_create;
}
if (streq(key, "tmp-dir")) {
char *copy;
copy = strdup(value);
if (!copy)
return log_oom();
free_and_replace(rt->tmp_dir, copy);
if (free_and_strdup_warn(&rt->tmp_dir, value) < 0)
return -ENOMEM;
} else if (streq(key, "var-tmp-dir")) {
char *copy;
copy = strdup(value);
if (!copy)
return log_oom();
free_and_replace(rt->var_tmp_dir, copy);
if (free_and_strdup_warn(&rt->var_tmp_dir, value) < 0)
return -ENOMEM;
} else if (streq(key, "netns-socket-0")) {
int fd;
@ -6426,27 +6412,6 @@ int exec_runtime_deserialize_compat(Unit *u, const char *key, const char *value,
safe_close(rt->netns_storage_socket[1]);
rt->netns_storage_socket[1] = fdset_remove(fds, fd);
} else if (streq(key, "ipcns-socket-0")) {
int fd;
if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd)) {
log_unit_debug(u, "Failed to parse ipcns socket value: %s", value);
return 0;
}
safe_close(rt->ipcns_storage_socket[0]);
rt->ipcns_storage_socket[0] = fdset_remove(fds, fd);
} else if (streq(key, "ipcns-socket-1")) {
int fd;
if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd)) {
log_unit_debug(u, "Failed to parse ipcns socket value: %s", value);
return 0;
}
safe_close(rt->ipcns_storage_socket[1]);
rt->ipcns_storage_socket[1] = fdset_remove(fds, fd);
} else
return 0;

View File

@ -108,7 +108,9 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool switching_root) {
fputs(u->id, f);
fputc('\n', f);
if (unit_can_serialize(u)) {
assert(!!UNIT_VTABLE(u)->serialize == !!UNIT_VTABLE(u)->deserialize_item);
if (UNIT_VTABLE(u)->serialize) {
r = UNIT_VTABLE(u)->serialize(u, f, fds);
if (r < 0)
return r;
@ -498,17 +500,15 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
continue;
}
if (unit_can_serialize(u)) {
r = exec_runtime_deserialize_compat(u, l, v, fds);
if (r < 0) {
log_unit_warning(u, "Failed to deserialize runtime parameter '%s', ignoring.", l);
continue;
}
} else if (r > 0)
/* Returns positive if key was handled by the call */
if (r > 0)
continue;
if (UNIT_VTABLE(u)->deserialize_item) {
r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds);
if (r < 0)
log_unit_warning(u, "Failed to deserialize unit parameter '%s', ignoring.", l);

View File

@ -3488,12 +3488,6 @@ void unit_unwatch_bus_name(Unit *u, const char *name) {
u->get_name_owner_slot = sd_bus_slot_unref(u->get_name_owner_slot);
}
bool unit_can_serialize(Unit *u) {
assert(u);
return UNIT_VTABLE(u)->serialize && UNIT_VTABLE(u)->deserialize_item;
}
int unit_add_node_dependency(Unit *u, const char *what, UnitDependency dep, UnitDependencyMask mask) {
_cleanup_free_ char *e = NULL;
Unit *device;

View File

@ -814,8 +814,6 @@ char *unit_dbus_path_invocation_id(Unit *u);
int unit_load_related_unit(Unit *u, const char *type, Unit **_found);
bool unit_can_serialize(Unit *u) _pure_;
int unit_add_node_dependency(Unit *u, const char *what, UnitDependency d, UnitDependencyMask mask);
int unit_add_blockdev_dependency(Unit *u, const char *what, UnitDependencyMask mask);

View File

@ -237,25 +237,6 @@ static usec_t time_event_source_next(const sd_event_source *s) {
return USEC_INFINITY;
}
static int earliest_time_prioq_compare(const void *a, const void *b) {
const sd_event_source *x = a, *y = b;
/* Enabled ones first */
if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
return -1;
if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
return 1;
/* Move the pending ones to the end */
if (!x->pending && y->pending)
return -1;
if (x->pending && !y->pending)
return 1;
/* Order by time */
return CMP(time_event_source_next(x), time_event_source_next(y));
}
static usec_t time_event_source_latest(const sd_event_source *s) {
assert(s);
@ -274,7 +255,15 @@ static usec_t time_event_source_latest(const sd_event_source *s) {
return USEC_INFINITY;
}
static int latest_time_prioq_compare(const void *a, const void *b) {
static bool event_source_timer_candidate(const sd_event_source *s) {
assert(s);
/* Returns true for event sources that either are not pending yet (i.e. where it's worth to mark them pending)
* or which are currently ratelimited (i.e. where it's worth leaving the ratelimited state) */
return !s->pending || s->ratelimited;
}
static int time_prioq_compare(const void *a, const void *b, usec_t (*time_func)(const sd_event_source *s)) {
const sd_event_source *x = a, *y = b;
/* Enabled ones first */
@ -283,14 +272,22 @@ static int latest_time_prioq_compare(const void *a, const void *b) {
if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
return 1;
/* Move the pending ones to the end */
if (!x->pending && y->pending)
/* Order "non-pending OR ratelimited" before "pending AND not-ratelimited" */
if (event_source_timer_candidate(x) && !event_source_timer_candidate(y))
return -1;
if (x->pending && !y->pending)
if (!event_source_timer_candidate(x) && event_source_timer_candidate(y))
return 1;
/* Order by time */
return CMP(time_event_source_latest(x), time_event_source_latest(y));
return CMP(time_func(x), time_func(y));
}
static int earliest_time_prioq_compare(const void *a, const void *b) {
return time_prioq_compare(a, b, time_event_source_next);
}
static int latest_time_prioq_compare(const void *a, const void *b) {
return time_prioq_compare(a, b, time_event_source_latest);
}
static int exit_prioq_compare(const void *a, const void *b) {

View File

@ -67,3 +67,5 @@ lt.l4 lt pc105 - terminate:ctrl_alt_bksp
lt lt pc105 - terminate:ctrl_alt_bksp
khmer kh,us pc105 - terminate:ctrl_alt_bksp
es-dvorak es microsoftpro dvorak terminate:ctrl_alt_bksp
lv lv pc105 apostrophe terminate:ctrl_alt_bksp
lv-tilde lv pc105 tilde terminate:ctrl_alt_bksp

View File

@ -0,0 +1 @@
../TEST-01-BASIC/Makefile

View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -e
TEST_DESCRIPTION="Test that mount/unmount storms can enter/exit rate limit state and will not leak units"
. $TEST_BASE_DIR/test-functions
do_test "$@"

View File

@ -0,0 +1,6 @@
[Unit]
Description=TEST-60-MOUNT-RATELIMIT
[Service]
Type=oneshot
ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh

73
test/units/testsuite-60.sh Executable file
View File

@ -0,0 +1,73 @@
#!/usr/bin/env bash
set -eux
set -o pipefail
systemd-analyze log-level debug
systemd-analyze log-target journal
NUM_DIRS=20
# mount/unmount enough times to trigger the /proc/self/mountinfo parsing rate limiting
for ((i = 0; i < NUM_DIRS; i++)); do
mkdir "/tmp/meow${i}"
done
for ((i = 0; i < NUM_DIRS; i++)); do
mount -t tmpfs tmpfs "/tmp/meow${i}"
done
systemctl daemon-reload
systemctl list-units -t mount tmp-meow* | grep -q tmp-meow
for ((i = 0; i < NUM_DIRS; i++)); do
umount "/tmp/meow${i}"
done
# figure out if we have entered the rate limit state
exited_rl=0
timeout="$(date -ud "2 minutes" +%s)"
while [[ $(date -u +%s) -le ${timeout} ]]; do
if journalctl -u init.scope | grep -q "(mount-monitor-dispatch) entered rate limit"; then
entered_rl=1
break
fi
sleep 5
done
# if the infra is slow we might not enter the rate limit state; in that case skip the exit check
if [ "${entered_rl}" = "1" ]; then
exited_rl=0
timeout="$(date -ud "2 minutes" +%s)"
while [[ $(date -u +%s) -le ${timeout} ]]; do
if journalctl -u init.scope | grep -q "(mount-monitor-dispatch) left rate limit"; then
exited_rl=1
break
fi
sleep 5
done
if [ "${exited_rl}" = "0" ]; then
exit 24
fi
fi
# give some time for units to settle so we don't race between exiting the rate limit state and cleaning up the units
sleep 60
systemctl daemon-reload
sleep 60
# verify that the mount units are always cleaned up at the end
if systemctl list-units -t mount tmp-meow* | grep -q tmp-meow; then
exit 42
fi
systemd-analyze log-level info
echo OK >/testok
exit 0