From 592caf0437e6ba4a6b3bcfa0c36d347380582c10 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Mar 16 2021 04:10:44 +0000 Subject: import systemd-239-45.el8 --- diff --git a/SOURCES/0544-Revert-test-add-test-cases-for-empty-string-match-an.patch b/SOURCES/0544-Revert-test-add-test-cases-for-empty-string-match-an.patch new file mode 100644 index 0000000..fcfec2d --- /dev/null +++ b/SOURCES/0544-Revert-test-add-test-cases-for-empty-string-match-an.patch @@ -0,0 +1,123 @@ +From b05c8d2e10c773b9bcae17055be48a2291ca6fa6 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Tue, 2 Mar 2021 12:57:59 -0500 +Subject: [PATCH] Revert "test: add test cases for empty string match" and + "test: add test case for multi matches when use ||" + +This effectively reverts commits 03bc565e6e3249385c4e1ca0ae27670ca2ad9a41 +and 03b766cc937ffa4dcb7cfb25b2ac20d8a00cb6db. + +Resolves: #1931947 +--- + test/udev-test.pl | 98 ----------------------------------------------- + 1 file changed, 98 deletions(-) + +diff --git a/test/udev-test.pl b/test/udev-test.pl +index 5b1e33504e..0612859cda 100755 +--- a/test/udev-test.pl ++++ b/test/udev-test.pl +@@ -1732,104 +1732,6 @@ KERNEL=="dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong1" + KERNEL=="X|attyACM0|dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong2" + KERNEL=="all|dontknow|ttyACM0", SYMLINK+="right" + KERNEL=="ttyACM0a|nothing", SYMLINK+="wrong3" +-EOF +- }, +- { +- desc => "test multi matches 5", +- devices => [ +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", +- exp_links => ["found"], +- not_exp_name => "bad", +- }], +- rules => < "test multi matches 6", +- devices => [ +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", +- exp_links => ["found"], +- not_exp_name => "bad", +- }], +- rules => < "test multi matches 7", +- devices => [ +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", +- exp_links => ["found"], +- not_exp_name => "bad", +- }], +- rules => < "test multi matches 8", +- devices => [ +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", +- exp_links => ["found"], +- not_exp_name => "bad", +- }], +- rules => < "test multi matches 9", +- devices => [ +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", +- exp_links => ["found"], +- not_exp_name => "bad", +- }], +- rules => < "test multi matches 10", +- devices => [ +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", +- exp_links => ["found"], +- not_exp_name => "bad", +- }], +- rules => < "test multi matches 11", +- devices => [ +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", +- exp_links => ["found"], +- not_exp_name => "bad", +- }], +- rules => < +Date: Tue, 24 Apr 2018 21:40:23 +0200 +Subject: [PATCH] test/sys-script.py: add missing DEVNAME entries to uevents + +Resolves: #1931947 +--- + test/sys-script.py | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/test/sys-script.py b/test/sys-script.py +index a51112603e..f4a847e356 100755 +--- a/test/sys-script.py ++++ b/test/sys-script.py +@@ -11677,6 +11677,7 @@ f('sys/devices/pci0000:00/0000:00:1d.7/usb5/5-1/5-1:1.0/host7/target7:0:0/7:0:0: + f('sys/devices/pci0000:00/0000:00:1d.7/usb5/5-1/5-1:1.0/host7/target7:0:0/7:0:0:0/block/sdb/uevent', 0o644, b'''MAJOR=8 + MINOR=16 + DEVTYPE=disk ++DEVNAME=sdb + ''') + d('sys/devices/pci0000:00/0000:00:1d.7/usb5/5-1/5-1:1.0/host7/target7:0:0/7:0:0:0/block/sdb/queue', 0o755) + l('sys/devices/pci0000:00/0000:00:1d.7/usb5/5-1/5-1:1.0/host7/target7:0:0/7:0:0:0/block/sdb/queue/bsg', '../../../bsg/7:0:0:0') +@@ -11709,6 +11710,7 @@ f('sys/devices/pci0000:00/0000:00:1d.7/usb5/5-1/5-1:1.0/host7/target7:0:0/7:0:0: + f('sys/devices/pci0000:00/0000:00:1d.7/usb5/5-1/5-1:1.0/host7/target7:0:0/7:0:0:0/block/sdb/sdb1/uevent', 0o644, b'''MAJOR=8 + MINOR=17 + DEVTYPE=partition ++DEVNAME=sdb1 + ''') + d('sys/devices/pci0000:00/0000:00:1d.7/usb5/5-1/5-1:1.0/host7/target7:0:0/7:0:0:0/block/sdb/sdb1/power', 0o755) + f('sys/devices/pci0000:00/0000:00:1d.7/usb5/5-1/5-1:1.0/host7/target7:0:0/7:0:0:0/block/sdb/sdb1/power/wakeup', 0o644, b'\n') +@@ -13150,6 +13152,7 @@ f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda10 + f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda10/uevent', 0o644, b'''MAJOR=8 + MINOR=10 + DEVTYPE=partition ++DEVNAME=sda10 + ''') + d('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda10/power', 0o755) + f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda10/power/wakeup', 0o644, b'\n') +@@ -13163,6 +13166,7 @@ f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda9/ + f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda9/uevent', 0o644, b'''MAJOR=8 + MINOR=9 + DEVTYPE=partition ++DEVNAME=sda9 + ''') + d('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda9/holders', 0o755) + l('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda9/holders/md0', '../../../../../../../../../virtual/block/md0') +@@ -13178,6 +13182,7 @@ f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda7/ + f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda7/uevent', 0o644, b'''MAJOR=8 + MINOR=7 + DEVTYPE=partition ++DEVNAME=sda7 + ''') + d('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda7/power', 0o755) + f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda7/power/wakeup', 0o644, b'\n') +@@ -13205,6 +13210,7 @@ f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda8/ + f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda8/uevent', 0o644, b'''MAJOR=8 + MINOR=8 + DEVTYPE=partition ++DEVNAME=sda8 + ''') + d('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda8/power', 0o755) + f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda8/power/wakeup', 0o644, b'\n') +@@ -13232,6 +13238,7 @@ f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda6/ + f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda6/uevent', 0o644, b'''MAJOR=8 + MINOR=6 + DEVTYPE=partition ++DEVNAME=sda6 + ''') + d('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda6/power', 0o755) + f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda6/power/wakeup', 0o644, b'\n') diff --git a/SOURCES/0546-sd-event-split-out-helper-functions-for-reshuffling-.patch b/SOURCES/0546-sd-event-split-out-helper-functions-for-reshuffling-.patch new file mode 100644 index 0000000..afc2d7e --- /dev/null +++ b/SOURCES/0546-sd-event-split-out-helper-functions-for-reshuffling-.patch @@ -0,0 +1,207 @@ +From 4ce10f8e41a85a56ad9b805442eb1149ece7c82a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20Sekleta=CC=81r?= +Date: Fri, 23 Oct 2020 18:29:27 +0200 +Subject: [PATCH] sd-event: split out helper functions for reshuffling prioqs + +We typically don't just reshuffle a single prioq at once, but always +two. Let's add two helper functions that do this, and reuse them +everywhere. + +(Note that this drops one minor optimization: +sd_event_source_set_time_accuracy() previously only reshuffled the +"latest" prioq, since changing the accuracy has no effect on the +earliest time of an event source, just the latest time an event source +can run. This optimization is removed to simplify things, given that +it's not really worth the effort as prioq_reshuffle() on properly +ordered prioqs has practically zero cost O(1)). + +(Slightly generalized, commented and split out of #17284 by Lennart) + +(cherry picked from commit e1951c16a8fbe5b0b9ecc08f4f835a806059d28f) + +Related: #1819868 +--- + src/libsystemd/sd-event/sd-event.c | 96 ++++++++++++------------------ + 1 file changed, 38 insertions(+), 58 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 0d3bf5cbb6..47f99eb096 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -889,6 +889,33 @@ static void event_gc_signal_data(sd_event *e, const int64_t *priority, int sig) + event_unmask_signal_data(e, d, sig); + } + ++static void event_source_pp_prioq_reshuffle(sd_event_source *s) { ++ assert(s); ++ ++ /* Reshuffles the pending + prepare prioqs. Called whenever the dispatch order changes, i.e. when ++ * they are enabled/disabled or marked pending and such. */ ++ ++ if (s->pending) ++ prioq_reshuffle(s->event->pending, s, &s->pending_index); ++ ++ if (s->prepare) ++ prioq_reshuffle(s->event->prepare, s, &s->prepare_index); ++} ++ ++static void event_source_time_prioq_reshuffle(sd_event_source *s) { ++ struct clock_data *d; ++ ++ assert(s); ++ assert(EVENT_SOURCE_IS_TIME(s->type)); ++ ++ /* Called whenever the event source's timer ordering properties changed, i.e. time, accuracy, ++ * pending, enable state. Makes sure the two prioq's are ordered properly again. */ ++ assert_se(d = event_get_clock_data(s->event, s->type)); ++ prioq_reshuffle(d->earliest, s, &s->time.earliest_index); ++ prioq_reshuffle(d->latest, s, &s->time.latest_index); ++ d->needs_rearm = true; ++} ++ + static void source_disconnect(sd_event_source *s) { + sd_event *event; + +@@ -1052,16 +1079,8 @@ static int source_set_pending(sd_event_source *s, bool b) { + } else + assert_se(prioq_remove(s->event->pending, s, &s->pending_index)); + +- if (EVENT_SOURCE_IS_TIME(s->type)) { +- struct clock_data *d; +- +- d = event_get_clock_data(s->event, s->type); +- assert(d); +- +- prioq_reshuffle(d->earliest, s, &s->time.earliest_index); +- prioq_reshuffle(d->latest, s, &s->time.latest_index); +- d->needs_rearm = true; +- } ++ if (EVENT_SOURCE_IS_TIME(s->type)) ++ event_source_time_prioq_reshuffle(s); + + if (s->type == SOURCE_SIGNAL && !b) { + struct signal_data *d; +@@ -2215,11 +2234,7 @@ _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority) + } else + s->priority = priority; + +- if (s->pending) +- prioq_reshuffle(s->event->pending, s, &s->pending_index); +- +- if (s->prepare) +- prioq_reshuffle(s->event->prepare, s, &s->prepare_index); ++ event_source_pp_prioq_reshuffle(s); + + if (s->type == SOURCE_EXIT) + prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); +@@ -2280,18 +2295,10 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { + case SOURCE_TIME_BOOTTIME: + case SOURCE_TIME_MONOTONIC: + case SOURCE_TIME_REALTIME_ALARM: +- case SOURCE_TIME_BOOTTIME_ALARM: { +- struct clock_data *d; +- ++ case SOURCE_TIME_BOOTTIME_ALARM: + s->enabled = m; +- d = event_get_clock_data(s->event, s->type); +- assert(d); +- +- prioq_reshuffle(d->earliest, s, &s->time.earliest_index); +- prioq_reshuffle(d->latest, s, &s->time.latest_index); +- d->needs_rearm = true; ++ event_source_time_prioq_reshuffle(s); + break; +- } + + case SOURCE_SIGNAL: + s->enabled = m; +@@ -2346,18 +2353,10 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { + case SOURCE_TIME_BOOTTIME: + case SOURCE_TIME_MONOTONIC: + case SOURCE_TIME_REALTIME_ALARM: +- case SOURCE_TIME_BOOTTIME_ALARM: { +- struct clock_data *d; +- ++ case SOURCE_TIME_BOOTTIME_ALARM: + s->enabled = m; +- d = event_get_clock_data(s->event, s->type); +- assert(d); +- +- prioq_reshuffle(d->earliest, s, &s->time.earliest_index); +- prioq_reshuffle(d->latest, s, &s->time.latest_index); +- d->needs_rearm = true; ++ event_source_time_prioq_reshuffle(s); + break; +- } + + case SOURCE_SIGNAL: + +@@ -2405,11 +2404,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { + } + } + +- if (s->pending) +- prioq_reshuffle(s->event->pending, s, &s->pending_index); +- +- if (s->prepare) +- prioq_reshuffle(s->event->prepare, s, &s->prepare_index); ++ event_source_pp_prioq_reshuffle(s); + + return 0; + } +@@ -2425,7 +2420,6 @@ _public_ int sd_event_source_get_time(sd_event_source *s, uint64_t *usec) { + } + + _public_ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) { +- struct clock_data *d; + int r; + + assert_return(s, -EINVAL); +@@ -2439,13 +2433,7 @@ _public_ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) { + + s->time.next = usec; + +- d = event_get_clock_data(s->event, s->type); +- assert(d); +- +- prioq_reshuffle(d->earliest, s, &s->time.earliest_index); +- prioq_reshuffle(d->latest, s, &s->time.latest_index); +- d->needs_rearm = true; +- ++ event_source_time_prioq_reshuffle(s); + return 0; + } + +@@ -2460,7 +2448,6 @@ _public_ int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *use + } + + _public_ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec) { +- struct clock_data *d; + int r; + + assert_return(s, -EINVAL); +@@ -2478,12 +2465,7 @@ _public_ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec + + s->time.accuracy = usec; + +- d = event_get_clock_data(s->event, s->type); +- assert(d); +- +- prioq_reshuffle(d->latest, s, &s->time.latest_index); +- d->needs_rearm = true; +- ++ event_source_time_prioq_reshuffle(s); + return 0; + } + +@@ -2773,9 +2755,7 @@ static int process_timer( + if (r < 0) + return r; + +- prioq_reshuffle(d->earliest, s, &s->time.earliest_index); +- prioq_reshuffle(d->latest, s, &s->time.latest_index); +- d->needs_rearm = true; ++ event_source_time_prioq_reshuffle(s); + } + + return 0; diff --git a/SOURCES/0547-sd-event-split-out-enable-and-disable-codepaths-from.patch b/SOURCES/0547-sd-event-split-out-enable-and-disable-codepaths-from.patch new file mode 100644 index 0000000..040b83f --- /dev/null +++ b/SOURCES/0547-sd-event-split-out-enable-and-disable-codepaths-from.patch @@ -0,0 +1,306 @@ +From d7ad6ad123200f562081ff09f7bed3c6d969ac0a Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 23 Oct 2020 21:21:58 +0200 +Subject: [PATCH] sd-event: split out enable and disable codepaths from + sd_event_source_set_enabled() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +So far half of sd_event_source_set_enabled() was doing enabling, the +other half was doing disabling. Let's split that into two separate +calls. + +(This also adds a new shortcut to sd_event_source_set_enabled(): if the +caller toggles between "ON" and "ONESHOT" we'll now shortcut this, since +the event source is already enabled in that case and shall remain +enabled.) + +This heavily borrows and is inspired from Michal Sekletár's #17284 +refactoring. + +(cherry picked from commit ddfde737b546c17e54182028153aa7f7e78804e3) + +Related: #1819868 +--- + src/libsystemd/sd-event/sd-event.c | 227 +++++++++++++++-------------- + 1 file changed, 121 insertions(+), 106 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 47f99eb096..df5ed0dce8 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -2260,152 +2260,167 @@ _public_ int sd_event_source_get_enabled(sd_event_source *s, int *m) { + return 0; + } + +-_public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { ++static int event_source_disable(sd_event_source *s) { + int r; + +- assert_return(s, -EINVAL); +- assert_return(IN_SET(m, SD_EVENT_OFF, SD_EVENT_ON, SD_EVENT_ONESHOT), -EINVAL); +- assert_return(!event_pid_changed(s->event), -ECHILD); ++ assert(s); ++ assert(s->enabled != SD_EVENT_OFF); + +- /* If we are dead anyway, we are fine with turning off +- * sources, but everything else needs to fail. */ +- if (s->event->state == SD_EVENT_FINISHED) +- return m == SD_EVENT_OFF ? 0 : -ESTALE; ++ /* Unset the pending flag when this event source is disabled */ ++ if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { ++ r = source_set_pending(s, false); ++ if (r < 0) ++ return r; ++ } + +- if (s->enabled == m) +- return 0; ++ s->enabled = SD_EVENT_OFF; + +- if (m == SD_EVENT_OFF) { ++ switch (s->type) { + +- /* Unset the pending flag when this event source is disabled */ +- if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { +- r = source_set_pending(s, false); +- if (r < 0) +- return r; +- } ++ case SOURCE_IO: ++ source_io_unregister(s); ++ break; + +- switch (s->type) { ++ case SOURCE_TIME_REALTIME: ++ case SOURCE_TIME_BOOTTIME: ++ case SOURCE_TIME_MONOTONIC: ++ case SOURCE_TIME_REALTIME_ALARM: ++ case SOURCE_TIME_BOOTTIME_ALARM: ++ event_source_time_prioq_reshuffle(s); ++ break; + +- case SOURCE_IO: +- source_io_unregister(s); +- s->enabled = m; +- break; ++ case SOURCE_SIGNAL: ++ event_gc_signal_data(s->event, &s->priority, s->signal.sig); ++ break; + +- case SOURCE_TIME_REALTIME: +- case SOURCE_TIME_BOOTTIME: +- case SOURCE_TIME_MONOTONIC: +- case SOURCE_TIME_REALTIME_ALARM: +- case SOURCE_TIME_BOOTTIME_ALARM: +- s->enabled = m; +- event_source_time_prioq_reshuffle(s); +- break; ++ case SOURCE_CHILD: ++ assert(s->event->n_enabled_child_sources > 0); ++ s->event->n_enabled_child_sources--; + +- case SOURCE_SIGNAL: +- s->enabled = m; ++ event_gc_signal_data(s->event, &s->priority, SIGCHLD); ++ break; + +- event_gc_signal_data(s->event, &s->priority, s->signal.sig); +- break; ++ case SOURCE_EXIT: ++ prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); ++ break; + +- case SOURCE_CHILD: +- s->enabled = m; ++ case SOURCE_DEFER: ++ case SOURCE_POST: ++ case SOURCE_INOTIFY: ++ break; + +- assert(s->event->n_enabled_child_sources > 0); +- s->event->n_enabled_child_sources--; ++ default: ++ assert_not_reached("Wut? I shouldn't exist."); ++ } + +- event_gc_signal_data(s->event, &s->priority, SIGCHLD); +- break; ++ return 0; ++} + +- case SOURCE_EXIT: +- s->enabled = m; +- prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); +- break; ++static int event_source_enable(sd_event_source *s, int m) { ++ int r; + +- case SOURCE_DEFER: +- case SOURCE_POST: +- case SOURCE_INOTIFY: +- s->enabled = m; +- break; ++ assert(s); ++ assert(IN_SET(m, SD_EVENT_ON, SD_EVENT_ONESHOT)); ++ assert(s->enabled == SD_EVENT_OFF); + +- default: +- assert_not_reached("Wut? I shouldn't exist."); +- } ++ /* Unset the pending flag when this event source is enabled */ ++ if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { ++ r = source_set_pending(s, false); ++ if (r < 0) ++ return r; ++ } + +- } else { ++ s->enabled = m; + +- /* Unset the pending flag when this event source is enabled */ +- if (s->enabled == SD_EVENT_OFF && !IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { +- r = source_set_pending(s, false); +- if (r < 0) +- return r; ++ switch (s->type) { ++ ++ case SOURCE_IO: ++ r = source_io_register(s, m, s->io.events); ++ if (r < 0) { ++ s->enabled = SD_EVENT_OFF; ++ return r; + } + +- switch (s->type) { ++ break; + +- case SOURCE_IO: +- r = source_io_register(s, m, s->io.events); +- if (r < 0) +- return r; ++ case SOURCE_TIME_REALTIME: ++ case SOURCE_TIME_BOOTTIME: ++ case SOURCE_TIME_MONOTONIC: ++ case SOURCE_TIME_REALTIME_ALARM: ++ case SOURCE_TIME_BOOTTIME_ALARM: ++ event_source_time_prioq_reshuffle(s); ++ break; + +- s->enabled = m; +- break; ++ case SOURCE_SIGNAL: ++ r = event_make_signal_data(s->event, s->signal.sig, NULL); ++ if (r < 0) { ++ s->enabled = SD_EVENT_OFF; ++ event_gc_signal_data(s->event, &s->priority, s->signal.sig); ++ return r; ++ } + +- case SOURCE_TIME_REALTIME: +- case SOURCE_TIME_BOOTTIME: +- case SOURCE_TIME_MONOTONIC: +- case SOURCE_TIME_REALTIME_ALARM: +- case SOURCE_TIME_BOOTTIME_ALARM: +- s->enabled = m; +- event_source_time_prioq_reshuffle(s); +- break; ++ break; + +- case SOURCE_SIGNAL: ++ case SOURCE_CHILD: ++ s->event->n_enabled_child_sources++; + +- s->enabled = m; ++ r = event_make_signal_data(s->event, SIGCHLD, NULL); ++ if (r < 0) { ++ s->enabled = SD_EVENT_OFF; ++ s->event->n_enabled_child_sources--; ++ event_gc_signal_data(s->event, &s->priority, SIGCHLD); ++ return r; ++ } + +- r = event_make_signal_data(s->event, s->signal.sig, NULL); +- if (r < 0) { +- s->enabled = SD_EVENT_OFF; +- event_gc_signal_data(s->event, &s->priority, s->signal.sig); +- return r; +- } + +- break; ++ break; + +- case SOURCE_CHILD: ++ case SOURCE_EXIT: ++ prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); ++ break; + +- if (s->enabled == SD_EVENT_OFF) +- s->event->n_enabled_child_sources++; ++ case SOURCE_DEFER: ++ case SOURCE_POST: ++ case SOURCE_INOTIFY: ++ break; + +- s->enabled = m; ++ default: ++ assert_not_reached("Wut? I shouldn't exist."); ++ } + +- r = event_make_signal_data(s->event, SIGCHLD, NULL); +- if (r < 0) { +- s->enabled = SD_EVENT_OFF; +- s->event->n_enabled_child_sources--; +- event_gc_signal_data(s->event, &s->priority, SIGCHLD); +- return r; +- } ++ return 0; ++} + +- break; ++_public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { ++ int r; + +- case SOURCE_EXIT: +- s->enabled = m; +- prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); +- break; ++ assert_return(s, -EINVAL); ++ assert_return(IN_SET(m, SD_EVENT_OFF, SD_EVENT_ON, SD_EVENT_ONESHOT), -EINVAL); ++ assert_return(!event_pid_changed(s->event), -ECHILD); + +- case SOURCE_DEFER: +- case SOURCE_POST: +- case SOURCE_INOTIFY: +- s->enabled = m; +- break; ++ /* If we are dead anyway, we are fine with turning off sources, but everything else needs to fail. */ ++ if (s->event->state == SD_EVENT_FINISHED) ++ return m == SD_EVENT_OFF ? 0 : -ESTALE; + +- default: +- assert_not_reached("Wut? I shouldn't exist."); ++ if (s->enabled == m) /* No change? */ ++ return 0; ++ ++ if (m == SD_EVENT_OFF) ++ r = event_source_disable(s); ++ else { ++ if (s->enabled != SD_EVENT_OFF) { ++ /* Switching from "on" to "oneshot" or back? If that's the case, we can take a shortcut, the ++ * event source is already enabled after all. */ ++ s->enabled = m; ++ return 0; + } ++ ++ r = event_source_enable(s, m); + } ++ if (r < 0) ++ return r; + + event_source_pp_prioq_reshuffle(s); +- + return 0; + } + diff --git a/SOURCES/0548-sd-event-mention-that-two-debug-logged-events-are-ig.patch b/SOURCES/0548-sd-event-mention-that-two-debug-logged-events-are-ig.patch new file mode 100644 index 0000000..6ea67ca --- /dev/null +++ b/SOURCES/0548-sd-event-mention-that-two-debug-logged-events-are-ig.patch @@ -0,0 +1,37 @@ +From e8904b5b7957bfc9328f1ab8b6851c7b0d8920c9 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 23 Nov 2020 11:39:40 +0100 +Subject: [PATCH] sd-event: mention that two debug logged events are ignored + +(cherry picked from commit f80a5d6a86dc2346f406ee086ba179879afaab70) + +Related: #1819868 +--- + src/libsystemd/sd-event/sd-event.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index df5ed0dce8..0f507f18d8 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -596,8 +596,6 @@ static bool event_pid_changed(sd_event *e) { + } + + static void source_io_unregister(sd_event_source *s) { +- int r; +- + assert(s); + assert(s->type == SOURCE_IO); + +@@ -607,9 +605,8 @@ static void source_io_unregister(sd_event_source *s) { + if (!s->io.registered) + return; + +- r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL); +- if (r < 0) +- log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll: %m", ++ if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL) < 0) ++ log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll, ignoring: %m", + strna(s->description), event_source_type_to_string(s->type)); + + s->io.registered = false; diff --git a/SOURCES/0549-sd-event-split-clock-data-allocation-out-of-sd_event.patch b/SOURCES/0549-sd-event-split-clock-data-allocation-out-of-sd_event.patch new file mode 100644 index 0000000..6e512af --- /dev/null +++ b/SOURCES/0549-sd-event-split-clock-data-allocation-out-of-sd_event.patch @@ -0,0 +1,71 @@ +From 6cc0022115afbac9ac66c456b140601d90271687 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 23 Nov 2020 11:40:24 +0100 +Subject: [PATCH] sd-event: split clock data allocation out of + sd_event_add_time() + +Just some simple refactoring, that will make things easier for us later. +But it looks better this way even without the later function reuse. + +(cherry picked from commit 41c63f36c3352af8bebf03b6181f5d866431d0af) + +Related: #1819868 +--- + src/libsystemd/sd-event/sd-event.c | 34 ++++++++++++++++++++---------- + 1 file changed, 23 insertions(+), 11 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 0f507f18d8..dc78dc7291 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -1232,6 +1232,28 @@ static int time_exit_callback(sd_event_source *s, uint64_t usec, void *userdata) + return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata)); + } + ++static int setup_clock_data(sd_event *e, struct clock_data *d, clockid_t clock) { ++ int r; ++ ++ assert(d); ++ ++ if (d->fd < 0) { ++ r = event_setup_timer_fd(e, d, clock); ++ if (r < 0) ++ return r; ++ } ++ ++ r = prioq_ensure_allocated(&d->earliest, earliest_time_prioq_compare); ++ if (r < 0) ++ return r; ++ ++ r = prioq_ensure_allocated(&d->latest, latest_time_prioq_compare); ++ if (r < 0) ++ return r; ++ ++ return 0; ++} ++ + _public_ int sd_event_add_time( + sd_event *e, + sd_event_source **ret, +@@ -1265,20 +1287,10 @@ _public_ int sd_event_add_time( + d = event_get_clock_data(e, type); + assert(d); + +- r = prioq_ensure_allocated(&d->earliest, earliest_time_prioq_compare); +- if (r < 0) +- return r; +- +- r = prioq_ensure_allocated(&d->latest, latest_time_prioq_compare); ++ r = setup_clock_data(e, d, clock); + if (r < 0) + return r; + +- if (d->fd < 0) { +- r = event_setup_timer_fd(e, d, clock); +- if (r < 0) +- return r; +- } +- + s = source_new(e, !ret, type); + if (!s) + return -ENOMEM; diff --git a/SOURCES/0550-sd-event-split-out-code-to-add-remove-timer-event-so.patch b/SOURCES/0550-sd-event-split-out-code-to-add-remove-timer-event-so.patch new file mode 100644 index 0000000..0333f0d --- /dev/null +++ b/SOURCES/0550-sd-event-split-out-code-to-add-remove-timer-event-so.patch @@ -0,0 +1,112 @@ +From 88b2618e4de850060a1c5c22b049e6de0578fbb5 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 23 Nov 2020 15:25:35 +0100 +Subject: [PATCH] sd-event: split out code to add/remove timer event sources to + earliest/latest prioq + +Just some refactoring that makes code prettier, and will come handy +later, because we can reuse these functions at more places. + +(cherry picked from commit 1e45e3fecc303e7ae9946220c742f69675e99c34) + +Related: #1819868 +--- + src/libsystemd/sd-event/sd-event.c | 57 +++++++++++++++++++++--------- + 1 file changed, 41 insertions(+), 16 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index dc78dc7291..de9bb02059 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -913,6 +913,19 @@ static void event_source_time_prioq_reshuffle(sd_event_source *s) { + d->needs_rearm = true; + } + ++static void event_source_time_prioq_remove( ++ sd_event_source *s, ++ struct clock_data *d) { ++ ++ assert(s); ++ assert(d); ++ ++ prioq_remove(d->earliest, s, &s->time.earliest_index); ++ prioq_remove(d->latest, s, &s->time.latest_index); ++ s->time.earliest_index = s->time.latest_index = PRIOQ_IDX_NULL; ++ d->needs_rearm = true; ++} ++ + static void source_disconnect(sd_event_source *s) { + sd_event *event; + +@@ -937,13 +950,8 @@ static void source_disconnect(sd_event_source *s) { + case SOURCE_TIME_REALTIME_ALARM: + case SOURCE_TIME_BOOTTIME_ALARM: { + struct clock_data *d; +- +- d = event_get_clock_data(s->event, s->type); +- assert(d); +- +- prioq_remove(d->earliest, s, &s->time.earliest_index); +- prioq_remove(d->latest, s, &s->time.latest_index); +- d->needs_rearm = true; ++ assert_se(d = event_get_clock_data(s->event, s->type)); ++ event_source_time_prioq_remove(s, d); + break; + } + +@@ -1254,6 +1262,30 @@ static int setup_clock_data(sd_event *e, struct clock_data *d, clockid_t clock) + return 0; + } + ++static int event_source_time_prioq_put( ++ sd_event_source *s, ++ struct clock_data *d) { ++ ++ int r; ++ ++ assert(s); ++ assert(d); ++ ++ r = prioq_put(d->earliest, s, &s->time.earliest_index); ++ if (r < 0) ++ return r; ++ ++ r = prioq_put(d->latest, s, &s->time.latest_index); ++ if (r < 0) { ++ assert_se(prioq_remove(d->earliest, s, &s->time.earliest_index) > 0); ++ s->time.earliest_index = PRIOQ_IDX_NULL; ++ return r; ++ } ++ ++ d->needs_rearm = true; ++ return 0; ++} ++ + _public_ int sd_event_add_time( + sd_event *e, + sd_event_source **ret, +@@ -1284,8 +1316,7 @@ _public_ int sd_event_add_time( + if (!callback) + callback = time_exit_callback; + +- d = event_get_clock_data(e, type); +- assert(d); ++ assert_se(d = event_get_clock_data(e, type)); + + r = setup_clock_data(e, d, clock); + if (r < 0) +@@ -1302,13 +1333,7 @@ _public_ int sd_event_add_time( + s->userdata = userdata; + s->enabled = SD_EVENT_ONESHOT; + +- d->needs_rearm = true; +- +- r = prioq_put(d->earliest, s, &s->time.earliest_index); +- if (r < 0) +- goto fail; +- +- r = prioq_put(d->latest, s, &s->time.latest_index); ++ r = event_source_time_prioq_put(s, d); + if (r < 0) + goto fail; + diff --git a/SOURCES/0551-sd-event-fix-delays-assert-brain-o-17790.patch b/SOURCES/0551-sd-event-fix-delays-assert-brain-o-17790.patch new file mode 100644 index 0000000..64afc46 --- /dev/null +++ b/SOURCES/0551-sd-event-fix-delays-assert-brain-o-17790.patch @@ -0,0 +1,29 @@ +From 1aae57f763cacbdeb10647c627cf307f79ad00ca Mon Sep 17 00:00:00 2001 +From: Vito Caputo +Date: Tue, 1 Dec 2020 00:26:54 -0800 +Subject: [PATCH] sd-event: fix delays assert brain-o (#17790) + +s/sizeof/ELEMENTSOF/ + +Bug introduced in 34b87517749caa4142b19eb3c63bdf349fafbc49. + +(cherry picked from commit cb9d621ebbfa30bbd620c17e143daeb0d78c12f0) + +Related: #1819868 +--- + src/libsystemd/sd-event/sd-event.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index de9bb02059..9d42157206 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -3586,7 +3586,7 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { + this_run = now(CLOCK_MONOTONIC); + + l = u64log2(this_run - e->last_run); +- assert(l < sizeof(e->delays)); ++ assert(l < ELEMENTSOF(e->delays)); + e->delays[l]++; + + if (this_run - e->last_log >= 5*USEC_PER_SEC) { diff --git a/SOURCES/0552-sd-event-let-s-suffix-last_run-last_log-with-_usec.patch b/SOURCES/0552-sd-event-let-s-suffix-last_run-last_log-with-_usec.patch new file mode 100644 index 0000000..1393d01 --- /dev/null +++ b/SOURCES/0552-sd-event-let-s-suffix-last_run-last_log-with-_usec.patch @@ -0,0 +1,60 @@ +From 5b5a590c5a8bbaebbecf4ab4797334a09a870287 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 23 Nov 2020 15:33:50 +0100 +Subject: [PATCH] sd-event: let's suffix last_run/last_log with "_usec" + +Otherwise it's a bit confusing what this is about: two timestamps. + +(cherry picked from commit e6a7bee538f6638c2d5ca2afc66bf47cba3f075c) + +Related: #1819868 +--- + src/libsystemd/sd-event/sd-event.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 9d42157206..88641879cc 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -301,7 +301,7 @@ struct sd_event { + + LIST_HEAD(sd_event_source, sources); + +- usec_t last_run, last_log; ++ usec_t last_run_usec, last_log_usec; + unsigned delays[sizeof(usec_t) * 8]; + }; + +@@ -3579,19 +3579,19 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { + assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); + +- if (e->profile_delays && e->last_run) { ++ if (e->profile_delays && e->last_run_usec != 0) { + usec_t this_run; + unsigned l; + + this_run = now(CLOCK_MONOTONIC); + +- l = u64log2(this_run - e->last_run); ++ l = u64log2(this_run - e->last_run_usec); + assert(l < ELEMENTSOF(e->delays)); + e->delays[l]++; + +- if (this_run - e->last_log >= 5*USEC_PER_SEC) { ++ if (this_run - e->last_log_usec >= 5*USEC_PER_SEC) { + event_log_delays(e); +- e->last_log = this_run; ++ e->last_log_usec = this_run; + } + } + +@@ -3601,7 +3601,7 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { + r = sd_event_wait(e, timeout); + + if (e->profile_delays) +- e->last_run = now(CLOCK_MONOTONIC); ++ e->last_run_usec = now(CLOCK_MONOTONIC); + + if (r > 0) { + /* There's something now, then let's dispatch it */ diff --git a/SOURCES/0553-sd-event-refuse-running-default-event-loops-in-any-o.patch b/SOURCES/0553-sd-event-refuse-running-default-event-loops-in-any-o.patch new file mode 100644 index 0000000..95ad16f --- /dev/null +++ b/SOURCES/0553-sd-event-refuse-running-default-event-loops-in-any-o.patch @@ -0,0 +1,42 @@ +From 4c5fdbde7e745126f31542a70b45cc4faec094d2 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 30 Oct 2019 20:26:50 +0100 +Subject: [PATCH] sd-event: refuse running default event loops in any other + thread than the one they are default for + +(cherry picked from commit e544601536ac13a288d7476f4400c7b0f22b7ea1) + +Related: #1819868 +--- + TODO | 1 - + src/libsystemd/sd-event/sd-event.c | 5 +++++ + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/TODO b/TODO +index 8f78000089..3100e067d6 100644 +--- a/TODO ++++ b/TODO +@@ -581,7 +581,6 @@ Features: + - allow multiple signal handlers per signal? + - document chaining of signal handler for SIGCHLD and child handlers + - define more intervals where we will shift wakeup intervals around in, 1h, 6h, 24h, ... +- - generate a failure of a default event loop is executed out-of-thread + - maybe add support for inotify events (which we can do safely now, with O_PATH) + + * investigate endianness issues of UUID vs. GUID +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 88641879cc..537a0b81d4 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -3360,6 +3360,11 @@ _public_ int sd_event_prepare(sd_event *e) { + assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); + ++ /* Let's check that if we are a default event loop we are executed in the correct thread. We only do ++ * this check here once, since gettid() is typically not cached, and thus want to minimize ++ * syscalls */ ++ assert_return(!e->default_event_ptr || e->tid == gettid(), -EREMOTEIO); ++ + if (e->exit_requested) + goto pending; + diff --git a/SOURCES/0554-sd-event-ref-event-loop-while-in-sd_event_prepare-ot.patch b/SOURCES/0554-sd-event-ref-event-loop-while-in-sd_event_prepare-ot.patch new file mode 100644 index 0000000..4824f09 --- /dev/null +++ b/SOURCES/0554-sd-event-ref-event-loop-while-in-sd_event_prepare-ot.patch @@ -0,0 +1,92 @@ +From 441684c6c961edec1391562fb2f48ff997a6169e Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 23 Nov 2020 15:38:00 +0100 +Subject: [PATCH] sd-event: ref event loop while in sd_event_prepare() ot + sd_event_run() + +sd_event_prepare() invokes callbacks that might drop the last user ref +on our event loop. Let's make sure we keep an explicit ref around it, so +that we won't end up with an invalid pointer. Similar in sd_event_run(). + +Basically, any function that is publically callable that might end up +invoking callbacks should ref the relevant objects to be protected +against callbacks destroying these objects while we still want to access +them. We did this correctly in sd_event_dispatch() and sd_event_loop(), +but these are not the only ones which are callable from the outside. + +(cherry picked from commit f814c871e65df8552a055dd887bc94b074037833) + +Related: #1819868 +--- + src/libsystemd/sd-event/sd-event.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 537a0b81d4..be1e6e5f53 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -3256,7 +3256,6 @@ static int event_prepare(sd_event *e) { + + static int dispatch_exit(sd_event *e) { + sd_event_source *p; +- _cleanup_(sd_event_unrefp) sd_event *ref = NULL; + int r; + + assert(e); +@@ -3267,7 +3266,7 @@ static int dispatch_exit(sd_event *e) { + return 0; + } + +- ref = sd_event_ref(e); ++ _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); + e->iteration++; + e->state = SD_EVENT_EXITING; + r = source_dispatch(p); +@@ -3365,6 +3364,9 @@ _public_ int sd_event_prepare(sd_event *e) { + * syscalls */ + assert_return(!e->default_event_ptr || e->tid == gettid(), -EREMOTEIO); + ++ /* Make sure that none of the preparation callbacks ends up freeing the event source under our feet */ ++ _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); ++ + if (e->exit_requested) + goto pending; + +@@ -3549,9 +3551,8 @@ _public_ int sd_event_dispatch(sd_event *e) { + + p = event_next_pending(e); + if (p) { +- _cleanup_(sd_event_unrefp) sd_event *ref = NULL; ++ _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); + +- ref = sd_event_ref(e); + e->state = SD_EVENT_RUNNING; + r = source_dispatch(p); + e->state = SD_EVENT_INITIAL; +@@ -3600,6 +3601,9 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { + } + } + ++ /* Make sure that none of the preparation callbacks ends up freeing the event source under our feet */ ++ _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); ++ + r = sd_event_prepare(e); + if (r == 0) + /* There was nothing? Then wait... */ +@@ -3621,7 +3625,6 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { + } + + _public_ int sd_event_loop(sd_event *e) { +- _cleanup_(sd_event_unrefp) sd_event *ref = NULL; + int r; + + assert_return(e, -EINVAL); +@@ -3629,7 +3632,7 @@ _public_ int sd_event_loop(sd_event *e) { + assert_return(!event_pid_changed(e), -ECHILD); + assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); + +- ref = sd_event_ref(e); ++ _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = NULL; + + while (e->state != SD_EVENT_FINISHED) { + r = sd_event_run(e, (uint64_t) -1); diff --git a/SOURCES/0555-sd-event-follow-coding-style-with-naming-return-para.patch b/SOURCES/0555-sd-event-follow-coding-style-with-naming-return-para.patch new file mode 100644 index 0000000..ab585e0 --- /dev/null +++ b/SOURCES/0555-sd-event-follow-coding-style-with-naming-return-para.patch @@ -0,0 +1,35 @@ +From 846b1dd75e626ad2e2483673eea65774edea9016 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 23 Nov 2020 17:47:16 +0100 +Subject: [PATCH] sd-event: follow coding style with naming return parameter + +(cherry picked from commit cad143a8f26976a23e634d5e1ecfb7d7ba75c3bf) + +Related: #1819868 +--- + src/libsystemd/sd-event/sd-event.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index be1e6e5f53..739296abcf 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -2285,13 +2285,14 @@ fail: + return r; + } + +-_public_ int sd_event_source_get_enabled(sd_event_source *s, int *m) { ++_public_ int sd_event_source_get_enabled(sd_event_source *s, int *ret) { + assert_return(s, -EINVAL); +- assert_return(m, -EINVAL); + assert_return(!event_pid_changed(s->event), -ECHILD); + +- *m = s->enabled; +- return 0; ++ if (ret) ++ *ret = s->enabled; ++ ++ return s->enabled != SD_EVENT_OFF; + } + + static int event_source_disable(sd_event_source *s) { diff --git a/SOURCES/0556-sd-event-remove-earliest_index-latest_index-into-com.patch b/SOURCES/0556-sd-event-remove-earliest_index-latest_index-into-com.patch new file mode 100644 index 0000000..7fb9b47 --- /dev/null +++ b/SOURCES/0556-sd-event-remove-earliest_index-latest_index-into-com.patch @@ -0,0 +1,98 @@ +From 97f599bf57fdaee688ae5750e9b2b2587e2b597a Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 23 Nov 2020 17:49:27 +0100 +Subject: [PATCH] sd-event: remove earliest_index/latest_index into common part + of event source objects + +So far we used these fields to organize the earliest/latest timer event +priority queue. In a follow-up commit we want to introduce ratelimiting +to event sources, at which point we want any kind of event source to be +able to trigger time wakeups, and hence they all need to be included in +the earliest/latest prioqs. Thus, in preparation let's make this +generic. + +No change in behaviour, just some shifting around of struct members from +the type-specific to the generic part. + +(cherry picked from commit f41315fceb5208c496145cda2d6c865a5458ce44) + +Related: #1819868 +--- + src/libsystemd/sd-event/sd-event.c | 25 +++++++++++++------------ + 1 file changed, 13 insertions(+), 12 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 739296abcf..34b42c298f 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -107,6 +107,9 @@ struct sd_event_source { + + LIST_FIELDS(sd_event_source, sources); + ++ unsigned earliest_index; ++ unsigned latest_index; ++ + union { + struct { + sd_event_io_handler_t callback; +@@ -119,8 +122,6 @@ struct sd_event_source { + struct { + sd_event_time_handler_t callback; + usec_t next, accuracy; +- unsigned earliest_index; +- unsigned latest_index; + } time; + struct { + sd_event_signal_handler_t callback; +@@ -908,8 +909,8 @@ static void event_source_time_prioq_reshuffle(sd_event_source *s) { + /* Called whenever the event source's timer ordering properties changed, i.e. time, accuracy, + * pending, enable state. Makes sure the two prioq's are ordered properly again. */ + assert_se(d = event_get_clock_data(s->event, s->type)); +- prioq_reshuffle(d->earliest, s, &s->time.earliest_index); +- prioq_reshuffle(d->latest, s, &s->time.latest_index); ++ prioq_reshuffle(d->earliest, s, &s->earliest_index); ++ prioq_reshuffle(d->latest, s, &s->latest_index); + d->needs_rearm = true; + } + +@@ -920,9 +921,9 @@ static void event_source_time_prioq_remove( + assert(s); + assert(d); + +- prioq_remove(d->earliest, s, &s->time.earliest_index); +- prioq_remove(d->latest, s, &s->time.latest_index); +- s->time.earliest_index = s->time.latest_index = PRIOQ_IDX_NULL; ++ prioq_remove(d->earliest, s, &s->earliest_index); ++ prioq_remove(d->latest, s, &s->latest_index); ++ s->earliest_index = s->latest_index = PRIOQ_IDX_NULL; + d->needs_rearm = true; + } + +@@ -1271,14 +1272,14 @@ static int event_source_time_prioq_put( + assert(s); + assert(d); + +- r = prioq_put(d->earliest, s, &s->time.earliest_index); ++ r = prioq_put(d->earliest, s, &s->earliest_index); + if (r < 0) + return r; + +- r = prioq_put(d->latest, s, &s->time.latest_index); ++ r = prioq_put(d->latest, s, &s->latest_index); + if (r < 0) { +- assert_se(prioq_remove(d->earliest, s, &s->time.earliest_index) > 0); +- s->time.earliest_index = PRIOQ_IDX_NULL; ++ assert_se(prioq_remove(d->earliest, s, &s->earliest_index) > 0); ++ s->earliest_index = PRIOQ_IDX_NULL; + return r; + } + +@@ -1329,7 +1330,7 @@ _public_ int sd_event_add_time( + s->time.next = usec; + s->time.accuracy = accuracy == 0 ? DEFAULT_ACCURACY_USEC : accuracy; + s->time.callback = callback; +- s->time.earliest_index = s->time.latest_index = PRIOQ_IDX_NULL; ++ s->earliest_index = s->latest_index = PRIOQ_IDX_NULL; + s->userdata = userdata; + s->enabled = SD_EVENT_ONESHOT; + diff --git a/SOURCES/0557-sd-event-update-state-at-the-end-in-event_source_ena.patch b/SOURCES/0557-sd-event-update-state-at-the-end-in-event_source_ena.patch new file mode 100644 index 0000000..e0a2145 --- /dev/null +++ b/SOURCES/0557-sd-event-update-state-at-the-end-in-event_source_ena.patch @@ -0,0 +1,116 @@ +From deb9e6ad3a1d7cfbc3b53d1e74cda6ae398a90fd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 10 Nov 2020 10:38:37 +0100 +Subject: [PATCH] sd-event: update state at the end in event_source_enable + +Coverity in CID#1435966 was complaining that s->enabled is not "restored" in +all cases. But the code was actually correct, since it should only be +"restored" in the error paths. But let's still make this prettier by not setting +the state before all operations that may fail are done. + +We need to set .enabled for the prioq reshuffling operations, so move those down. + +No functional change intended. + +(cherry picked from commit d2eafe61ca07f8300dc741a0491a914213fa2b6b) + +Related: #1819868 +--- + src/libsystemd/sd-event/sd-event.c | 51 +++++++++++++++++------------- + 1 file changed, 29 insertions(+), 22 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 34b42c298f..0cfba8fb39 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -2352,11 +2352,11 @@ static int event_source_disable(sd_event_source *s) { + return 0; + } + +-static int event_source_enable(sd_event_source *s, int m) { ++static int event_source_enable(sd_event_source *s, int enable) { + int r; + + assert(s); +- assert(IN_SET(m, SD_EVENT_ON, SD_EVENT_ONESHOT)); ++ assert(IN_SET(enable, SD_EVENT_ON, SD_EVENT_ONESHOT)); + assert(s->enabled == SD_EVENT_OFF); + + /* Unset the pending flag when this event source is enabled */ +@@ -2366,31 +2366,16 @@ static int event_source_enable(sd_event_source *s, int m) { + return r; + } + +- s->enabled = m; +- + switch (s->type) { +- + case SOURCE_IO: +- r = source_io_register(s, m, s->io.events); +- if (r < 0) { +- s->enabled = SD_EVENT_OFF; ++ r = source_io_register(s, enable, s->io.events); ++ if (r < 0) + return r; +- } +- +- break; +- +- case SOURCE_TIME_REALTIME: +- case SOURCE_TIME_BOOTTIME: +- case SOURCE_TIME_MONOTONIC: +- case SOURCE_TIME_REALTIME_ALARM: +- case SOURCE_TIME_BOOTTIME_ALARM: +- event_source_time_prioq_reshuffle(s); + break; + + case SOURCE_SIGNAL: + r = event_make_signal_data(s->event, s->signal.sig, NULL); + if (r < 0) { +- s->enabled = SD_EVENT_OFF; + event_gc_signal_data(s->event, &s->priority, s->signal.sig); + return r; + } +@@ -2411,10 +2396,12 @@ static int event_source_enable(sd_event_source *s, int m) { + + break; + ++ case SOURCE_TIME_REALTIME: ++ case SOURCE_TIME_BOOTTIME: ++ case SOURCE_TIME_MONOTONIC: ++ case SOURCE_TIME_REALTIME_ALARM: ++ case SOURCE_TIME_BOOTTIME_ALARM: + case SOURCE_EXIT: +- prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); +- break; +- + case SOURCE_DEFER: + case SOURCE_POST: + case SOURCE_INOTIFY: +@@ -2424,6 +2411,26 @@ static int event_source_enable(sd_event_source *s, int m) { + assert_not_reached("Wut? I shouldn't exist."); + } + ++ s->enabled = enable; ++ ++ /* Non-failing operations below */ ++ switch (s->type) { ++ case SOURCE_TIME_REALTIME: ++ case SOURCE_TIME_BOOTTIME: ++ case SOURCE_TIME_MONOTONIC: ++ case SOURCE_TIME_REALTIME_ALARM: ++ case SOURCE_TIME_BOOTTIME_ALARM: ++ event_source_time_prioq_reshuffle(s); ++ break; ++ ++ case SOURCE_EXIT: ++ prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); ++ break; ++ ++ default: ++ break; ++ } ++ + return 0; + } + diff --git a/SOURCES/0558-sd-event-increase-n_enabled_child_sources-just-once.patch b/SOURCES/0558-sd-event-increase-n_enabled_child_sources-just-once.patch new file mode 100644 index 0000000..2a41752 --- /dev/null +++ b/SOURCES/0558-sd-event-increase-n_enabled_child_sources-just-once.patch @@ -0,0 +1,36 @@ +From 188465c472996b426a1f22a9fc46d031b722c3b4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 10 Nov 2020 12:57:34 +0100 +Subject: [PATCH] sd-event: increase n_enabled_child_sources just once + +Neither source_child_pidfd_register() nor event_make_signal_data() look at +n_enabled_child_sources. + +(cherry picked from commit ac9f2640cb9c107b43f47bba7e068d3b92b5337b) + +Related: #1819868 +--- + src/libsystemd/sd-event/sd-event.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 0cfba8fb39..d18ce28a92 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -2383,8 +2383,6 @@ static int event_source_enable(sd_event_source *s, int enable) { + break; + + case SOURCE_CHILD: +- s->event->n_enabled_child_sources++; +- + r = event_make_signal_data(s->event, SIGCHLD, NULL); + if (r < 0) { + s->enabled = SD_EVENT_OFF; +@@ -2393,6 +2391,7 @@ static int event_source_enable(sd_event_source *s, int enable) { + return r; + } + ++ s->event->n_enabled_child_sources++; + + break; + diff --git a/SOURCES/0559-sd-event-add-ability-to-ratelimit-event-sources.patch b/SOURCES/0559-sd-event-add-ability-to-ratelimit-event-sources.patch new file mode 100644 index 0000000..b8c20d0 --- /dev/null +++ b/SOURCES/0559-sd-event-add-ability-to-ratelimit-event-sources.patch @@ -0,0 +1,858 @@ +From 395eb7753a9772f505102fbbe3ba3261b57abbe9 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 23 Nov 2020 18:02:40 +0100 +Subject: [PATCH] sd-event: add ability to ratelimit event sources + +Let's a concept of "rate limiting" to event sources: if specific event +sources fire too often in some time interval temporarily take them +offline, and take them back online once the interval passed. + +This is a simple scheme of avoiding starvation of event sources if some +event source fires too often. + +This introduces the new conceptual states of "offline" and "online" for +event sources: an event source is "online" only when enabled *and* not +ratelimited, and offline in all other cases. An event source that is +online hence has its fds registered in the epoll, its signals in the +signalfd and so on. + +(cherry picked from commit b6d5481b3d9f7c9b1198ab54b54326ec73e855bf) + +Related: #1819868 +--- + src/basic/ratelimit.h | 8 + + src/libsystemd/libsystemd.sym | 7 + + src/libsystemd/sd-event/sd-event.c | 433 +++++++++++++++++++++++------ + src/systemd/sd-event.h | 3 + + 4 files changed, 369 insertions(+), 82 deletions(-) + +diff --git a/src/basic/ratelimit.h b/src/basic/ratelimit.h +index de91def28d..0012b49935 100644 +--- a/src/basic/ratelimit.h ++++ b/src/basic/ratelimit.h +@@ -38,3 +38,11 @@ typedef struct RateLimit { + } while (false) + + bool ratelimit_below(RateLimit *r); ++ ++static inline void ratelimit_reset(RateLimit *rl) { ++ rl->num = rl->begin = 0; ++} ++ ++static inline bool ratelimit_configured(RateLimit *rl) { ++ return rl->interval > 0 && rl->burst > 0; ++} +diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym +index 778e88a16c..149d2e7b82 100644 +--- a/src/libsystemd/libsystemd.sym ++++ b/src/libsystemd/libsystemd.sym +@@ -572,3 +572,10 @@ global: + sd_bus_enqueue_for_read; + sd_event_source_disable_unref; + } LIBSYSTEMD_238; ++ ++LIBSYSTEMD_248 { ++global: ++ sd_event_source_set_ratelimit; ++ sd_event_source_get_ratelimit; ++ sd_event_source_is_ratelimited; ++} LIBSYSTEMD_239; +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index d18ce28a92..be912d94e3 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -19,6 +19,7 @@ + #include "missing.h" + #include "prioq.h" + #include "process-util.h" ++#include "ratelimit.h" + #include "set.h" + #include "signal-util.h" + #include "string-table.h" +@@ -46,6 +47,7 @@ typedef enum EventSourceType { + _SOURCE_EVENT_SOURCE_TYPE_INVALID = -1 + } EventSourceType; + ++ + static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] = { + [SOURCE_IO] = "io", + [SOURCE_TIME_REALTIME] = "realtime", +@@ -76,7 +78,25 @@ typedef enum WakeupType { + _WAKEUP_TYPE_INVALID = -1, + } WakeupType; + +-#define EVENT_SOURCE_IS_TIME(t) IN_SET((t), SOURCE_TIME_REALTIME, SOURCE_TIME_BOOTTIME, SOURCE_TIME_MONOTONIC, SOURCE_TIME_REALTIME_ALARM, SOURCE_TIME_BOOTTIME_ALARM) ++#define EVENT_SOURCE_IS_TIME(t) \ ++ IN_SET((t), \ ++ SOURCE_TIME_REALTIME, \ ++ SOURCE_TIME_BOOTTIME, \ ++ SOURCE_TIME_MONOTONIC, \ ++ SOURCE_TIME_REALTIME_ALARM, \ ++ SOURCE_TIME_BOOTTIME_ALARM) ++ ++#define EVENT_SOURCE_CAN_RATE_LIMIT(t) \ ++ IN_SET((t), \ ++ SOURCE_IO, \ ++ SOURCE_TIME_REALTIME, \ ++ SOURCE_TIME_BOOTTIME, \ ++ SOURCE_TIME_MONOTONIC, \ ++ SOURCE_TIME_REALTIME_ALARM, \ ++ SOURCE_TIME_BOOTTIME_ALARM, \ ++ SOURCE_SIGNAL, \ ++ SOURCE_DEFER, \ ++ SOURCE_INOTIFY) + + struct inode_data; + +@@ -96,6 +116,7 @@ struct sd_event_source { + bool pending:1; + bool dispatching:1; + bool floating:1; ++ bool ratelimited:1; + + int64_t priority; + unsigned pending_index; +@@ -107,6 +128,10 @@ struct sd_event_source { + + LIST_FIELDS(sd_event_source, sources); + ++ RateLimit rate_limit; ++ ++ /* These are primarily fields relevant for time event sources, but since any event source can ++ * effectively become one when rate-limited, this is part of the common fields. */ + unsigned earliest_index; + unsigned latest_index; + +@@ -266,7 +291,7 @@ struct sd_event { + Hashmap *signal_data; /* indexed by priority */ + + Hashmap *child_sources; +- unsigned n_enabled_child_sources; ++ unsigned n_online_child_sources; + + Set *post_sources; + +@@ -311,12 +336,23 @@ static thread_local sd_event *default_event = NULL; + static void source_disconnect(sd_event_source *s); + static void event_gc_inode_data(sd_event *e, struct inode_data *d); + ++static bool event_source_is_online(sd_event_source *s) { ++ assert(s); ++ return s->enabled != SD_EVENT_OFF && !s->ratelimited; ++} ++ ++static bool event_source_is_offline(sd_event_source *s) { ++ assert(s); ++ return s->enabled == SD_EVENT_OFF || s->ratelimited; ++} ++ + static sd_event *event_resolve(sd_event *e) { + return e == SD_EVENT_DEFAULT ? default_event : e; + } + + static int pending_prioq_compare(const void *a, const void *b) { + const sd_event_source *x = a, *y = b; ++ int r; + + assert(x->pending); + assert(y->pending); +@@ -327,23 +363,23 @@ static int pending_prioq_compare(const void *a, const void *b) { + if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) + return 1; + ++ /* Non rate-limited ones first. */ ++ r = CMP(!!x->ratelimited, !!y->ratelimited); ++ if (r != 0) ++ return r; ++ + /* Lower priority values first */ +- if (x->priority < y->priority) +- return -1; +- if (x->priority > y->priority) +- return 1; ++ r = CMP(x->priority, y->priority); ++ if (r != 0) ++ return r; + + /* Older entries first */ +- if (x->pending_iteration < y->pending_iteration) +- return -1; +- if (x->pending_iteration > y->pending_iteration) +- return 1; +- +- return 0; ++ return CMP(x->pending_iteration, y->pending_iteration); + } + + static int prepare_prioq_compare(const void *a, const void *b) { + const sd_event_source *x = a, *y = b; ++ int r; + + assert(x->prepare); + assert(y->prepare); +@@ -354,29 +390,46 @@ static int prepare_prioq_compare(const void *a, const void *b) { + if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) + return 1; + ++ /* Non rate-limited ones first. */ ++ r = CMP(!!x->ratelimited, !!y->ratelimited); ++ if (r != 0) ++ return r; ++ + /* Move most recently prepared ones last, so that we can stop + * preparing as soon as we hit one that has already been + * prepared in the current iteration */ +- if (x->prepare_iteration < y->prepare_iteration) +- return -1; +- if (x->prepare_iteration > y->prepare_iteration) +- return 1; ++ r = CMP(x->prepare_iteration, y->prepare_iteration); ++ if (r != 0) ++ return r; + + /* Lower priority values first */ +- if (x->priority < y->priority) +- return -1; +- if (x->priority > y->priority) +- return 1; ++ return CMP(x->priority, y->priority); ++} + +- return 0; ++static usec_t time_event_source_next(const sd_event_source *s) { ++ assert(s); ++ ++ /* We have two kinds of event sources that have elapsation times associated with them: the actual ++ * time based ones and the ones for which a ratelimit can be in effect (where we want to be notified ++ * once the ratelimit time window ends). Let's return the next elapsing time depending on what we are ++ * looking at here. */ ++ ++ if (s->ratelimited) { /* If rate-limited the next elapsation is when the ratelimit time window ends */ ++ assert(s->rate_limit.begin != 0); ++ assert(s->rate_limit.interval != 0); ++ return usec_add(s->rate_limit.begin, s->rate_limit.interval); ++ } ++ ++ /* Otherwise this must be a time event source, if not ratelimited */ ++ if (EVENT_SOURCE_IS_TIME(s->type)) ++ return s->time.next; ++ ++ return USEC_INFINITY; + } + + static int earliest_time_prioq_compare(const void *a, const void *b) { + const sd_event_source *x = a, *y = b; + +- assert(EVENT_SOURCE_IS_TIME(x->type)); +- assert(x->type == y->type); +- + /* Enabled ones first */ + if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) + return -1; +@@ -390,24 +443,30 @@ static int earliest_time_prioq_compare(const void *a, const void *b) { + return 1; + + /* Order by time */ +- if (x->time.next < y->time.next) +- return -1; +- if (x->time.next > y->time.next) +- return 1; +- +- return 0; ++ return CMP(time_event_source_next(x), time_event_source_next(y)); + } + + static usec_t time_event_source_latest(const sd_event_source *s) { +- return usec_add(s->time.next, s->time.accuracy); ++ assert(s); ++ ++ if (s->ratelimited) { /* For ratelimited stuff the earliest and the latest time shall actually be the ++ * same, as we should avoid adding additional inaccuracy on an inaccuracy time ++ * window */ ++ assert(s->rate_limit.begin != 0); ++ assert(s->rate_limit.interval != 0); ++ return usec_add(s->rate_limit.begin, s->rate_limit.interval); ++ } ++ ++ /* Must be a time event source, if not ratelimited */ ++ if (EVENT_SOURCE_IS_TIME(s->type)) ++ return usec_add(s->time.next, s->time.accuracy); ++ ++ return USEC_INFINITY; + } + + static int latest_time_prioq_compare(const void *a, const void *b) { + const sd_event_source *x = a, *y = b; + +- assert(EVENT_SOURCE_IS_TIME(x->type)); +- assert(x->type == y->type); +- + /* Enabled ones first */ + if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) + return -1; +@@ -852,12 +911,12 @@ static void event_gc_signal_data(sd_event *e, const int64_t *priority, int sig) + * the signalfd for it. */ + + if (sig == SIGCHLD && +- e->n_enabled_child_sources > 0) ++ e->n_online_child_sources > 0) + return; + + if (e->signal_sources && + e->signal_sources[sig] && +- e->signal_sources[sig]->enabled != SD_EVENT_OFF) ++ event_source_is_online(e->signal_sources[sig])) + return; + + /* +@@ -904,11 +963,17 @@ static void event_source_time_prioq_reshuffle(sd_event_source *s) { + struct clock_data *d; + + assert(s); +- assert(EVENT_SOURCE_IS_TIME(s->type)); + + /* Called whenever the event source's timer ordering properties changed, i.e. time, accuracy, + * pending, enable state. Makes sure the two prioq's are ordered properly again. */ +- assert_se(d = event_get_clock_data(s->event, s->type)); ++ ++ if (s->ratelimited) ++ d = &s->event->monotonic; ++ else { ++ assert(EVENT_SOURCE_IS_TIME(s->type)); ++ assert_se(d = event_get_clock_data(s->event, s->type)); ++ } ++ + prioq_reshuffle(d->earliest, s, &s->earliest_index); + prioq_reshuffle(d->latest, s, &s->latest_index); + d->needs_rearm = true; +@@ -949,12 +1014,18 @@ static void source_disconnect(sd_event_source *s) { + case SOURCE_TIME_BOOTTIME: + case SOURCE_TIME_MONOTONIC: + case SOURCE_TIME_REALTIME_ALARM: +- case SOURCE_TIME_BOOTTIME_ALARM: { +- struct clock_data *d; +- assert_se(d = event_get_clock_data(s->event, s->type)); +- event_source_time_prioq_remove(s, d); ++ case SOURCE_TIME_BOOTTIME_ALARM: ++ /* Only remove this event source from the time event source here if it is not ratelimited. If ++ * it is ratelimited, we'll remove it below, separately. Why? Because the clock used might ++ * differ: ratelimiting always uses CLOCK_MONOTONIC, but timer events might use any clock */ ++ ++ if (!s->ratelimited) { ++ struct clock_data *d; ++ assert_se(d = event_get_clock_data(s->event, s->type)); ++ event_source_time_prioq_remove(s, d); ++ } ++ + break; +- } + + case SOURCE_SIGNAL: + if (s->signal.sig > 0) { +@@ -969,9 +1040,9 @@ static void source_disconnect(sd_event_source *s) { + + case SOURCE_CHILD: + if (s->child.pid > 0) { +- if (s->enabled != SD_EVENT_OFF) { +- assert(s->event->n_enabled_child_sources > 0); +- s->event->n_enabled_child_sources--; ++ if (event_source_is_online(s)) { ++ assert(s->event->n_online_child_sources > 0); ++ s->event->n_online_child_sources--; + } + + (void) hashmap_remove(s->event->child_sources, PID_TO_PTR(s->child.pid)); +@@ -1037,6 +1108,9 @@ static void source_disconnect(sd_event_source *s) { + if (s->prepare) + prioq_remove(s->event->prepare, s, &s->prepare_index); + ++ if (s->ratelimited) ++ event_source_time_prioq_remove(s, &s->event->monotonic); ++ + event = s->event; + + s->type = _SOURCE_EVENT_SOURCE_TYPE_INVALID; +@@ -1458,11 +1532,11 @@ _public_ int sd_event_add_child( + return r; + } + +- e->n_enabled_child_sources++; ++ e->n_online_child_sources++; + + r = event_make_signal_data(e, SIGCHLD, NULL); + if (r < 0) { +- e->n_enabled_child_sources--; ++ e->n_online_child_sources--; + source_free(s); + return r; + } +@@ -2079,7 +2153,7 @@ _public_ int sd_event_source_set_io_fd(sd_event_source *s, int fd) { + if (s->io.fd == fd) + return 0; + +- if (s->enabled == SD_EVENT_OFF) { ++ if (event_source_is_offline(s)) { + s->io.fd = fd; + s->io.registered = false; + } else { +@@ -2146,7 +2220,7 @@ _public_ int sd_event_source_set_io_events(sd_event_source *s, uint32_t events) + if (r < 0) + return r; + +- if (s->enabled != SD_EVENT_OFF) { ++ if (event_source_is_online(s)) { + r = source_io_register(s, s->enabled, events); + if (r < 0) + return r; +@@ -2249,7 +2323,7 @@ _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority) + + event_gc_inode_data(s->event, old_inode_data); + +- } else if (s->type == SOURCE_SIGNAL && s->enabled != SD_EVENT_OFF) { ++ } else if (s->type == SOURCE_SIGNAL && event_source_is_online(s)) { + struct signal_data *old, *d; + + /* Move us from the signalfd belonging to the old +@@ -2296,20 +2370,29 @@ _public_ int sd_event_source_get_enabled(sd_event_source *s, int *ret) { + return s->enabled != SD_EVENT_OFF; + } + +-static int event_source_disable(sd_event_source *s) { ++static int event_source_offline( ++ sd_event_source *s, ++ int enabled, ++ bool ratelimited) { ++ ++ bool was_offline; + int r; + + assert(s); +- assert(s->enabled != SD_EVENT_OFF); ++ assert(enabled == SD_EVENT_OFF || ratelimited); + + /* Unset the pending flag when this event source is disabled */ +- if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { ++ if (s->enabled != SD_EVENT_OFF && ++ enabled == SD_EVENT_OFF && ++ !IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { + r = source_set_pending(s, false); + if (r < 0) + return r; + } + +- s->enabled = SD_EVENT_OFF; ++ was_offline = event_source_is_offline(s); ++ s->enabled = enabled; ++ s->ratelimited = ratelimited; + + switch (s->type) { + +@@ -2330,8 +2413,10 @@ static int event_source_disable(sd_event_source *s) { + break; + + case SOURCE_CHILD: +- assert(s->event->n_enabled_child_sources > 0); +- s->event->n_enabled_child_sources--; ++ if (!was_offline) { ++ assert(s->event->n_online_child_sources > 0); ++ s->event->n_online_child_sources--; ++ } + + event_gc_signal_data(s->event, &s->priority, SIGCHLD); + break; +@@ -2349,26 +2434,42 @@ static int event_source_disable(sd_event_source *s) { + assert_not_reached("Wut? I shouldn't exist."); + } + +- return 0; ++ return 1; + } + +-static int event_source_enable(sd_event_source *s, int enable) { ++static int event_source_online( ++ sd_event_source *s, ++ int enabled, ++ bool ratelimited) { ++ ++ bool was_online; + int r; + + assert(s); +- assert(IN_SET(enable, SD_EVENT_ON, SD_EVENT_ONESHOT)); +- assert(s->enabled == SD_EVENT_OFF); ++ assert(enabled != SD_EVENT_OFF || !ratelimited); + + /* Unset the pending flag when this event source is enabled */ +- if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { ++ if (s->enabled == SD_EVENT_OFF && ++ enabled != SD_EVENT_OFF && ++ !IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { + r = source_set_pending(s, false); + if (r < 0) + return r; + } + ++ /* Are we really ready for onlining? */ ++ if (enabled == SD_EVENT_OFF || ratelimited) { ++ /* Nope, we are not ready for onlining, then just update the precise state and exit */ ++ s->enabled = enabled; ++ s->ratelimited = ratelimited; ++ return 0; ++ } ++ ++ was_online = event_source_is_online(s); ++ + switch (s->type) { + case SOURCE_IO: +- r = source_io_register(s, enable, s->io.events); ++ r = source_io_register(s, enabled, s->io.events); + if (r < 0) + return r; + break; +@@ -2386,13 +2487,13 @@ static int event_source_enable(sd_event_source *s, int enable) { + r = event_make_signal_data(s->event, SIGCHLD, NULL); + if (r < 0) { + s->enabled = SD_EVENT_OFF; +- s->event->n_enabled_child_sources--; ++ s->event->n_online_child_sources--; + event_gc_signal_data(s->event, &s->priority, SIGCHLD); + return r; + } + +- s->event->n_enabled_child_sources++; +- ++ if (!was_online) ++ s->event->n_online_child_sources++; + break; + + case SOURCE_TIME_REALTIME: +@@ -2410,7 +2511,8 @@ static int event_source_enable(sd_event_source *s, int enable) { + assert_not_reached("Wut? I shouldn't exist."); + } + +- s->enabled = enable; ++ s->enabled = enabled; ++ s->ratelimited = ratelimited; + + /* Non-failing operations below */ + switch (s->type) { +@@ -2430,7 +2532,7 @@ static int event_source_enable(sd_event_source *s, int enable) { + break; + } + +- return 0; ++ return 1; + } + + _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { +@@ -2448,7 +2550,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { + return 0; + + if (m == SD_EVENT_OFF) +- r = event_source_disable(s); ++ r = event_source_offline(s, m, s->ratelimited); + else { + if (s->enabled != SD_EVENT_OFF) { + /* Switching from "on" to "oneshot" or back? If that's the case, we can take a shortcut, the +@@ -2457,7 +2559,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { + return 0; + } + +- r = event_source_enable(s, m); ++ r = event_source_online(s, m, s->ratelimited); + } + if (r < 0) + return r; +@@ -2605,6 +2707,96 @@ _public_ void *sd_event_source_set_userdata(sd_event_source *s, void *userdata) + return ret; + } + ++static int event_source_enter_ratelimited(sd_event_source *s) { ++ int r; ++ ++ assert(s); ++ ++ /* When an event source becomes ratelimited, we place it in the CLOCK_MONOTONIC priority queue, with ++ * the end of the rate limit time window, much as if it was a timer event source. */ ++ ++ if (s->ratelimited) ++ return 0; /* Already ratelimited, this is a NOP hence */ ++ ++ /* Make sure we can install a CLOCK_MONOTONIC event further down. */ ++ r = setup_clock_data(s->event, &s->event->monotonic, CLOCK_MONOTONIC); ++ if (r < 0) ++ return r; ++ ++ /* Timer event sources are already using the earliest/latest queues for the timer scheduling. Let's ++ * first remove them from the prioq appropriate for their own clock, so that we can use the prioq ++ * fields of the event source then for adding it to the CLOCK_MONOTONIC prioq instead. */ ++ if (EVENT_SOURCE_IS_TIME(s->type)) ++ event_source_time_prioq_remove(s, event_get_clock_data(s->event, s->type)); ++ ++ /* Now, let's add the event source to the monotonic clock instead */ ++ r = event_source_time_prioq_put(s, &s->event->monotonic); ++ if (r < 0) ++ goto fail; ++ ++ /* And let's take the event source officially offline */ ++ r = event_source_offline(s, s->enabled, /* ratelimited= */ true); ++ if (r < 0) { ++ event_source_time_prioq_remove(s, &s->event->monotonic); ++ goto fail; ++ } ++ ++ event_source_pp_prioq_reshuffle(s); ++ ++ log_debug("Event source %p (%s) entered rate limit state.", s, strna(s->description)); ++ return 0; ++ ++fail: ++ /* Reinstall time event sources in the priority queue as before. This shouldn't fail, since the queue ++ * space for it should already be allocated. */ ++ if (EVENT_SOURCE_IS_TIME(s->type)) ++ assert_se(event_source_time_prioq_put(s, event_get_clock_data(s->event, s->type)) >= 0); ++ ++ return r; ++} ++ ++static int event_source_leave_ratelimit(sd_event_source *s) { ++ int r; ++ ++ assert(s); ++ ++ if (!s->ratelimited) ++ return 0; ++ ++ /* Let's take the event source out of the monotonic prioq first. */ ++ event_source_time_prioq_remove(s, &s->event->monotonic); ++ ++ /* Let's then add the event source to its native clock prioq again — if this is a timer event source */ ++ if (EVENT_SOURCE_IS_TIME(s->type)) { ++ r = event_source_time_prioq_put(s, event_get_clock_data(s->event, s->type)); ++ if (r < 0) ++ goto fail; ++ } ++ ++ /* Let's try to take it online again. */ ++ r = event_source_online(s, s->enabled, /* ratelimited= */ false); ++ if (r < 0) { ++ /* Do something roughly sensible when this failed: undo the two prioq ops above */ ++ if (EVENT_SOURCE_IS_TIME(s->type)) ++ event_source_time_prioq_remove(s, event_get_clock_data(s->event, s->type)); ++ ++ goto fail; ++ } ++ ++ event_source_pp_prioq_reshuffle(s); ++ ratelimit_reset(&s->rate_limit); ++ ++ log_debug("Event source %p (%s) left rate limit state.", s, strna(s->description)); ++ return 0; ++ ++fail: ++ /* Do something somewhat reasonable when we cannot move an event sources out of ratelimited mode: ++ * simply put it back in it, maybe we can then process it more successfully next iteration. */ ++ assert_se(event_source_time_prioq_put(s, &s->event->monotonic) >= 0); ++ ++ return r; ++} ++ + static usec_t sleep_between(sd_event *e, usec_t a, usec_t b) { + usec_t c; + assert(e); +@@ -2703,7 +2895,7 @@ static int event_arm_timer( + d->needs_rearm = false; + + a = prioq_peek(d->earliest); +- if (!a || a->enabled == SD_EVENT_OFF || a->time.next == USEC_INFINITY) { ++ if (!a || a->enabled == SD_EVENT_OFF || time_event_source_next(a) == USEC_INFINITY) { + + if (d->fd < 0) + return 0; +@@ -2723,7 +2915,7 @@ static int event_arm_timer( + b = prioq_peek(d->latest); + assert_se(b && b->enabled != SD_EVENT_OFF); + +- t = sleep_between(e, a->time.next, time_event_source_latest(b)); ++ t = sleep_between(e, time_event_source_next(a), time_event_source_latest(b)); + if (d->next == t) + return 0; + +@@ -2802,10 +2994,22 @@ static int process_timer( + + for (;;) { + s = prioq_peek(d->earliest); +- if (!s || +- s->time.next > n || +- s->enabled == SD_EVENT_OFF || +- s->pending) ++ if (!s || time_event_source_next(s) > n) ++ break; ++ ++ if (s->ratelimited) { ++ /* This is an event sources whose ratelimit window has ended. Let's turn it on ++ * again. */ ++ assert(s->ratelimited); ++ ++ r = event_source_leave_ratelimit(s); ++ if (r < 0) ++ return r; ++ ++ continue; ++ } ++ ++ if (s->enabled == SD_EVENT_OFF || s->pending) + break; + + r = source_set_pending(s, true); +@@ -2851,7 +3055,7 @@ static int process_child(sd_event *e) { + if (s->pending) + continue; + +- if (s->enabled == SD_EVENT_OFF) ++ if (event_source_is_offline(s)) + continue; + + zero(s->child.siginfo); +@@ -3024,7 +3228,7 @@ static int event_inotify_data_process(sd_event *e, struct inotify_data *d) { + + LIST_FOREACH(inotify.by_inode_data, s, inode_data->event_sources) { + +- if (s->enabled == SD_EVENT_OFF) ++ if (event_source_is_offline(s)) + continue; + + r = source_set_pending(s, true); +@@ -3060,7 +3264,7 @@ static int event_inotify_data_process(sd_event *e, struct inotify_data *d) { + * sources if IN_IGNORED or IN_UNMOUNT is set. */ + LIST_FOREACH(inotify.by_inode_data, s, inode_data->event_sources) { + +- if (s->enabled == SD_EVENT_OFF) ++ if (event_source_is_offline(s)) + continue; + + if ((d->buffer.ev.mask & (IN_IGNORED|IN_UNMOUNT)) == 0 && +@@ -3099,6 +3303,7 @@ static int process_inotify(sd_event *e) { + } + + static int source_dispatch(sd_event_source *s) { ++ _cleanup_(sd_event_unrefp) sd_event *saved_event = NULL; + EventSourceType saved_type; + int r = 0; + +@@ -3109,6 +3314,20 @@ static int source_dispatch(sd_event_source *s) { + * the event. */ + saved_type = s->type; + ++ /* Similar, store a reference to the event loop object, so that we can still access it after the ++ * callback might have invalidated/disconnected the event source. */ ++ saved_event = sd_event_ref(s->event); ++ ++ /* Check if we hit the ratelimit for this event source, if so, let's disable it. */ ++ assert(!s->ratelimited); ++ if (!ratelimit_below(&s->rate_limit)) { ++ r = event_source_enter_ratelimited(s); ++ if (r < 0) ++ return r; ++ ++ return 1; ++ } ++ + if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { + r = source_set_pending(s, false); + if (r < 0) +@@ -3235,7 +3454,7 @@ static int event_prepare(sd_event *e) { + sd_event_source *s; + + s = prioq_peek(e->prepare); +- if (!s || s->prepare_iteration == e->iteration || s->enabled == SD_EVENT_OFF) ++ if (!s || s->prepare_iteration == e->iteration || event_source_is_offline(s)) + break; + + s->prepare_iteration = e->iteration; +@@ -3269,7 +3488,7 @@ static int dispatch_exit(sd_event *e) { + assert(e); + + p = prioq_peek(e->exit); +- if (!p || p->enabled == SD_EVENT_OFF) { ++ if (!p || event_source_is_offline(p)) { + e->state = SD_EVENT_FINISHED; + return 0; + } +@@ -3291,7 +3510,7 @@ static sd_event_source* event_next_pending(sd_event *e) { + if (!p) + return NULL; + +- if (p->enabled == SD_EVENT_OFF) ++ if (event_source_is_offline(p)) + return NULL; + + return p; +@@ -3844,3 +4063,53 @@ _public_ int sd_event_source_get_destroy_callback(sd_event_source *s, sd_event_d + + return !!s->destroy_callback; + } ++ ++_public_ int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval, unsigned burst) { ++ int r; ++ ++ assert_return(s, -EINVAL); ++ ++ /* Turning on ratelimiting on event source types that don't support it, is a loggable offense. Doing ++ * so is a programming error. */ ++ assert_return(EVENT_SOURCE_CAN_RATE_LIMIT(s->type), -EDOM); ++ ++ /* When ratelimiting is configured we'll always reset the rate limit state first and start fresh, ++ * non-ratelimited. */ ++ r = event_source_leave_ratelimit(s); ++ if (r < 0) ++ return r; ++ ++ RATELIMIT_INIT(s->rate_limit, interval, burst); ++ return 0; ++} ++ ++_public_ int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval, unsigned *ret_burst) { ++ assert_return(s, -EINVAL); ++ ++ /* Querying whether an event source has ratelimiting configured is not a loggable offsense, hence ++ * don't use assert_return(). Unlike turning on ratelimiting it's not really a programming error */ ++ if (!EVENT_SOURCE_CAN_RATE_LIMIT(s->type)) ++ return -EDOM; ++ ++ if (!ratelimit_configured(&s->rate_limit)) ++ return -ENOEXEC; ++ ++ if (ret_interval) ++ *ret_interval = s->rate_limit.interval; ++ if (ret_burst) ++ *ret_burst = s->rate_limit.burst; ++ ++ return 0; ++} ++ ++_public_ int sd_event_source_is_ratelimited(sd_event_source *s) { ++ assert_return(s, -EINVAL); ++ ++ if (!EVENT_SOURCE_CAN_RATE_LIMIT(s->type)) ++ return false; ++ ++ if (!ratelimit_configured(&s->rate_limit)) ++ return false; ++ ++ return s->ratelimited; ++} +diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h +index 9876be01c6..a17a9b3488 100644 +--- a/src/systemd/sd-event.h ++++ b/src/systemd/sd-event.h +@@ -144,6 +144,9 @@ int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid); + int sd_event_source_get_inotify_mask(sd_event_source *s, uint32_t *ret); + int sd_event_source_set_destroy_callback(sd_event_source *s, sd_event_destroy_t callback); + int sd_event_source_get_destroy_callback(sd_event_source *s, sd_event_destroy_t *ret); ++int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval_usec, unsigned burst); ++int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval_usec, unsigned *ret_burst); ++int sd_event_source_is_ratelimited(sd_event_source *s); + + /* Define helpers so that __attribute__((cleanup(sd_event_unrefp))) and similar may be used. */ + _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_event, sd_event_unref); diff --git a/SOURCES/0560-test-add-ratelimiting-test.patch b/SOURCES/0560-test-add-ratelimiting-test.patch new file mode 100644 index 0000000..8e398e1 --- /dev/null +++ b/SOURCES/0560-test-add-ratelimiting-test.patch @@ -0,0 +1,127 @@ +From c35ba62cd6f337c4eef64cdc3b9796f988802229 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20Sekleta=CC=81r?= +Date: Mon, 23 Nov 2020 18:04:57 +0100 +Subject: [PATCH] test: add ratelimiting test + +(Taken from Michal's #17274 by Lennart, and slightly adjusted) + +(cherry picked from commit 68d890651781904a4c762ac866af36e30c4f7ff8) + +Related: #1819868 +--- + src/libsystemd/sd-event/test-event.c | 96 ++++++++++++++++++++++++++++ + 1 file changed, 96 insertions(+) + +diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c +index bde00cf719..e3ee4cd5c3 100644 +--- a/src/libsystemd/sd-event/test-event.c ++++ b/src/libsystemd/sd-event/test-event.c +@@ -482,6 +482,100 @@ static void test_inotify(unsigned n_create_events) { + sd_event_unref(e); + } + ++ ++static int ratelimit_io_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) { ++ unsigned *c = (unsigned*) userdata; ++ *c += 1; ++ return 0; ++} ++ ++static int ratelimit_time_handler(sd_event_source *s, uint64_t usec, void *userdata) { ++ int r; ++ ++ r = sd_event_source_set_enabled(s, SD_EVENT_ON); ++ if (r < 0) ++ log_warning_errno(r, "Failed to turn on notify event source: %m"); ++ ++ r = sd_event_source_set_time(s, usec + 1000); ++ if (r < 0) ++ log_error_errno(r, "Failed to restart watchdog event source: %m"); ++ ++ unsigned *c = (unsigned*) userdata; ++ *c += 1; ++ ++ return 0; ++} ++ ++static void test_ratelimit(void) { ++ _cleanup_close_pair_ int p[2] = {-1, -1}; ++ _cleanup_(sd_event_unrefp) sd_event *e = NULL; ++ _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL; ++ uint64_t interval; ++ unsigned count, burst; ++ ++ assert_se(sd_event_default(&e) >= 0); ++ assert_se(pipe2(p, O_CLOEXEC|O_NONBLOCK) >= 0); ++ ++ assert_se(sd_event_add_io(e, &s, p[0], EPOLLIN, ratelimit_io_handler, &count) >= 0); ++ assert_se(sd_event_source_set_description(s, "test-ratelimit-io") >= 0); ++ assert_se(sd_event_source_set_ratelimit(s, 1 * USEC_PER_SEC, 5) >= 0); ++ assert_se(sd_event_source_get_ratelimit(s, &interval, &burst) >= 0); ++ assert_se(interval == 1 * USEC_PER_SEC && burst == 5); ++ ++ assert_se(write(p[1], "1", 1) == 1); ++ ++ count = 0; ++ for (unsigned i = 0; i < 10; i++) { ++ log_debug("slow loop iteration %u", i); ++ assert_se(sd_event_run(e, UINT64_MAX) >= 0); ++ assert_se(usleep(250 * USEC_PER_MSEC) >= 0); ++ } ++ ++ assert_se(sd_event_source_is_ratelimited(s) == 0); ++ assert_se(count == 10); ++ log_info("ratelimit_io_handler: called %d times, event source not ratelimited", count); ++ ++ assert_se(sd_event_source_set_ratelimit(s, 0, 0) >= 0); ++ assert_se(sd_event_source_set_ratelimit(s, 1 * USEC_PER_SEC, 5) >= 0); ++ ++ count = 0; ++ for (unsigned i = 0; i < 10; i++) { ++ log_debug("fast event loop iteration %u", i); ++ assert_se(sd_event_run(e, UINT64_MAX) >= 0); ++ assert_se(usleep(10) >= 0); ++ } ++ log_info("ratelimit_io_handler: called %d times, event source got ratelimited", count); ++ assert_se(count < 10); ++ ++ s = sd_event_source_unref(s); ++ safe_close_pair(p); ++ ++ count = 0; ++ ++ assert_se(sd_event_add_time(e, &s, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 1000, 0, ratelimit_time_handler, &count) >= 0); ++ assert_se(sd_event_source_set_ratelimit(s, 1 * USEC_PER_SEC, 10) == 0); ++ ++ do { ++ assert_se(sd_event_run(e, UINT64_MAX) >= 0); ++ } while (!sd_event_source_is_ratelimited(s)); ++ ++ log_info("ratelimit_time_handler: called %d times, event source got ratelimited", count); ++ assert_se(count == 10); ++ ++ /* In order to get rid of active rate limit client needs to disable it explicitely */ ++ assert_se(sd_event_source_set_ratelimit(s, 0, 0) >= 0); ++ assert_se(!sd_event_source_is_ratelimited(s)); ++ ++ assert_se(sd_event_source_set_ratelimit(s, 1 * USEC_PER_SEC, 10) >= 0); ++ ++ do { ++ assert_se(sd_event_run(e, UINT64_MAX) >= 0); ++ } while (!sd_event_source_is_ratelimited(s)); ++ ++ log_info("ratelimit_time_handler: called 10 more times, event source got ratelimited"); ++ assert_se(count == 20); ++} ++ + int main(int argc, char *argv[]) { + + log_set_max_level(LOG_DEBUG); +@@ -494,5 +588,7 @@ int main(int argc, char *argv[]) { + test_inotify(100); /* should work without overflow */ + test_inotify(33000); /* should trigger a q overflow */ + ++ test_ratelimit(); ++ + return 0; + } diff --git a/SOURCES/0561-core-prevent-excessive-proc-self-mountinfo-parsing.patch b/SOURCES/0561-core-prevent-excessive-proc-self-mountinfo-parsing.patch new file mode 100644 index 0000000..71075e0 --- /dev/null +++ b/SOURCES/0561-core-prevent-excessive-proc-self-mountinfo-parsing.patch @@ -0,0 +1,29 @@ +From 51737206afaa10d902c86ec9b5ec97cf425039c2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20Sekleta=CC=81r?= +Date: Thu, 9 Jul 2020 18:16:44 +0200 +Subject: [PATCH] core: prevent excessive /proc/self/mountinfo parsing + +(cherry picked from commit d586f642fd90e3bb378f7b6d3e3a64a753e51756) + +Resolves: #1819868 +--- + src/core/mount.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/core/mount.c b/src/core/mount.c +index 2746372db2..076dfd06a3 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -1763,6 +1763,12 @@ static void mount_enumerate(Manager *m) { + goto fail; + } + ++ r = sd_event_source_set_ratelimit(m->mount_event_source, 1 * USEC_PER_SEC, 5); ++ if (r < 0) { ++ log_error_errno(r, "Failed to enable rate limit for mount events: %m"); ++ goto fail; ++ } ++ + (void) sd_event_source_set_description(m->mount_event_source, "mount-monitor-dispatch"); + } + diff --git a/SOURCES/0562-udev-run-link_update-with-increased-retry-count-in-s.patch b/SOURCES/0562-udev-run-link_update-with-increased-retry-count-in-s.patch new file mode 100644 index 0000000..90fb6ad --- /dev/null +++ b/SOURCES/0562-udev-run-link_update-with-increased-retry-count-in-s.patch @@ -0,0 +1,44 @@ +From 1f3165bda13c8572c8c31d23c998835c4e2ad8f3 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Thu, 4 Mar 2021 17:35:22 +0100 +Subject: [PATCH] udev: run link_update() with increased retry count in second + invocation + +In PR #17431 we have introduced retry loop in link_update() in order to +maximize the chance that we end up with correct target when there are +multiple contenders for given symlink. + +Number of iterations in retry loop is either 1 or +LINK_UPDATE_MAX_RETRIES, depending on the value of 'initialized' db +flag. When device appears for the first time we need to set the +flag before calling link_update() via update_devnode() for the second +time to make sure we run the second invocation with higher retry loop +counter. + +(cherry picked from commit 996c83903da5bf8b371314b4207ff97afeef65a4) + +Related: #1931947 +--- + src/udev/udev-event.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c +index 9004634f65..eaec05523b 100644 +--- a/src/udev/udev-event.c ++++ b/src/udev/udev-event.c +@@ -934,14 +934,13 @@ void udev_event_execute_rules(struct udev_event *event, + /* (re)write database file */ + udev_device_tag_index(dev, event->dev_db, true); + udev_device_update_db(dev); ++ udev_device_set_is_initialized(dev); + + /* Yes, we run update_devnode() twice, because in the first invocation, that is before update of udev database, + * it could happen that two contenders are replacing each other's symlink. Hence we run it again to make sure + * symlinks point to devices that claim them with the highest priority. */ + update_devnode(event); + +- udev_device_set_is_initialized(dev); +- + event->dev_db = udev_device_unref(event->dev_db); + } + } diff --git a/SOURCES/0563-pam-systemd-use-secure_getenv-rather-than-getenv.patch b/SOURCES/0563-pam-systemd-use-secure_getenv-rather-than-getenv.patch new file mode 100644 index 0000000..2eb7fc5 --- /dev/null +++ b/SOURCES/0563-pam-systemd-use-secure_getenv-rather-than-getenv.patch @@ -0,0 +1,89 @@ +From fcd9a141d08d521c01dc1a1c06a8d43a2337a392 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 4 Feb 2019 10:23:43 +0100 +Subject: [PATCH] pam-systemd: use secure_getenv() rather than getenv() + +And explain why in a comment. + +(cherry picked from commit 83d4ab55336ff8a0643c6aa627b31e351a24040a) + +CVE-2019-3842 + +Resolves: #1687514 +--- + src/login/pam_systemd.c | 55 ++++++++++++++++++++++++----------------- + 1 file changed, 32 insertions(+), 23 deletions(-) + +diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c +index 1fbf6ba585..78ddb7d398 100644 +--- a/src/login/pam_systemd.c ++++ b/src/login/pam_systemd.c +@@ -274,6 +274,33 @@ static int append_session_cg_weight(pam_handle_t *handle, sd_bus_message *m, con + return 0; + } + ++static const char* getenv_harder(pam_handle_t *handle, const char *key, const char *fallback) { ++ const char *v; ++ ++ assert(handle); ++ assert(key); ++ ++ /* Looks for an environment variable, preferrably in the environment block associated with the ++ * specified PAM handle, falling back to the process' block instead. Why check both? Because we want ++ * to permit configuration of session properties from unit files that invoke PAM services, so that ++ * PAM services don't have to be reworked to set systemd-specific properties, but these properties ++ * can still be set from the unit file Environment= block. */ ++ ++ v = pam_getenv(handle, key); ++ if (!isempty(v)) ++ return v; ++ ++ /* We use secure_getenv() here, since we might get loaded into su/sudo, which are SUID. Ideally ++ * they'd clean up the environment before invoking foreign code (such as PAM modules), but alas they ++ * currently don't (to be precise, they clean up the environment they pass to their children, but ++ * not their own environ[]). */ ++ v = secure_getenv(key); ++ if (!isempty(v)) ++ return v; ++ ++ return fallback; ++} ++ + _public_ PAM_EXTERN int pam_sm_open_session( + pam_handle_t *handle, + int flags, +@@ -352,29 +379,11 @@ _public_ PAM_EXTERN int pam_sm_open_session( + pam_get_item(handle, PAM_RUSER, (const void**) &remote_user); + pam_get_item(handle, PAM_RHOST, (const void**) &remote_host); + +- seat = pam_getenv(handle, "XDG_SEAT"); +- if (isempty(seat)) +- seat = getenv("XDG_SEAT"); +- +- cvtnr = pam_getenv(handle, "XDG_VTNR"); +- if (isempty(cvtnr)) +- cvtnr = getenv("XDG_VTNR"); +- +- type = pam_getenv(handle, "XDG_SESSION_TYPE"); +- if (isempty(type)) +- type = getenv("XDG_SESSION_TYPE"); +- if (isempty(type)) +- type = type_pam; +- +- class = pam_getenv(handle, "XDG_SESSION_CLASS"); +- if (isempty(class)) +- class = getenv("XDG_SESSION_CLASS"); +- if (isempty(class)) +- class = class_pam; +- +- desktop = pam_getenv(handle, "XDG_SESSION_DESKTOP"); +- if (isempty(desktop)) +- desktop = getenv("XDG_SESSION_DESKTOP"); ++ seat = getenv_harder(handle, "XDG_SEAT", NULL); ++ cvtnr = getenv_harder(handle, "XDG_VTNR", NULL); ++ type = getenv_harder(handle, "XDG_SESSION_TYPE", type_pam); ++ class = getenv_harder(handle, "XDG_SESSION_CLASS", class_pam); ++ desktop = getenv_harder(handle, "XDG_SESSION_DESKTOP", NULL); + + tty = strempty(tty); + diff --git a/SPECS/systemd.spec b/SPECS/systemd.spec index a3c4fe1..23e5b66 100644 --- a/SPECS/systemd.spec +++ b/SPECS/systemd.spec @@ -13,7 +13,7 @@ Name: systemd Url: http://www.freedesktop.org/wiki/Software/systemd Version: 239 -Release: 44%{?dist} +Release: 45%{?dist} # For a breakdown of the licensing, see README License: LGPLv2+ and MIT and GPLv2+ Summary: System and Service Manager @@ -593,6 +593,26 @@ Patch0540: 0540-test-udev-test.pl-generator-for-large-list-of-block-.patch Patch0541: 0541-test-udev-test.pl-suppress-umount-error-message-at-s.patch Patch0542: 0542-test-udev_test.pl-add-expected-good-count.patch Patch0543: 0543-test-udev-test-gracefully-exit-when-imports-fail.patch +Patch0544: 0544-Revert-test-add-test-cases-for-empty-string-match-an.patch +Patch0545: 0545-test-sys-script.py-add-missing-DEVNAME-entries-to-ue.patch +Patch0546: 0546-sd-event-split-out-helper-functions-for-reshuffling-.patch +Patch0547: 0547-sd-event-split-out-enable-and-disable-codepaths-from.patch +Patch0548: 0548-sd-event-mention-that-two-debug-logged-events-are-ig.patch +Patch0549: 0549-sd-event-split-clock-data-allocation-out-of-sd_event.patch +Patch0550: 0550-sd-event-split-out-code-to-add-remove-timer-event-so.patch +Patch0551: 0551-sd-event-fix-delays-assert-brain-o-17790.patch +Patch0552: 0552-sd-event-let-s-suffix-last_run-last_log-with-_usec.patch +Patch0553: 0553-sd-event-refuse-running-default-event-loops-in-any-o.patch +Patch0554: 0554-sd-event-ref-event-loop-while-in-sd_event_prepare-ot.patch +Patch0555: 0555-sd-event-follow-coding-style-with-naming-return-para.patch +Patch0556: 0556-sd-event-remove-earliest_index-latest_index-into-com.patch +Patch0557: 0557-sd-event-update-state-at-the-end-in-event_source_ena.patch +Patch0558: 0558-sd-event-increase-n_enabled_child_sources-just-once.patch +Patch0559: 0559-sd-event-add-ability-to-ratelimit-event-sources.patch +Patch0560: 0560-test-add-ratelimiting-test.patch +Patch0561: 0561-core-prevent-excessive-proc-self-mountinfo-parsing.patch +Patch0562: 0562-udev-run-link_update-with-increased-retry-count-in-s.patch +Patch0563: 0563-pam-systemd-use-secure_getenv-rather-than-getenv.patch %ifarch %{ix86} x86_64 aarch64 @@ -1221,6 +1241,28 @@ fi %files tests -f .file-list-tests %changelog +* Thu Mar 11 2021 systemd maintenance team - 239-45 +- Revert "test: add test cases for empty string match" and "test: add test case for multi matches when use ||" (#1931947) +- test/sys-script.py: add missing DEVNAME entries to uevents (#1931947) +- sd-event: split out helper functions for reshuffling prioqs (#1819868) +- sd-event: split out enable and disable codepaths from sd_event_source_set_enabled() (#1819868) +- sd-event: mention that two debug logged events are ignored (#1819868) +- sd-event: split clock data allocation out of sd_event_add_time() (#1819868) +- sd-event: split out code to add/remove timer event sources to earliest/latest prioq (#1819868) +- sd-event: fix delays assert brain-o (#17790) (#1819868) +- sd-event: let's suffix last_run/last_log with "_usec" (#1819868) +- sd-event: refuse running default event loops in any other thread than the one they are default for (#1819868) +- sd-event: ref event loop while in sd_event_prepare() ot sd_event_run() (#1819868) +- sd-event: follow coding style with naming return parameter (#1819868) +- sd-event: remove earliest_index/latest_index into common part of event source objects (#1819868) +- sd-event: update state at the end in event_source_enable (#1819868) +- sd-event: increase n_enabled_child_sources just once (#1819868) +- sd-event: add ability to ratelimit event sources (#1819868) +- test: add ratelimiting test (#1819868) +- core: prevent excessive /proc/self/mountinfo parsing (#1819868) +- udev: run link_update() with increased retry count in second invocation (#1931947) +- pam-systemd: use secure_getenv() rather than getenv() (#1687514) + * Thu Jan 28 2021 systemd maintenance team - 239-44 - ci: PowerTools repo was renamed to powertools in RHEL 8.3 (#1871827) - ci: use quay.io instead of Docker Hub to avoid rate limits (#1871827)