From 47dba9fb091cc6fa8ae8ea1d2d6b0652ec84f765 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Sat, 18 Dec 2021 17:52:52 +0000 Subject: [PATCH] path unit: add TriggerLimitBurst= and TriggerLimitIntervalSec= Given there's now a default for these settings, also allow users to configure them, matching socket units --- man/org.freedesktop.systemd1.xml | 12 ++++++++++++ man/systemd.path.xml | 15 +++++++++++++++ src/core/dbus-path.c | 8 ++++++++ src/core/load-fragment-gperf.gperf.in | 2 ++ src/core/path.c | 22 ++++++++++++++++++---- src/shared/bus-unit-util.c | 6 ++++++ test/fuzz/fuzz-unit-file/directives.path | 2 ++ 7 files changed, 63 insertions(+), 4 deletions(-) diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml index be4c1282f5..7196f361e1 100644 --- a/man/org.freedesktop.systemd1.xml +++ b/man/org.freedesktop.systemd1.xml @@ -9357,6 +9357,10 @@ node /org/freedesktop/systemd1/unit/cups_2epath { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly u DirectoryMode = ...; readonly s Result = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly t TriggerLimitIntervalUSec = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly u TriggerLimitBurst = ...; }; interface org.freedesktop.DBus.Peer { ... }; interface org.freedesktop.DBus.Introspectable { ... }; @@ -9369,6 +9373,10 @@ node /org/freedesktop/systemd1/unit/cups_2epath { + + + + @@ -9389,6 +9397,10 @@ node /org/freedesktop/systemd1/unit/cups_2epath { + + + + diff --git a/man/systemd.path.xml b/man/systemd.path.xml index 44afba08c9..fd3d4efc2a 100644 --- a/man/systemd.path.xml +++ b/man/systemd.path.xml @@ -186,6 +186,21 @@ in question. Takes an access mode in octal notation. Defaults to . + + TriggerLimitIntervalSec= + TriggerLimitBurst= + + Configures a limit on how often this path unit may be activated within a specific time + interval. The TriggerLimitIntervalSec= may be used to configure the length of the time + interval in the usual time units us, ms, s, + min, h, … and defaults to 2s (See + systemd.time7 for details on + the various time units understood). The TriggerLimitBurst= setting takes a positive integer + value and specifies the number of permitted activations per time interval, and defaults to 200. Set either to + 0 to disable any form of trigger rate limiting. If the limit is hit, the unit is placed into a failure mode, + and will not watch the path(s) anymore until restarted. Note that this limit is enforced before the service + activation is enqueued. + diff --git a/src/core/dbus-path.c b/src/core/dbus-path.c index e025c31532..f143ad5d4a 100644 --- a/src/core/dbus-path.c +++ b/src/core/dbus-path.c @@ -49,6 +49,8 @@ const sd_bus_vtable bus_path_vtable[] = { SD_BUS_PROPERTY("MakeDirectory", "b", bus_property_get_bool, offsetof(Path, make_directory), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Path, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Path, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("TriggerLimitIntervalUSec", "t", bus_property_get_usec, offsetof(Path, trigger_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("TriggerLimitBurst", "u", bus_property_get_unsigned, offsetof(Path, trigger_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_VTABLE_END }; @@ -136,6 +138,12 @@ static int bus_path_set_transient_property( return 1; } + if (streq(name, "TriggerLimitBurst")) + return bus_set_transient_unsigned(u, name, &p->trigger_limit.burst, message, flags, error); + + if (streq(name, "TriggerLimitIntervalUSec")) + return bus_set_transient_usec(u, name, &p->trigger_limit.interval, message, flags, error); + return 0; } diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in index 6baa3b3b74..deea540e10 100644 --- a/src/core/load-fragment-gperf.gperf.in +++ b/src/core/load-fragment-gperf.gperf.in @@ -542,6 +542,8 @@ Path.DirectoryNotEmpty, config_parse_path_spec, Path.Unit, config_parse_trigger_unit, 0, 0 Path.MakeDirectory, config_parse_bool, 0, offsetof(Path, make_directory) Path.DirectoryMode, config_parse_mode, 0, offsetof(Path, directory_mode) +Path.TriggerLimitIntervalSec, config_parse_sec, 0, offsetof(Path, trigger_limit.interval) +Path.TriggerLimitBurst, config_parse_unsigned, 0, offsetof(Path, trigger_limit.burst) {{ CGROUP_CONTEXT_CONFIG_ITEMS('Slice') }} {{ CGROUP_CONTEXT_CONFIG_ITEMS('Scope') }} {{ KILL_CONTEXT_CONFIG_ITEMS('Scope') }} diff --git a/src/core/path.c b/src/core/path.c index f89e35a001..0b736f00bf 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -266,8 +266,8 @@ static void path_init(Unit *u) { p->directory_mode = 0755; - p->trigger_limit.interval = 2 * USEC_PER_SEC; - p->trigger_limit.burst = 200; + p->trigger_limit.interval = USEC_INFINITY; + p->trigger_limit.burst = UINT_MAX; } void path_free_specs(Path *p) { @@ -356,6 +356,16 @@ static int path_add_trigger_dependencies(Path *p) { static int path_add_extras(Path *p) { int r; + assert(p); + + /* To avoid getting pid1 in a busy-loop state (eg: failed condition on associated service), + * set a default trigger limit if the user didn't specify any. */ + if (p->trigger_limit.interval == USEC_INFINITY) + p->trigger_limit.interval = 2 * USEC_PER_SEC; + + if (p->trigger_limit.burst == UINT_MAX) + p->trigger_limit.burst = 200; + r = path_add_trigger_dependencies(p); if (r < 0) return r; @@ -403,12 +413,16 @@ static void path_dump(Unit *u, FILE *f, const char *prefix) { "%sResult: %s\n" "%sUnit: %s\n" "%sMakeDirectory: %s\n" - "%sDirectoryMode: %04o\n", + "%sDirectoryMode: %04o\n" + "%sTriggerLimitIntervalSec: %s\n" + "%sTriggerLimitBurst: %u\n", prefix, path_state_to_string(p->state), prefix, path_result_to_string(p->result), prefix, trigger ? trigger->id : "n/a", prefix, yes_no(p->make_directory), - prefix, p->directory_mode); + prefix, p->directory_mode, + prefix, FORMAT_TIMESPAN(p->trigger_limit.interval, USEC_PER_SEC), + prefix, p->trigger_limit.burst); LIST_FOREACH(spec, s, p->specs) path_spec_dump(s, f, prefix); diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index c58394e63e..dcce530c99 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -2113,6 +2113,12 @@ static int bus_append_path_property(sd_bus_message *m, const char *field, const return 1; } + if (streq(field, "TriggerLimitBurst")) + return bus_append_safe_atou(m, field, eq); + + if (streq(field, "TriggerLimitIntervalSec")) + return bus_append_parse_sec_rename(m, field, eq); + return 0; } diff --git a/test/fuzz/fuzz-unit-file/directives.path b/test/fuzz/fuzz-unit-file/directives.path index 213beff0f1..3c4df76b23 100644 --- a/test/fuzz/fuzz-unit-file/directives.path +++ b/test/fuzz/fuzz-unit-file/directives.path @@ -7,4 +7,6 @@ PathChanged= PathExists= PathExistsGlob= PathModified= +TriggerLimitBurst= +TriggerLimitIntervalSec= Unit=