summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKristijan Gjoshev <crypter@mail.com>2020-02-01 18:27:08 +0100
committerAnita Zhang <the.anitazha@gmail.com>2020-11-05 10:59:33 -0800
commitacf24a1a84e9496e3feb09449f4cc43fe67a9a64 (patch)
tree4f0ea72d0e2f6b20aea5c51c489574c63ec0ef81
parentman: add <option> around default booleans in systemd.timer (diff)
downloadsystemd-acf24a1a84e9496e3feb09449f4cc43fe67a9a64.tar.xz
systemd-acf24a1a84e9496e3feb09449f4cc43fe67a9a64.zip
timer: add new feature FixedRandomDelay=
FixedRandomDelay=yes will use `siphash24(sd_id128_get_machine() || MANAGER_IS_SYSTEM(m) || getuid() || u->id)`, where || is concatenation, instead of a random number to choose a value between 0 and RandomizedDelaySec= as the timer delay. This essentially sets up a fixed, but seemingly random, offset for each timer iteration rather than having a random offset recalculated each time it fires. Closes #10355 Co-author: Anita Zhang <the.anitazha@gmail.com>
-rw-r--r--docs/TRANSIENT-SETTINGS.md1
-rw-r--r--man/org.freedesktop.systemd1.xml6
-rw-r--r--man/systemd.timer.xml12
-rw-r--r--src/core/dbus-timer.c4
-rw-r--r--src/core/load-fragment-gperf.gperf.m41
-rw-r--r--src/core/timer.c34
-rw-r--r--src/core/timer.h1
-rw-r--r--src/shared/bus-unit-util.c3
-rw-r--r--test/fuzz/fuzz-unit-file/directives.service1
-rw-r--r--test/fuzz/fuzz-unit-file/systemd-tmpfiles-clean.timer1
10 files changed, 62 insertions, 2 deletions
diff --git a/docs/TRANSIENT-SETTINGS.md b/docs/TRANSIENT-SETTINGS.md
index f0dc2ee20ff..50b9a42fa11 100644
--- a/docs/TRANSIENT-SETTINGS.md
+++ b/docs/TRANSIENT-SETTINGS.md
@@ -374,6 +374,7 @@ Most timer unit settings are available to transient units.
✓ RemainAfterElapse=
✓ AccuracySec=
✓ RandomizedDelaySec=
+✓ FixedRandomDelay=
Unit=
```
diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml
index c0e0f385b41..1f6bbc1a6ec 100644
--- a/man/org.freedesktop.systemd1.xml
+++ b/man/org.freedesktop.systemd1.xml
@@ -7211,6 +7211,8 @@ node /org/freedesktop/systemd1/unit/systemd_2dtmpfiles_2dclean_2etimer {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly t RandomizedDelayUSec = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly b FixedRandomDelay = ...;
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b Persistent = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b WakeSystem = ...;
@@ -7236,6 +7238,8 @@ node /org/freedesktop/systemd1/unit/systemd_2dtmpfiles_2dclean_2etimer {
<!--property RandomizedDelayUSec is not documented!-->
+ <!--property FixedRandomDelay is not documented!-->
+
<!--property Persistent is not documented!-->
<!--property WakeSystem is not documented!-->
@@ -7276,6 +7280,8 @@ node /org/freedesktop/systemd1/unit/systemd_2dtmpfiles_2dclean_2etimer {
<variablelist class="dbus-property" generated="True" extra-ref="RandomizedDelayUSec"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="FixedRandomDelay"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="Persistent"/>
<variablelist class="dbus-property" generated="True" extra-ref="WakeSystem"/>
diff --git a/man/systemd.timer.xml b/man/systemd.timer.xml
index 24c6dd50f89..c4698bf4dc9 100644
--- a/man/systemd.timer.xml
+++ b/man/systemd.timer.xml
@@ -269,6 +269,18 @@
</varlistentry>
<varlistentry>
+ <term><varname>FixedRandomDelay=</varname></term>
+
+ <listitem><para>Takes a boolean argument. If true, some amount of time between 0 and
+ <varname>RandomizedDelaySec=</varname> is chosen and added as the delay for each timer iteration. As this
+ delay will not be recalculated on each run, this effectively creates a fixed offset for each iteration.
+ The distribution between 0 and <varname>RandomizedDelaySec=</varname> is deterministic and based on
+ a combination of the machine ID, whether the timer is run by the user/system manager, the service manager's
+ user ID, and the timer's unit name. Has no effect if
+ <varname>RandomizedDelaySec=</varname> is set to 0. Defaults to <option>false</option>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><varname>OnClockChange=</varname></term>
<term><varname>OnTimezoneChange=</varname></term>
diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c
index da35fa86786..ee54ba87720 100644
--- a/src/core/dbus-timer.c
+++ b/src/core/dbus-timer.c
@@ -131,6 +131,7 @@ const sd_bus_vtable bus_timer_vtable[] = {
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Timer, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("AccuracyUSec", "t", bus_property_get_usec, offsetof(Timer, accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RandomizedDelayUSec", "t", bus_property_get_usec, offsetof(Timer, random_usec), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("FixedRandomDelay", "b", bus_property_get_bool, offsetof(Timer, fixed_random_delay), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Persistent", "b", bus_property_get_bool, offsetof(Timer, persistent), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("WakeSystem", "b", bus_property_get_bool, offsetof(Timer, wake_system), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RemainAfterElapse", "b", bus_property_get_bool, offsetof(Timer, remain_after_elapse), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -232,6 +233,9 @@ static int bus_timer_set_transient_property(
if (streq(name, "RandomizedDelayUSec"))
return bus_set_transient_usec(u, name, &t->random_usec, message, flags, error);
+ if (streq(name, "FixedRandomDelay"))
+ return bus_set_transient_bool(u, name, &t->fixed_random_delay, message, flags, error);
+
if (streq(name, "WakeSystem"))
return bus_set_transient_bool(u, name, &t->wake_system, message, flags, error);
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 063d8ba6b62..946862c398a 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -481,6 +481,7 @@ Timer.OnTimezoneChange, config_parse_bool,
Timer.Persistent, config_parse_bool, 0, offsetof(Timer, persistent)
Timer.WakeSystem, config_parse_bool, 0, offsetof(Timer, wake_system)
Timer.RemainAfterElapse, config_parse_bool, 0, offsetof(Timer, remain_after_elapse)
+Timer.FixedRandomDelay, config_parse_bool, 0, offsetof(Timer, fixed_random_delay)
Timer.AccuracySec, config_parse_sec, 0, offsetof(Timer, accuracy_usec)
Timer.RandomizedDelaySec, config_parse_sec, 0, offsetof(Timer, random_usec)
Timer.Unit, config_parse_trigger_unit, 0, 0
diff --git a/src/core/timer.c b/src/core/timer.c
index 94388f0727f..46669b6b141 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -169,6 +169,36 @@ static int timer_setup_persistent(Timer *t) {
return 0;
}
+static uint64_t timer_get_fixed_delay_hash(Timer *t) {
+ static const uint8_t hash_key[] = {
+ 0x51, 0x0a, 0xdb, 0x76, 0x29, 0x51, 0x42, 0xc2,
+ 0x80, 0x35, 0xea, 0xe6, 0x8e, 0x3a, 0x37, 0xbd
+ };
+
+ struct siphash state;
+ sd_id128_t machine_id;
+ uid_t uid;
+ int r;
+
+ assert(t);
+
+ uid = getuid();
+ r = sd_id128_get_machine(&machine_id);
+ if (r < 0) {
+ log_unit_debug_errno(UNIT(t), r,
+ "Failed to get machine ID for the fixed delay calculation, proceeding with 0: %m");
+ machine_id = SD_ID128_NULL;
+ }
+
+ siphash24_init(&state, hash_key);
+ siphash24_compress(&machine_id, sizeof(sd_id128_t), &state);
+ siphash24_compress_boolean(MANAGER_IS_SYSTEM(UNIT(t)->manager), &state);
+ siphash24_compress(&uid, sizeof(uid_t), &state);
+ siphash24_compress_string(UNIT(t)->id, &state);
+
+ return siphash24_finalize(&state);
+}
+
static int timer_load(Unit *u) {
Timer *t = TIMER(u);
int r;
@@ -215,6 +245,7 @@ static void timer_dump(Unit *u, FILE *f, const char *prefix) {
"%sWakeSystem: %s\n"
"%sAccuracy: %s\n"
"%sRemainAfterElapse: %s\n"
+ "%sFixedRandomDelay: %s\n"
"%sOnClockChange: %s\n"
"%sOnTimeZoneChange: %s\n",
prefix, timer_state_to_string(t->state),
@@ -224,6 +255,7 @@ static void timer_dump(Unit *u, FILE *f, const char *prefix) {
prefix, yes_no(t->wake_system),
prefix, format_timespan(buf, sizeof(buf), t->accuracy_usec, 1),
prefix, yes_no(t->remain_after_elapse),
+ prefix, yes_no(t->fixed_random_delay),
prefix, yes_no(t->on_clock_change),
prefix, yes_no(t->on_timezone_change));
@@ -332,7 +364,7 @@ static void add_random(Timer *t, usec_t *v) {
if (*v == USEC_INFINITY)
return;
- add = random_u64() % t->random_usec;
+ add = (t->fixed_random_delay ? timer_get_fixed_delay_hash(t) : random_u64()) % t->random_usec;
if (*v + add < *v) /* overflow */
*v = (usec_t) -2; /* Highest possible value, that is not USEC_INFINITY */
diff --git a/src/core/timer.h b/src/core/timer.h
index ab66a201adc..ce4046a2106 100644
--- a/src/core/timer.h
+++ b/src/core/timer.h
@@ -59,6 +59,7 @@ struct Timer {
bool remain_after_elapse;
bool on_clock_change;
bool on_timezone_change;
+ bool fixed_random_delay;
char *stamp_path;
};
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 79c2e0cf199..d1dc9e2e022 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -2074,7 +2074,8 @@ static int bus_append_timer_property(sd_bus_message *m, const char *field, const
"RemainAfterElapse",
"Persistent",
"OnTimezoneChange",
- "OnClockChange"))
+ "OnClockChange",
+ "FixedRandomDelay"))
return bus_append_parse_boolean(m, field, eq);
if (STR_IN_SET(field, "AccuracySec",
diff --git a/test/fuzz/fuzz-unit-file/directives.service b/test/fuzz/fuzz-unit-file/directives.service
index eebc89f5c23..30ce98687a4 100644
--- a/test/fuzz/fuzz-unit-file/directives.service
+++ b/test/fuzz/fuzz-unit-file/directives.service
@@ -175,6 +175,7 @@ PipeSize=
Priority=
PropagatesReloadTo=
RandomizedDelaySec=
+FixedRandomDelay=
RebootArgument=
ReceiveBuffer=
RefuseManualStart=
diff --git a/test/fuzz/fuzz-unit-file/systemd-tmpfiles-clean.timer b/test/fuzz/fuzz-unit-file/systemd-tmpfiles-clean.timer
index 7db361cd69b..64b8808adc3 100644
--- a/test/fuzz/fuzz-unit-file/systemd-tmpfiles-clean.timer
+++ b/test/fuzz/fuzz-unit-file/systemd-tmpfiles-clean.timer
@@ -32,6 +32,7 @@ OnCalendar=Fri 2012-11-23 11:12:13
Persistent=true
AccuracySec=24h
RandomizedDelaySec=234234234
+FixedRandomDelay=true
Persistent=no
Unit=foo.service