From 7628565604f5a6a572cb4a33ccde9a64fcc9ff09 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 8 Aug 2024 10:59:08 +0200 Subject: [PATCH 01/12] mkosi: Disable pagination in gdb --- mkosi.extra/root/.gdbinit | 1 + 1 file changed, 1 insertion(+) diff --git a/mkosi.extra/root/.gdbinit b/mkosi.extra/root/.gdbinit index e576a26803..e9c9ec4144 100644 --- a/mkosi.extra/root/.gdbinit +++ b/mkosi.extra/root/.gdbinit @@ -1,3 +1,4 @@ # SPDX-License-Identifier: LGPL-2.1-or-later set debuginfod enabled off +set pagination off From c022fcd80c5bf94e8ac5511559f085303b24b070 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 8 Aug 2024 21:48:34 +0200 Subject: [PATCH 02/12] mkosi: Install llvm For llvm-symbolizer which is required to sanitize address sanitizer reports. --- mkosi.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/mkosi.conf b/mkosi.conf index 6545e1a41f..12917af7e6 100644 --- a/mkosi.conf +++ b/mkosi.conf @@ -101,6 +101,7 @@ Packages= kexec-tools kmod less + llvm lvm2 man mdadm From dba138b863fadf57362026281d0597b2d7736090 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 8 Aug 2024 21:49:09 +0200 Subject: [PATCH 03/12] test: Fix section of StateDirectory= --- test/test.service.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test.service.in b/test/test.service.in index ef9dba30c4..48c09baf6c 100644 --- a/test/test.service.in +++ b/test/test.service.in @@ -4,7 +4,6 @@ Description=%N Wants=basic.target network.target @wants@ After=basic.target network.target @after@ Before=getty-pre.target -StateDirectory=%N [Service] ExecStartPre=rm -f /failed /testok @@ -13,3 +12,4 @@ ExecStart=@command@ ExecStopPost=/usr/lib/systemd/tests/integration-test-setup.sh finalize Type=oneshot MemoryAccounting=@memory-accounting@ +StateDirectory=%N From db043a9b1a109478581f19b69a3019fc15f672aa Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 8 Aug 2024 22:34:05 +0200 Subject: [PATCH 04/12] test: Use usual setup in integration-test-setup script --- test/integration-test-setup.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/integration-test-setup.sh b/test/integration-test-setup.sh index 71f576f61f..d7c384a97c 100755 --- a/test/integration-test-setup.sh +++ b/test/integration-test-setup.sh @@ -1,6 +1,7 @@ -#!/bin/bash +#!/usr/bin/env bash # SPDX-License-Identifier: LGPL-2.1-or-later -set -e +set -eux +set -o pipefail case "$1" in setup) From 2031fe74617a188df5a25ff14f269ff01f169832 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Fri, 9 Aug 2024 14:49:52 +0200 Subject: [PATCH 05/12] basic: Various cleanups for ratelimit functions --- src/basic/ratelimit.c | 28 ++++++++++++++-------------- src/basic/ratelimit.h | 6 +++--- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/basic/ratelimit.c b/src/basic/ratelimit.c index 41ca0709e8..df8c95c562 100644 --- a/src/basic/ratelimit.c +++ b/src/basic/ratelimit.c @@ -8,37 +8,37 @@ /* Modelled after Linux' lib/ratelimit.c by Dave Young * , which is licensed GPLv2. */ -bool ratelimit_below(RateLimit *r) { +bool ratelimit_below(RateLimit *rl) { usec_t ts; - assert(r); + assert(rl); - if (!ratelimit_configured(r)) + if (!ratelimit_configured(rl)) return true; ts = now(CLOCK_MONOTONIC); - if (r->begin <= 0 || - usec_sub_unsigned(ts, r->begin) > r->interval) { - r->begin = ts; /* Start a new time window */ - r->num = 1; /* Reset counter */ + if (rl->begin <= 0 || + usec_sub_unsigned(ts, rl->begin) > rl->interval) { + rl->begin = ts; /* Start a new time window */ + rl->num = 1; /* Reset counter */ return true; } - if (_unlikely_(r->num == UINT_MAX)) + if (_unlikely_(rl->num == UINT_MAX)) return false; - r->num++; - return r->num <= r->burst; + rl->num++; + return rl->num <= rl->burst; } -unsigned ratelimit_num_dropped(RateLimit *r) { - assert(r); +unsigned ratelimit_num_dropped(const RateLimit *rl) { + assert(rl); - if (r->num == UINT_MAX) /* overflow, return as special case */ + if (rl->num == UINT_MAX) /* overflow, return as special case */ return UINT_MAX; - return LESS_BY(r->num, r->burst); + return LESS_BY(rl->num, rl->burst); } usec_t ratelimit_end(const RateLimit *rl) { diff --git a/src/basic/ratelimit.h b/src/basic/ratelimit.h index 492ea3b48d..7801ef4270 100644 --- a/src/basic/ratelimit.h +++ b/src/basic/ratelimit.h @@ -18,13 +18,13 @@ static inline void ratelimit_reset(RateLimit *rl) { rl->num = rl->begin = 0; } -static inline bool ratelimit_configured(RateLimit *rl) { +static inline bool ratelimit_configured(const RateLimit *rl) { return rl->interval > 0 && rl->burst > 0; } -bool ratelimit_below(RateLimit *r); +bool ratelimit_below(RateLimit *rl); -unsigned ratelimit_num_dropped(RateLimit *r); +unsigned ratelimit_num_dropped(const RateLimit *rl); usec_t ratelimit_end(const RateLimit *rl); usec_t ratelimit_left(const RateLimit *rl); From 14702b9c18b73130e98a9c0d65697adf54a1bcfc Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Wed, 29 Nov 2023 14:15:00 +0100 Subject: [PATCH 06/12] core: Use RateLimit struct to store ratelimits This makes it easier to serialize these ratelimits with JSON_BUILD_CALLBACK(). --- src/core/dbus-execute.c | 8 ++++---- src/core/dbus-manager.c | 8 ++++---- src/core/dbus-socket.c | 8 ++++---- src/core/execute-serialize.c | 12 ++++++------ src/core/execute.c | 11 +++++------ src/core/execute.h | 3 +-- src/core/load-fragment-gperf.gperf.in | 8 ++++---- src/core/main.c | 6 +++--- src/core/manager.c | 6 ++---- src/core/manager.h | 3 +-- src/core/socket.c | 17 ++++++++--------- src/core/socket.h | 3 +-- src/core/unit.c | 13 +++++-------- 13 files changed, 48 insertions(+), 58 deletions(-) diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 264e2f0af6..2954f63422 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -1111,8 +1111,8 @@ const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_PROPERTY("SyslogLevel", "i", property_get_syslog_level, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SyslogFacility", "i", property_get_syslog_facility, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LogLevelMax", "i", bus_property_get_int, offsetof(ExecContext, log_level_max), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LogRateLimitIntervalUSec", "t", bus_property_get_usec, offsetof(ExecContext, log_ratelimit_interval_usec), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LogRateLimitBurst", "u", bus_property_get_unsigned, offsetof(ExecContext, log_ratelimit_burst), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LogRateLimitIntervalUSec", "t", bus_property_get_usec, offsetof(ExecContext, log_ratelimit.interval), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LogRateLimitBurst", "u", bus_property_get_unsigned, offsetof(ExecContext, log_ratelimit.burst), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LogExtraFields", "aay", property_get_log_extra_fields, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LogFilterPatterns", "a(bs)", property_get_log_filter_patterns, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LogNamespace", "s", NULL, offsetof(ExecContext, log_namespace), SD_BUS_VTABLE_PROPERTY_CONST), @@ -1730,10 +1730,10 @@ int bus_exec_context_set_transient_property( return bus_set_transient_log_level(u, name, &c->log_level_max, message, flags, error); if (streq(name, "LogRateLimitIntervalUSec")) - return bus_set_transient_usec(u, name, &c->log_ratelimit_interval_usec, message, flags, error); + return bus_set_transient_usec(u, name, &c->log_ratelimit.interval, message, flags, error); if (streq(name, "LogRateLimitBurst")) - return bus_set_transient_unsigned(u, name, &c->log_ratelimit_burst, message, flags, error); + return bus_set_transient_unsigned(u, name, &c->log_ratelimit.burst, message, flags, error); if (streq(name, "LogFilterPatterns")) { /* Use _cleanup_free_, not _cleanup_strv_free_, as we don't want the content of the strv diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 3d2796f2c4..e88bb50c80 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -3112,11 +3112,11 @@ const sd_bus_vtable bus_manager_vtable[] = { SD_BUS_PROPERTY("DefaultTimeoutAbortUSec", "t", property_get_default_timeout_abort_usec, 0, 0), SD_BUS_PROPERTY("DefaultDeviceTimeoutUSec", "t", bus_property_get_usec, offsetof(Manager, defaults.device_timeout_usec), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultRestartUSec", "t", bus_property_get_usec, offsetof(Manager, defaults.restart_usec), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("DefaultStartLimitIntervalUSec", "t", bus_property_get_usec, offsetof(Manager, defaults.start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultStartLimitIntervalUSec", "t", bus_property_get_usec, offsetof(Manager, defaults.start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST), /* The following two items are obsolete alias */ - SD_BUS_PROPERTY("DefaultStartLimitIntervalSec", "t", bus_property_get_usec, offsetof(Manager, defaults.start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), - SD_BUS_PROPERTY("DefaultStartLimitInterval", "t", bus_property_get_usec, offsetof(Manager, defaults.start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), - SD_BUS_PROPERTY("DefaultStartLimitBurst", "u", bus_property_get_unsigned, offsetof(Manager, defaults.start_limit_burst), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultStartLimitIntervalSec", "t", bus_property_get_usec, offsetof(Manager, defaults.start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), + SD_BUS_PROPERTY("DefaultStartLimitInterval", "t", bus_property_get_usec, offsetof(Manager, defaults.start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), + SD_BUS_PROPERTY("DefaultStartLimitBurst", "u", bus_property_get_unsigned, offsetof(Manager, defaults.start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultCPUAccounting", "b", bus_property_get_bool, offsetof(Manager, defaults.cpu_accounting), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultBlockIOAccounting", "b", bus_property_get_bool, offsetof(Manager, defaults.blockio_accounting), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultIOAccounting", "b", bus_property_get_bool, offsetof(Manager, defaults.io_accounting), SD_BUS_VTABLE_PROPERTY_CONST), diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index 2ab4961b2b..545bef5af5 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -112,8 +112,8 @@ const sd_bus_vtable bus_socket_vtable[] = { SD_BUS_PROPERTY("SocketProtocol", "i", bus_property_get_int, offsetof(Socket, socket_protocol), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("TriggerLimitIntervalUSec", "t", bus_property_get_usec, offsetof(Socket, trigger_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("TriggerLimitBurst", "u", bus_property_get_unsigned, offsetof(Socket, trigger_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("PollLimitIntervalUSec", "t", bus_property_get_usec, offsetof(Socket, poll_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("PollLimitBurst", "u", bus_property_get_unsigned, offsetof(Socket, poll_limit_burst), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("PollLimitIntervalUSec", "t", bus_property_get_usec, offsetof(Socket, poll_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("PollLimitBurst", "u", bus_property_get_unsigned, offsetof(Socket, poll_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("UID", "u", bus_property_get_uid, offsetof(Unit, ref_uid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("GID", "u", bus_property_get_gid, offsetof(Unit, ref_gid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), @@ -237,7 +237,7 @@ static int bus_socket_set_transient_property( return bus_set_transient_unsigned(u, name, &s->trigger_limit.burst, message, flags, error); if (streq(name, "PollLimitBurst")) - return bus_set_transient_unsigned(u, name, &s->poll_limit_burst, message, flags, error); + return bus_set_transient_unsigned(u, name, &s->poll_limit.burst, message, flags, error); if (streq(name, "SocketMode")) return bus_set_transient_mode_t(u, name, &s->socket_mode, message, flags, error); @@ -267,7 +267,7 @@ static int bus_socket_set_transient_property( return bus_set_transient_usec(u, name, &s->trigger_limit.interval, message, flags, error); if (streq(name, "PollLimitIntervalUSec")) - return bus_set_transient_usec(u, name, &s->poll_limit_interval, message, flags, error); + return bus_set_transient_usec(u, name, &s->poll_limit.interval, message, flags, error); if (streq(name, "SmackLabel")) return bus_set_transient_string(u, name, &s->smack, message, flags, error); diff --git a/src/core/execute-serialize.c b/src/core/execute-serialize.c index 237d26044e..38bd969560 100644 --- a/src/core/execute-serialize.c +++ b/src/core/execute-serialize.c @@ -2174,14 +2174,14 @@ static int exec_context_serialize(const ExecContext *c, FILE *f) { if (r < 0) return r; - if (c->log_ratelimit_interval_usec > 0) { - r = serialize_usec(f, "exec-context-log-ratelimit-interval-usec", c->log_ratelimit_interval_usec); + if (c->log_ratelimit.interval > 0) { + r = serialize_usec(f, "exec-context-log-ratelimit-interval-usec", c->log_ratelimit.interval); if (r < 0) return r; } - if (c->log_ratelimit_burst > 0) { - r = serialize_item_format(f, "exec-context-log-ratelimit-burst", "%u", c->log_ratelimit_burst); + if (c->log_ratelimit.burst > 0) { + r = serialize_item_format(f, "exec-context-log-ratelimit-burst", "%u", c->log_ratelimit.burst); if (r < 0) return r; } @@ -3112,11 +3112,11 @@ static int exec_context_deserialize(ExecContext *c, FILE *f) { if (r < 0) return r; } else if ((val = startswith(l, "exec-context-log-ratelimit-interval-usec="))) { - r = deserialize_usec(val, &c->log_ratelimit_interval_usec); + r = deserialize_usec(val, &c->log_ratelimit.interval); if (r < 0) return r; } else if ((val = startswith(l, "exec-context-log-ratelimit-burst="))) { - r = safe_atou(val, &c->log_ratelimit_burst); + r = safe_atou(val, &c->log_ratelimit.burst); if (r < 0) return r; } else if ((val = startswith(l, "exec-context-log-filter-allowed-patterns="))) { diff --git a/src/core/execute.c b/src/core/execute.c index e1a94587a1..c2735fc998 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -626,8 +626,7 @@ void exec_context_done(ExecContext *c) { c->log_filter_allowed_patterns = set_free_free(c->log_filter_allowed_patterns); c->log_filter_denied_patterns = set_free_free(c->log_filter_denied_patterns); - c->log_ratelimit_interval_usec = 0; - c->log_ratelimit_burst = 0; + c->log_ratelimit = (RateLimit) {}; c->stdin_data = mfree(c->stdin_data); c->stdin_data_size = 0; @@ -1216,13 +1215,13 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) { fprintf(f, "%sLogLevelMax: %s\n", prefix, strna(t)); } - if (c->log_ratelimit_interval_usec > 0) + if (c->log_ratelimit.interval > 0) fprintf(f, "%sLogRateLimitIntervalSec: %s\n", - prefix, FORMAT_TIMESPAN(c->log_ratelimit_interval_usec, USEC_PER_SEC)); + prefix, FORMAT_TIMESPAN(c->log_ratelimit.interval, USEC_PER_SEC)); - if (c->log_ratelimit_burst > 0) - fprintf(f, "%sLogRateLimitBurst: %u\n", prefix, c->log_ratelimit_burst); + if (c->log_ratelimit.burst > 0) + fprintf(f, "%sLogRateLimitBurst: %u\n", prefix, c->log_ratelimit.burst); if (!set_isempty(c->log_filter_allowed_patterns) || !set_isempty(c->log_filter_denied_patterns)) { fprintf(f, "%sLogFilterPatterns:", prefix); diff --git a/src/core/execute.h b/src/core/execute.h index 22d72c8959..15c7473a7c 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -302,8 +302,7 @@ struct ExecContext { Set *log_filter_allowed_patterns; Set *log_filter_denied_patterns; - usec_t log_ratelimit_interval_usec; - unsigned log_ratelimit_burst; + RateLimit log_ratelimit; int log_level_max; diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in index 9a78e22fb5..7441d3c759 100644 --- a/src/core/load-fragment-gperf.gperf.in +++ b/src/core/load-fragment-gperf.gperf.in @@ -54,8 +54,8 @@ {{type}}.SyslogLevel, config_parse_log_level, 0, offsetof({{type}}, exec_context.syslog_priority) {{type}}.SyslogLevelPrefix, config_parse_bool, 0, offsetof({{type}}, exec_context.syslog_level_prefix) {{type}}.LogLevelMax, config_parse_log_level, 0, offsetof({{type}}, exec_context.log_level_max) -{{type}}.LogRateLimitIntervalSec, config_parse_sec, 0, offsetof({{type}}, exec_context.log_ratelimit_interval_usec) -{{type}}.LogRateLimitBurst, config_parse_unsigned, 0, offsetof({{type}}, exec_context.log_ratelimit_burst) +{{type}}.LogRateLimitIntervalSec, config_parse_sec, 0, offsetof({{type}}, exec_context.log_ratelimit.interval) +{{type}}.LogRateLimitBurst, config_parse_unsigned, 0, offsetof({{type}}, exec_context.log_ratelimit.burst) {{type}}.LogExtraFields, config_parse_log_extra_fields, 0, offsetof({{type}}, exec_context) {{type}}.LogFilterPatterns, config_parse_log_filter_patterns, 0, offsetof({{type}}, exec_context) {{type}}.Capabilities, config_parse_warn_compat, DISABLED_LEGACY, offsetof({{type}}, exec_context) @@ -514,8 +514,8 @@ Socket.FileDescriptorName, config_parse_fdname, Socket.Service, config_parse_socket_service, 0, 0 Socket.TriggerLimitIntervalSec, config_parse_sec, 0, offsetof(Socket, trigger_limit.interval) Socket.TriggerLimitBurst, config_parse_unsigned, 0, offsetof(Socket, trigger_limit.burst) -Socket.PollLimitIntervalSec, config_parse_sec, 0, offsetof(Socket, poll_limit_interval) -Socket.PollLimitBurst, config_parse_unsigned, 0, offsetof(Socket, poll_limit_burst) +Socket.PollLimitIntervalSec, config_parse_sec, 0, offsetof(Socket, poll_limit.interval) +Socket.PollLimitBurst, config_parse_unsigned, 0, offsetof(Socket, poll_limit.burst) {% if ENABLE_SMACK %} Socket.SmackLabel, config_parse_unit_string_printf, 0, offsetof(Socket, smack) Socket.SmackLabelIPIn, config_parse_unit_string_printf, 0, offsetof(Socket, smack_ip_in) diff --git a/src/core/main.c b/src/core/main.c index 4c92d81c40..29723a9c66 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -783,9 +783,9 @@ static int parse_config_file(void) { { "Manager", "DefaultTimeoutAbortSec", config_parse_default_timeout_abort, 0, NULL }, { "Manager", "DefaultDeviceTimeoutSec", config_parse_sec, 0, &arg_defaults.device_timeout_usec }, { "Manager", "DefaultRestartSec", config_parse_sec, 0, &arg_defaults.restart_usec }, - { "Manager", "DefaultStartLimitInterval", config_parse_sec, 0, &arg_defaults.start_limit_interval}, /* obsolete alias */ - { "Manager", "DefaultStartLimitIntervalSec", config_parse_sec, 0, &arg_defaults.start_limit_interval}, - { "Manager", "DefaultStartLimitBurst", config_parse_unsigned, 0, &arg_defaults.start_limit_burst }, + { "Manager", "DefaultStartLimitInterval", config_parse_sec, 0, &arg_defaults.start_limit.interval}, /* obsolete alias */ + { "Manager", "DefaultStartLimitIntervalSec", config_parse_sec, 0, &arg_defaults.start_limit.interval}, + { "Manager", "DefaultStartLimitBurst", config_parse_unsigned, 0, &arg_defaults.start_limit.burst }, { "Manager", "DefaultEnvironment", config_parse_environ, arg_runtime_scope, &arg_default_environment }, { "Manager", "ManagerEnvironment", config_parse_environ, arg_runtime_scope, &arg_manager_environment }, { "Manager", "DefaultLimitCPU", config_parse_rlimit, RLIMIT_CPU, arg_defaults.rlimit }, diff --git a/src/core/manager.c b/src/core/manager.c index 39fbbfa470..499ecec88e 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -4342,8 +4342,7 @@ int manager_set_unit_defaults(Manager *m, const UnitDefaults *defaults) { m->defaults.timeout_abort_set = defaults->timeout_abort_set; m->defaults.device_timeout_usec = defaults->device_timeout_usec; - m->defaults.start_limit_interval = defaults->start_limit_interval; - m->defaults.start_limit_burst = defaults->start_limit_burst; + m->defaults.start_limit = defaults->start_limit; m->defaults.cpu_accounting = defaults->cpu_accounting; m->defaults.memory_accounting = defaults->memory_accounting; @@ -5104,8 +5103,7 @@ void unit_defaults_init(UnitDefaults *defaults, RuntimeScope scope) { .timeout_abort_usec = manager_default_timeout(scope), .timeout_abort_set = false, .device_timeout_usec = manager_default_timeout(scope), - .start_limit_interval = DEFAULT_START_LIMIT_INTERVAL, - .start_limit_burst = DEFAULT_START_LIMIT_BURST, + .start_limit = { DEFAULT_START_LIMIT_INTERVAL, DEFAULT_START_LIMIT_BURST }, /* On 4.15+ with unified hierarchy, CPU accounting is essentially free as it doesn't require the CPU * controller to be enabled, so the default is to enable it unless we got told otherwise. */ diff --git a/src/core/manager.h b/src/core/manager.h index 908a148196..62e1346a85 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -162,8 +162,7 @@ typedef struct UnitDefaults { usec_t restart_usec, timeout_start_usec, timeout_stop_usec, timeout_abort_usec, device_timeout_usec; bool timeout_abort_set; - usec_t start_limit_interval; - unsigned start_limit_burst; + RateLimit start_limit; bool cpu_accounting; bool memory_accounting; diff --git a/src/core/socket.c b/src/core/socket.c index da9aa9a4a7..9cb188abc7 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -137,8 +137,7 @@ static void socket_init(Unit *u) { s->trigger_limit = RATELIMIT_OFF; - s->poll_limit_interval = USEC_INFINITY; - s->poll_limit_burst = UINT_MAX; + s->poll_limit = RATELIMIT_OFF; } static void socket_unwatch_control_pid(Socket *s) { @@ -322,10 +321,10 @@ static int socket_add_extras(Socket *s) { if (s->trigger_limit.burst == UINT_MAX) s->trigger_limit.burst = s->accept ? 200 : 20; - if (s->poll_limit_interval == USEC_INFINITY) - s->poll_limit_interval = 2 * USEC_PER_SEC; - if (s->poll_limit_burst == UINT_MAX) - s->poll_limit_burst = s->accept ? 150 : 15; + if (s->poll_limit.interval == USEC_INFINITY) + s->poll_limit.interval = 2 * USEC_PER_SEC; + if (s->poll_limit.burst == UINT_MAX) + s->poll_limit.burst = s->accept ? 150 : 15; if (have_non_accept_socket(s)) { @@ -797,8 +796,8 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { "%sPollLimitBurst: %u\n", prefix, FORMAT_TIMESPAN(s->trigger_limit.interval, USEC_PER_SEC), prefix, s->trigger_limit.burst, - prefix, FORMAT_TIMESPAN(s->poll_limit_interval, USEC_PER_SEC), - prefix, s->poll_limit_burst); + prefix, FORMAT_TIMESPAN(s->poll_limit.interval, USEC_PER_SEC), + prefix, s->poll_limit.burst); str = ip_protocol_to_name(s->socket_protocol); if (str) @@ -1783,7 +1782,7 @@ static int socket_watch_fds(Socket *s) { (void) sd_event_source_set_description(p->event_source, "socket-port-io"); } - r = sd_event_source_set_ratelimit(p->event_source, s->poll_limit_interval, s->poll_limit_burst); + r = sd_event_source_set_ratelimit(p->event_source, s->poll_limit.interval, s->poll_limit.burst); if (r < 0) log_unit_debug_errno(UNIT(s), r, "Failed to set poll limit on I/O event source, ignoring: %m"); } diff --git a/src/core/socket.h b/src/core/socket.h index 55afee6122..d4b39d559d 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -161,8 +161,7 @@ struct Socket { char *fdname; RateLimit trigger_limit; - usec_t poll_limit_interval; - unsigned poll_limit_burst; + RateLimit poll_limit; }; SocketPeer *socket_peer_ref(SocketPeer *p); diff --git a/src/core/unit.c b/src/core/unit.c index 2bdbcdf366..6a452f888a 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -120,10 +120,7 @@ Unit* unit_new(Manager *m, size_t size) { u->last_section_private = -1; - u->start_ratelimit = (const RateLimit) { - m->defaults.start_limit_interval, - m->defaults.start_limit_burst, - }; + u->start_ratelimit = m->defaults.start_limit; u->auto_start_stop_ratelimit = (const RateLimit) { .interval = 10 * USEC_PER_SEC, @@ -5693,12 +5690,12 @@ static int unit_export_log_ratelimit_interval(Unit *u, const ExecContext *c) { if (u->exported_log_ratelimit_interval) return 0; - if (c->log_ratelimit_interval_usec == 0) + if (c->log_ratelimit.interval == 0) return 0; p = strjoina("/run/systemd/units/log-rate-limit-interval:", u->id); - if (asprintf(&buf, "%" PRIu64, c->log_ratelimit_interval_usec) < 0) + if (asprintf(&buf, "%" PRIu64, c->log_ratelimit.interval) < 0) return log_oom(); r = symlink_atomic(buf, p); @@ -5720,12 +5717,12 @@ static int unit_export_log_ratelimit_burst(Unit *u, const ExecContext *c) { if (u->exported_log_ratelimit_burst) return 0; - if (c->log_ratelimit_burst == 0) + if (c->log_ratelimit.burst == 0) return 0; p = strjoina("/run/systemd/units/log-rate-limit-burst:", u->id); - if (asprintf(&buf, "%u", c->log_ratelimit_burst) < 0) + if (asprintf(&buf, "%u", c->log_ratelimit.burst) < 0) return log_oom(); r = symlink_atomic(buf, p); From 6d2984d21bf2a8f71d379ef6bc13a761bb2e2756 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Wed, 7 Aug 2024 13:12:03 +0200 Subject: [PATCH 07/12] core: Introduce unit_is_filtered() --- src/core/dbus-manager.c | 9 +-------- src/core/unit.c | 16 ++++++++++++++++ src/core/unit.h | 2 ++ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index e88bb50c80..1fa8b15a80 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -1218,14 +1218,7 @@ static int list_units_filtered(sd_bus_message *message, void *userdata, sd_bus_e if (k != u->id) continue; - if (!strv_isempty(states) && - !strv_contains(states, unit_load_state_to_string(u->load_state)) && - !strv_contains(states, unit_active_state_to_string(unit_active_state(u))) && - !strv_contains(states, unit_sub_state_to_string(u))) - continue; - - if (!strv_isempty(patterns) && - !strv_fnmatch_or_empty(patterns, u->id, FNM_NOESCAPE)) + if (unit_is_filtered(u, states, patterns)) continue; r = reply_unit_info(reply, u); diff --git a/src/core/unit.c b/src/core/unit.c index 6a452f888a..6bd68c7d46 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -6470,6 +6470,22 @@ int unit_arm_timer( return 0; } +bool unit_is_filtered(Unit *u, char *const *states, char *const *patterns) { + assert(u); + + if (!strv_isempty(states)) { + char *const *unit_states = STRV_MAKE( + unit_load_state_to_string(u->load_state), + unit_active_state_to_string(unit_active_state(u)), + unit_sub_state_to_string(u)); + + if (!strv_overlap(states, unit_states)) + return true; + } + + return !strv_isempty(patterns) && !strv_fnmatch_or_empty(patterns, u->id, FNM_NOESCAPE); +} + static int unit_get_nice(Unit *u) { ExecContext *ec; diff --git a/src/core/unit.h b/src/core/unit.h index bf736a5870..831bce885c 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -1043,6 +1043,8 @@ Condition *unit_find_failed_condition(Unit *u); int unit_arm_timer(Unit *u, sd_event_source **source, bool relative, usec_t usec, sd_event_time_handler_t handler); +bool unit_is_filtered(Unit *u, char *const *states, char *const *patterns); + int unit_compare_priority(Unit *a, Unit *b); UnitMountDependencyType unit_mount_dependency_type_from_string(const char *s) _const_; From 406e41cdef60629f3dfed9da8d9c40821ab73bef Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Fri, 9 Aug 2024 14:07:34 +0200 Subject: [PATCH 08/12] core: Clean up includes a little --- src/core/job.h | 5 +++-- src/core/unit.h | 3 --- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/core/job.h b/src/core/job.h index 8e8d6ff08f..680b4a6016 100644 --- a/src/core/job.h +++ b/src/core/job.h @@ -3,12 +3,11 @@ #include +#include "sd-bus.h" #include "sd-event.h" #include "list.h" #include "unit-dependency-atom.h" -#include "unit-name.h" -#include "unit.h" typedef struct ActivationDetails ActivationDetails; typedef struct Job Job; @@ -17,6 +16,8 @@ typedef enum JobType JobType; typedef enum JobState JobState; typedef enum JobMode JobMode; typedef enum JobResult JobResult; +typedef struct Manager Manager; +typedef struct Unit Unit; /* Be careful when changing the job types! Adjust job_merging_table[] accordingly! */ enum JobType { diff --git a/src/core/unit.h b/src/core/unit.h index 831bce885c..7f11539986 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -17,15 +17,12 @@ typedef enum UnitMountDependencyType { _UNIT_MOUNT_DEPENDENCY_TYPE_INVALID = -EINVAL, } UnitMountDependencyType; -#include "bpf-program.h" #include "cgroup.h" #include "condition.h" #include "emergency-action.h" #include "install.h" #include "list.h" #include "pidref.h" -#include "set.h" -#include "show-status.h" #include "unit-file.h" typedef struct UnitRef UnitRef; From 32c9bf14ce1a1b4219c765e6c56823c786d97aff Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 8 Aug 2024 10:57:35 +0200 Subject: [PATCH 09/12] taint: Add taint_strv() to get taints as an array --- src/core/taint.c | 14 ++++++++++++-- src/core/taint.h | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/core/taint.c b/src/core/taint.c index 969b37f209..b7a1c647a2 100644 --- a/src/core/taint.c +++ b/src/core/taint.c @@ -31,7 +31,7 @@ static int short_uid_gid_range(UIDRangeUsernsMode mode) { return !uid_range_covers(p, 0, 65535); } -char* taint_string(void) { +char** taint_strv(void) { const char *stage[12] = {}; size_t n = 0; @@ -81,5 +81,15 @@ char* taint_string(void) { assert(n < ELEMENTSOF(stage) - 1); /* One extra for NULL terminator */ - return strv_join((char**) stage, ":"); + return strv_copy((char *const *) stage); +} + +char* taint_string(void) { + _cleanup_strv_free_ char **taints = NULL; + + taints = taint_strv(); + if (!taints) + return NULL; + + return strv_join(taints, ":"); } diff --git a/src/core/taint.h b/src/core/taint.h index 2e514e3335..fb47156511 100644 --- a/src/core/taint.h +++ b/src/core/taint.h @@ -1,4 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +char** taint_strv(void); char* taint_string(void); From e3878ff657ed203e9048007789b22b0377ba8d03 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 8 Aug 2024 14:14:53 +0200 Subject: [PATCH 10/12] sd-json: Use goto finish instead of return sd_json_buildv() uses a "finish" goto label for cleanup so make sure we goto that label on failure instead of returning directly. --- src/libsystemd/sd-json/sd-json.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsystemd/sd-json/sd-json.c b/src/libsystemd/sd-json/sd-json.c index 98ffe4db54..835ba56bed 100644 --- a/src/libsystemd/sd-json/sd-json.c +++ b/src/libsystemd/sd-json/sd-json.c @@ -4098,7 +4098,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { SD_JSON_BUILD_PAIR("realtime", SD_JSON_BUILD_UNSIGNED(ts->realtime)), SD_JSON_BUILD_PAIR("monotonic", SD_JSON_BUILD_UNSIGNED(ts->monotonic))); if (r < 0) - return r; + goto finish; } else add = JSON_VARIANT_MAGIC_NULL; } From c557f6f54090d931702ba354eea07232a53b5c0c Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Wed, 24 Jul 2024 22:08:15 +0200 Subject: [PATCH 11/12] core-varlink: merge two FLAGS_SET() where appropriate --- src/core/core-varlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/core-varlink.c b/src/core/core-varlink.c index ba6d50b504..ac20296b85 100644 --- a/src/core/core-varlink.c +++ b/src/core/core-varlink.c @@ -596,7 +596,7 @@ static int vl_reply(sd_varlink *link, sd_json_variant *parameters, const char *e if (error_id) log_debug("varlink systemd-oomd client error: %s", error_id); - if (FLAGS_SET(flags, SD_VARLINK_REPLY_ERROR) && FLAGS_SET(flags, SD_VARLINK_REPLY_LOCAL)) { + if (FLAGS_SET(flags, SD_VARLINK_REPLY_ERROR|SD_VARLINK_REPLY_LOCAL)) { /* sd_varlink connection was closed, likely because of systemd-oomd restart. Let's try to * reconnect and send the initial ManagedOOM update again. */ From 2250c996cfc41afb30cd086adeed18fd41a683ba Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 12 Aug 2024 14:15:35 +0200 Subject: [PATCH 12/12] core-varlink: Introduce manager_varlink_managed_oom_connect() In the next commit, we'll introduce a varlink server for the user manager. As preparation for that, let's introduce a new function to initialize only the managed OOM connection whenever we send a managed OOM update. --- src/core/core-varlink.c | 282 +++++++++++++++++++++------------------- 1 file changed, 145 insertions(+), 137 deletions(-) diff --git a/src/core/core-varlink.c b/src/core/core-varlink.c index ac20296b85..28eb927944 100644 --- a/src/core/core-varlink.c +++ b/src/core/core-varlink.c @@ -95,70 +95,6 @@ static int build_managed_oom_json_array_element(Unit *u, const char *property, s SD_JSON_BUILD_PAIR_CONDITION(use_limit, "limit", SD_JSON_BUILD_UNSIGNED(c->moom_mem_pressure_limit))); } -int manager_varlink_send_managed_oom_update(Unit *u) { - _cleanup_(sd_json_variant_unrefp) sd_json_variant *arr = NULL, *v = NULL; - CGroupRuntime *crt; - CGroupContext *c; - int r; - - assert(u); - - if (!UNIT_VTABLE(u)->can_set_managed_oom || !u->manager) - return 0; - - crt = unit_get_cgroup_runtime(u); - if (!crt || !crt->cgroup_path) - return 0; - - if (MANAGER_IS_SYSTEM(u->manager)) { - /* In system mode we can't send any notifications unless oomd connected back to us. In this - * mode oomd must initiate communication, not us. */ - if (!u->manager->managed_oom_varlink) - return 0; - } else { - /* If we are in user mode, let's connect to oomd if we aren't connected yet. In this mode we - * must initiate communication to oomd, not the other way round. */ - r = manager_varlink_init(u->manager); - if (r <= 0) - return r; - } - - c = unit_get_cgroup_context(u); - if (!c) - return 0; - - r = sd_json_build(&arr, SD_JSON_BUILD_EMPTY_ARRAY); - if (r < 0) - return r; - - FOREACH_ELEMENT(i, managed_oom_mode_properties) { - _cleanup_(sd_json_variant_unrefp) sd_json_variant *e = NULL; - - r = build_managed_oom_json_array_element(u, *i, &e); - if (r < 0) - return r; - - r = sd_json_variant_append_array(&arr, e); - if (r < 0) - return r; - } - - r = sd_json_buildo(&v, SD_JSON_BUILD_PAIR("cgroups", SD_JSON_BUILD_VARIANT(arr))); - if (r < 0) - return r; - - if (MANAGER_IS_SYSTEM(u->manager)) - /* in system mode, oomd is our client, thus send out notifications as replies to the - * initiating method call from them. */ - r = sd_varlink_notify(u->manager->managed_oom_varlink, v); - else - /* in user mode, we are oomd's client, thus send out notifications as method calls that do - * not expect a reply. */ - r = sd_varlink_send(u->manager->managed_oom_varlink, "io.systemd.oom.ReportManagedOOMCGroups", v); - - return r; -} - static int build_managed_oom_cgroups_json(Manager *m, sd_json_variant **ret) { _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL, *arr = NULL; int r; @@ -213,6 +149,150 @@ static int build_managed_oom_cgroups_json(Manager *m, sd_json_variant **ret) { return 0; } +static int manager_varlink_send_managed_oom_initial(Manager *m) { + _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; + int r; + + assert(m); + + if (MANAGER_IS_SYSTEM(m)) + return 0; + + assert(m->managed_oom_varlink); + + r = build_managed_oom_cgroups_json(m, &v); + if (r < 0) + return r; + + return sd_varlink_send(m->managed_oom_varlink, "io.systemd.oom.ReportManagedOOMCGroups", v); +} + +static int manager_varlink_managed_oom_connect(Manager *m); + +static int managed_oom_vl_reply(sd_varlink *link, sd_json_variant *parameters, const char *error_id, sd_varlink_reply_flags_t flags, void *userdata) { + Manager *m = ASSERT_PTR(userdata); + int r; + + if (error_id) + log_debug("varlink systemd-oomd client error: %s", error_id); + + if (FLAGS_SET(flags, SD_VARLINK_REPLY_ERROR|SD_VARLINK_REPLY_LOCAL)) { + /* sd_varlink connection was closed, likely because of systemd-oomd restart. Let's try to + * reconnect and send the initial ManagedOOM update again. */ + + m->managed_oom_varlink = sd_varlink_unref(link); + + log_debug("Reconnecting to %s", VARLINK_ADDR_PATH_MANAGED_OOM_USER); + + r = manager_varlink_managed_oom_connect(m); + if (r <= 0) + return r; + } + + return 0; +} + +static int manager_varlink_managed_oom_connect(Manager *m) { + _cleanup_(sd_varlink_close_unrefp) sd_varlink *link = NULL; + int r; + + assert(m); + + if (m->managed_oom_varlink) + return 1; + + r = sd_varlink_connect_address(&link, VARLINK_ADDR_PATH_MANAGED_OOM_USER); + if (r == -ENOENT) + return 0; + if (ERRNO_IS_NEG_DISCONNECT(r)) { + log_debug_errno(r, "systemd-oomd varlink socket isn't available, skipping user manager varlink setup: %m"); + return 0; + } + if (r < 0) + return log_error_errno(r, "Failed to connect to '%s': %m", VARLINK_ADDR_PATH_MANAGED_OOM_USER); + + sd_varlink_set_userdata(link, m); + + r = sd_varlink_bind_reply(link, managed_oom_vl_reply); + if (r < 0) + return r; + + r = sd_varlink_attach_event(link, m->event, EVENT_PRIORITY_IPC); + if (r < 0) + return log_error_errno(r, "Failed to attach varlink connection to event loop: %m"); + + m->managed_oom_varlink = TAKE_PTR(link); + + /* Queue the initial ManagedOOM update. */ + (void) manager_varlink_send_managed_oom_initial(m); + + return 1; +} + +int manager_varlink_send_managed_oom_update(Unit *u) { + _cleanup_(sd_json_variant_unrefp) sd_json_variant *arr = NULL, *v = NULL; + CGroupRuntime *crt; + CGroupContext *c; + int r; + + assert(u); + + if (!UNIT_VTABLE(u)->can_set_managed_oom || !u->manager) + return 0; + + crt = unit_get_cgroup_runtime(u); + if (!crt || !crt->cgroup_path) + return 0; + + if (MANAGER_IS_SYSTEM(u->manager)) { + /* In system mode we can't send any notifications unless oomd connected back to us. In this + * mode oomd must initiate communication, not us. */ + if (!u->manager->managed_oom_varlink) + return 0; + } else { + /* If we are in user mode, let's connect to oomd if we aren't connected yet. In this mode we + * must initiate communication to oomd, not the other way round. */ + r = manager_varlink_managed_oom_connect(u->manager); + if (r <= 0) + return r; + } + + c = unit_get_cgroup_context(u); + if (!c) + return 0; + + r = sd_json_build(&arr, SD_JSON_BUILD_EMPTY_ARRAY); + if (r < 0) + return r; + + FOREACH_ELEMENT(i, managed_oom_mode_properties) { + _cleanup_(sd_json_variant_unrefp) sd_json_variant *e = NULL; + + r = build_managed_oom_json_array_element(u, *i, &e); + if (r < 0) + return r; + + r = sd_json_variant_append_array(&arr, e); + if (r < 0) + return r; + } + + r = sd_json_buildo(&v, SD_JSON_BUILD_PAIR("cgroups", SD_JSON_BUILD_VARIANT(arr))); + if (r < 0) + return r; + + if (MANAGER_IS_SYSTEM(u->manager)) + /* in system mode, oomd is our client, thus send out notifications as replies to the + * initiating method call from them. */ + r = sd_varlink_notify(u->manager->managed_oom_varlink, v); + else + /* in user mode, we are oomd's client, thus send out notifications as method calls that do + * not expect a reply. */ + r = sd_varlink_send(u->manager->managed_oom_varlink, "io.systemd.oom.ReportManagedOOMCGroups", v); + + return r; +} + static int vl_method_subscribe_managed_oom_cgroups( sd_varlink *link, sd_json_variant *parameters, @@ -261,24 +341,6 @@ static int vl_method_subscribe_managed_oom_cgroups( return sd_varlink_notify(m->managed_oom_varlink, v); } -static int manager_varlink_send_managed_oom_initial(Manager *m) { - _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; - int r; - - assert(m); - - if (MANAGER_IS_SYSTEM(m)) - return 0; - - assert(m->managed_oom_varlink); - - r = build_managed_oom_cgroups_json(m, &v); - if (r < 0) - return r; - - return sd_varlink_send(m->managed_oom_varlink, "io.systemd.oom.ReportManagedOOMCGroups", v); -} - static int vl_method_get_user_record(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { static const sd_json_dispatch_field dispatch_table[] = { @@ -589,70 +651,16 @@ static int manager_varlink_init_system(Manager *m) { return 1; } -static int vl_reply(sd_varlink *link, sd_json_variant *parameters, const char *error_id, sd_varlink_reply_flags_t flags, void *userdata) { - Manager *m = ASSERT_PTR(userdata); - int r; - - if (error_id) - log_debug("varlink systemd-oomd client error: %s", error_id); - - if (FLAGS_SET(flags, SD_VARLINK_REPLY_ERROR|SD_VARLINK_REPLY_LOCAL)) { - /* sd_varlink connection was closed, likely because of systemd-oomd restart. Let's try to - * reconnect and send the initial ManagedOOM update again. */ - - m->managed_oom_varlink = sd_varlink_unref(link); - - log_debug("Reconnecting to %s", VARLINK_ADDR_PATH_MANAGED_OOM_USER); - - r = manager_varlink_init(m); - if (r <= 0) - return r; - } - - return 0; -} - static int manager_varlink_init_user(Manager *m) { - _cleanup_(sd_varlink_close_unrefp) sd_varlink *link = NULL; - int r; - assert(m); - if (m->managed_oom_varlink) - return 1; - if (!MANAGER_IS_USER(m)) return 0; if (MANAGER_IS_TEST_RUN(m)) return 0; - r = sd_varlink_connect_address(&link, VARLINK_ADDR_PATH_MANAGED_OOM_USER); - if (r == -ENOENT) - return 0; - if (ERRNO_IS_NEG_DISCONNECT(r)) { - log_debug_errno(r, "systemd-oomd varlink socket isn't available, skipping user manager varlink setup: %m"); - return 0; - } - if (r < 0) - return log_error_errno(r, "Failed to connect to '%s': %m", VARLINK_ADDR_PATH_MANAGED_OOM_USER); - - sd_varlink_set_userdata(link, m); - - r = sd_varlink_bind_reply(link, vl_reply); - if (r < 0) - return r; - - r = sd_varlink_attach_event(link, m->event, EVENT_PRIORITY_IPC); - if (r < 0) - return log_error_errno(r, "Failed to attach varlink connection to event loop: %m"); - - m->managed_oom_varlink = TAKE_PTR(link); - - /* Queue the initial ManagedOOM update. */ - (void) manager_varlink_send_managed_oom_initial(m); - - return 1; + return manager_varlink_managed_oom_connect(m); } int manager_varlink_init(Manager *m) {