diff --git a/0699-core-make-manager-event-loop-rate-limit-configurable.patch b/0699-core-make-manager-event-loop-rate-limit-configurable.patch new file mode 100644 index 0000000..cd6db46 --- /dev/null +++ b/0699-core-make-manager-event-loop-rate-limit-configurable.patch @@ -0,0 +1,256 @@ +From b084721752f93a3077df5b2d12ec3124f82dbc73 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Wed, 13 May 2026 16:20:55 +0200 +Subject: [PATCH] core: make manager event loop rate limit configurable + +Co-developed-by: Claude Opus 4.6 +(cherry picked from commit e1c63fd4c0657a7fc7b749c64283ab4dbc6fb39e) + +Resolves: RHEL-161564 +--- + man/org.freedesktop.systemd1.xml | 14 ++++++++++++++ + man/systemd-system.conf.xml | 17 +++++++++++++++++ + src/core/dbus-manager.c | 2 ++ + src/core/main.c | 32 ++++++++++++++++++++++++++++++++ + src/core/manager-serialize.c | 3 +++ + src/core/manager.c | 3 +-- + src/core/manager.h | 2 ++ + src/core/system.conf.in | 2 ++ + src/core/user.conf.in | 4 +++- + 9 files changed, 76 insertions(+), 3 deletions(-) + +diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml +index 0b6be4c755..cc50db7f77 100644 +--- a/man/org.freedesktop.systemd1.xml ++++ b/man/org.freedesktop.systemd1.xml +@@ -476,6 +476,10 @@ node /org/freedesktop/systemd1 { + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly b DefaultBlockIOAccounting = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") ++ readonly t EventLoopRateLimitIntervalUSec = ...; ++ @org.freedesktop.DBus.Property.EmitsChangedSignal("const") ++ readonly u EventLoopRateLimitBurst = ...; ++ @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly b DefaultIOAccounting = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly b DefaultIPAccounting = ...; +@@ -718,6 +722,10 @@ node /org/freedesktop/systemd1 { + + + ++ ++ ++ ++ + + + +@@ -1164,6 +1172,10 @@ node /org/freedesktop/systemd1 { + + + ++ ++ ++ ++ + + + +@@ -12241,6 +12253,8 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \ + ShutdownStartTimestamp, + ShutdownStartTimestampMonotonic, and + SoftRebootsCount were added in version 256. ++ EventLoopRateLimitIntervalUSec, and ++ EventLoopRateLimitBurst were added in version 261. + + + Unit Objects +diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml +index 23d09cfb37..1c71e54457 100644 +--- a/man/systemd-system.conf.xml ++++ b/man/systemd-system.conf.xml +@@ -625,6 +625,23 @@ + + + ++ ++ ++ EventLoopRateLimitIntervalSec= ++ EventLoopRateLimitBurst= ++ ++ Configures the rate limiting applied to the manager's main event loop. If the event ++ loop iterates more than EventLoopRateLimitBurst= times within ++ EventLoopRateLimitIntervalSec=, event processing is briefly paused to prevent ++ excessive CPU usage. EventLoopRateLimitIntervalSec= defaults to 1s. ++ EventLoopRateLimitBurst= defaults to 50000. These settings can also be set on the ++ kernel command line via ++ systemd.event_loop_ratelimit_interval_sec= and ++ systemd.event_loop_ratelimit_burst=. ++ ++ ++ ++ + + + +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index d516f30c96..3be3a536fe 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -3144,6 +3144,8 @@ const sd_bus_vtable bus_manager_vtable[] = { + 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("EventLoopRateLimitIntervalUSec", "t", bus_property_get_usec, offsetof(Manager, event_loop_ratelimit.interval), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("EventLoopRateLimitBurst", "u", bus_property_get_unsigned, offsetof(Manager, event_loop_ratelimit.burst), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultIOAccounting", "b", bus_property_get_bool, offsetof(Manager, defaults.io_accounting), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultIPAccounting", "b", bus_property_get_bool, offsetof(Manager, defaults.ip_accounting), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultMemoryAccounting", "b", bus_property_get_bool, offsetof(Manager, defaults.memory_accounting), SD_BUS_VTABLE_PROPERTY_CONST), +diff --git a/src/core/main.c b/src/core/main.c +index 506bc00f1d..971ad50b7e 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -160,6 +160,8 @@ static void *arg_random_seed; + static size_t arg_random_seed_size; + static usec_t arg_reload_limit_interval_sec; + static unsigned arg_reload_limit_burst; ++static usec_t arg_event_loop_ratelimit_interval_sec; ++static unsigned arg_event_loop_ratelimit_burst; + + /* A copy of the original environment block */ + static char **saved_env = NULL; +@@ -569,6 +571,28 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat + return 0; + } + ++ } else if (proc_cmdline_key_streq(key, "systemd.event_loop_ratelimit_interval_sec")) { ++ ++ if (proc_cmdline_value_missing(key, value)) ++ return 0; ++ ++ r = parse_sec(value, &arg_event_loop_ratelimit_interval_sec); ++ if (r < 0) { ++ log_warning_errno(r, "Failed to parse systemd.event_loop_ratelimit_interval_sec= argument '%s', ignoring: %m", value); ++ return 0; ++ } ++ ++ } else if (proc_cmdline_key_streq(key, "systemd.event_loop_ratelimit_burst")) { ++ ++ if (proc_cmdline_value_missing(key, value)) ++ return 0; ++ ++ r = safe_atou(value, &arg_event_loop_ratelimit_burst); ++ if (r < 0) { ++ log_warning_errno(r, "Failed to parse systemd.event_loop_ratelimit_burst= argument '%s', ignoring: %m", value); ++ return 0; ++ } ++ + } else if (streq(key, "quiet") && !value) { + + if (arg_show_status == _SHOW_STATUS_INVALID) +@@ -833,6 +857,8 @@ static int parse_config_file(void) { + { "Manager", "DefaultOOMScoreAdjust", config_parse_oom_score_adjust, 0, NULL }, + { "Manager", "ReloadLimitIntervalSec", config_parse_sec, 0, &arg_reload_limit_interval_sec }, + { "Manager", "ReloadLimitBurst", config_parse_unsigned, 0, &arg_reload_limit_burst }, ++ { "Manager", "EventLoopRateLimitIntervalSec", config_parse_sec, 0, &arg_event_loop_ratelimit_interval_sec }, ++ { "Manager", "EventLoopRateLimitBurst", config_parse_unsigned, 0, &arg_event_loop_ratelimit_burst }, + #if ENABLE_SMACK + { "Manager", "DefaultSmackProcessLabel", config_parse_string, 0, &arg_defaults.smack_process_label }, + #else +@@ -918,6 +944,8 @@ static void set_manager_settings(Manager *m) { + * counter on every daemon-reload. */ + m->reload_reexec_ratelimit.interval = arg_reload_limit_interval_sec; + m->reload_reexec_ratelimit.burst = arg_reload_limit_burst; ++ m->event_loop_ratelimit.interval = arg_event_loop_ratelimit_interval_sec; ++ m->event_loop_ratelimit.burst = arg_event_loop_ratelimit_burst; + + manager_set_watchdog(m, WATCHDOG_RUNTIME, arg_runtime_watchdog); + manager_set_watchdog(m, WATCHDOG_REBOOT, arg_reboot_watchdog); +@@ -2776,6 +2804,10 @@ static void reset_arguments(void) { + + arg_reload_limit_interval_sec = 0; + arg_reload_limit_burst = 0; ++ ++ arg_event_loop_ratelimit_interval_sec = 1 * USEC_PER_SEC; ++ arg_event_loop_ratelimit_burst = 50000; ++ + } + + static void determine_default_oom_score_adjust(void) { +diff --git a/src/core/manager-serialize.c b/src/core/manager-serialize.c +index b225799ed9..a0923b2203 100644 +--- a/src/core/manager-serialize.c ++++ b/src/core/manager-serialize.c +@@ -157,6 +157,7 @@ int manager_serialize( + + (void) serialize_ratelimit(f, "dump-ratelimit", &m->dump_ratelimit); + (void) serialize_ratelimit(f, "reload-reexec-ratelimit", &m->reload_reexec_ratelimit); ++ (void) serialize_ratelimit(f, "event-loop-ratelimit", &m->event_loop_ratelimit); + + (void) serialize_id128(f, "bus-id", m->bus_id); + bus_track_serialize(m->subscribed, f, "subscribed"); +@@ -523,6 +524,8 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { + deserialize_ratelimit(&m->dump_ratelimit, "dump-ratelimit", val); + else if ((val = startswith(l, "reload-reexec-ratelimit="))) + deserialize_ratelimit(&m->reload_reexec_ratelimit, "reload-reexec-ratelimit", val); ++ else if ((val = startswith(l, "event-loop-ratelimit="))) ++ deserialize_ratelimit(&m->event_loop_ratelimit, "event-loop-ratelimit", val); + else if ((val = startswith(l, "soft-reboots-count="))) { + unsigned n; + +diff --git a/src/core/manager.c b/src/core/manager.c +index 22efab33df..ef17f873b4 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -3412,7 +3412,6 @@ static int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t use + } + + int manager_loop(Manager *m) { +- RateLimit rl = { .interval = 1*USEC_PER_SEC, .burst = 50000 }; + int r; + + assert(m); +@@ -3429,7 +3428,7 @@ int manager_loop(Manager *m) { + + (void) watchdog_ping(); + +- if (!ratelimit_below(&rl)) { ++ if (!ratelimit_below(&m->event_loop_ratelimit)) { + /* Yay, something is going seriously wrong, pause a little */ + log_warning("Looping too fast. Throttling execution a little."); + sleep(1); +diff --git a/src/core/manager.h b/src/core/manager.h +index 66ad04baf5..63726f70ab 100644 +--- a/src/core/manager.h ++++ b/src/core/manager.h +@@ -504,6 +504,8 @@ struct Manager { + RateLimit dump_ratelimit; + + sd_event_source *memory_pressure_event_source; ++ /* Rate limit for the manager event loop */ ++ RateLimit event_loop_ratelimit; + + /* For NFTSet= */ + FirewallContext *fw_ctx; +diff --git a/src/core/system.conf.in b/src/core/system.conf.in +index 4fe420c344..f095d5bf8e 100644 +--- a/src/core/system.conf.in ++++ b/src/core/system.conf.in +@@ -82,3 +82,5 @@ + #DefaultSmackProcessLabel= + #ReloadLimitIntervalSec= + #ReloadLimitBurst= ++#EventLoopRateLimitIntervalSec=1s ++#EventLoopRateLimitBurst=50000 +diff --git a/src/core/user.conf.in b/src/core/user.conf.in +index 14f0eae7f8..fa81824c65 100644 +--- a/src/core/user.conf.in ++++ b/src/core/user.conf.in +@@ -56,4 +56,6 @@ + #DefaultMemoryPressureWatch=auto + #DefaultSmackProcessLabel= + #ReloadLimitIntervalSec= +-#ReloadLimitBurst ++#ReloadLimitBurst= ++#EventLoopRateLimitIntervalSec=1s ++#EventLoopRateLimitBurst=50000 diff --git a/systemd.spec b/systemd.spec index e90c715..d7d921d 100644 --- a/systemd.spec +++ b/systemd.spec @@ -48,7 +48,7 @@ Url: https://systemd.io # Allow users to specify the version and release when building the rpm by # setting the %%version_override and %%release_override macros. Version: %{?version_override}%{!?version_override:257} -Release: 30%{?dist} +Release: 31%{?dist} %global stable %(c="%version"; [ "$c" = "${c#*.*}" ]; echo $?) @@ -808,6 +808,7 @@ Patch0695: 0695-TEST-87-AUX-UTILS-VM-make-coredumps-stored-in-archiv.patch Patch0696: 0696-TEST-87-AUX-UTILS-VM-rotate-journal-at-one-more-plac.patch Patch0697: 0697-udev-rules-add-missing-device-name-prefix-in-log-mes.patch Patch0698: 0698-nss-systemd-avoid-ELF-TLS-for-recursion-guard.patch +Patch0699: 0699-core-make-manager-event-loop-rate-limit-configurable.patch # Downstream-only patches (9000–9999) %endif @@ -1759,6 +1760,9 @@ rm -f .file-list-* rm -f %{name}.lang %changelog +* Mon Jul 27 2026 systemd maintenance team - 257-31 +- core: make manager event loop rate limit configurable (RHEL-161564) + * Thu Jul 16 2026 systemd maintenance team - 257-30 - nss-systemd: avoid ELF TLS for recursion guard (RHEL-186510)