Merge "Add debian package for systemd"

This commit is contained in:
Zuul 2021-11-16 19:03:57 +00:00 committed by Gerrit Code Review
commit 06c317eb9e
17 changed files with 1799 additions and 0 deletions

View File

@ -0,0 +1,52 @@
From 2818847c832ad5e11c501b9cb7110aec5e534582 Mon Sep 17 00:00:00 2001
From: Yue Tao <Yue.Tao@windriver.com>
Date: Tue, 9 Nov 2021 23:19:48 -0800
Subject: [PATCH] Update symbols file for libsystemd0
Introduce 3 new functions by porting upstream commit
b6d5481b3d9f7c9b1198ab54b54326ec73e855bf.
See source patch 919-sd-event-add-ability-to-ratelimit-event-sources.patch
Signed-off-by: Yue Tao <Yue.Tao@windriver.com>
---
debian/libsystemd0.symbols | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/debian/libsystemd0.symbols b/debian/libsystemd0.symbols
index fdd6adebb1..9bd312e355 100644
--- a/debian/libsystemd0.symbols
+++ b/debian/libsystemd0.symbols
@@ -28,6 +28,7 @@ libsystemd.so.0 libsystemd0 #MINVER#
LIBSYSTEMD_245@LIBSYSTEMD_245 245
LIBSYSTEMD_246@LIBSYSTEMD_246 246
LIBSYSTEMD_247@LIBSYSTEMD_247 247
+ LIBSYSTEMD_248@LIBSYSTEMD_248 248
sd_booted@LIBSYSTEMD_209 0
sd_bus_add_fallback@LIBSYSTEMD_221 221
sd_bus_add_fallback_vtable@LIBSYSTEMD_221 221
@@ -434,11 +435,13 @@ libsystemd.so.0 libsystemd0 #MINVER#
sd_event_source_get_io_revents@LIBSYSTEMD_221 221
sd_event_source_get_pending@LIBSYSTEMD_221 221
sd_event_source_get_priority@LIBSYSTEMD_221 221
+ sd_event_source_get_ratelimit@LIBSYSTEMD_248 248
sd_event_source_get_signal@LIBSYSTEMD_221 221
sd_event_source_get_time@LIBSYSTEMD_221 221
sd_event_source_get_time_accuracy@LIBSYSTEMD_221 221
sd_event_source_get_time_clock@LIBSYSTEMD_221 221
sd_event_source_get_userdata@LIBSYSTEMD_221 221
+ sd_event_source_is_ratelimited@LIBSYSTEMD_248 248
sd_event_source_ref@LIBSYSTEMD_221 221
sd_event_source_send_child_signal@LIBSYSTEMD_245 245
sd_event_source_set_child_pidfd_own@LIBSYSTEMD_245 245
@@ -453,6 +456,7 @@ libsystemd.so.0 libsystemd0 #MINVER#
sd_event_source_set_io_fd_own@LIBSYSTEMD_237 237
sd_event_source_set_prepare@LIBSYSTEMD_221 221
sd_event_source_set_priority@LIBSYSTEMD_221 221
+ sd_event_source_set_ratelimit@LIBSYSTEMD_248 248
sd_event_source_set_time@LIBSYSTEMD_221 221
sd_event_source_set_time_accuracy@LIBSYSTEMD_221 221
sd_event_source_set_time_relative@LIBSYSTEMD_247 247
--
2.31.1

View File

@ -0,0 +1 @@
0001-Update-symbols-file-for-libsystemd0.patch

View File

@ -0,0 +1,4 @@
debver: 247.3-6
revision:
dist: $STX_DIST
PKG_GITREVCOUNT: true

View File

@ -0,0 +1,88 @@
From 8b63ddb68a39d48ebb621d76a2b1f07f5ff67ac7 Mon Sep 17 00:00:00 2001
Message-Id: <8b63ddb68a39d48ebb621d76a2b1f07f5ff67ac7.1574264572.git.Jim.Somerville@windriver.com>
From: systemd team <systemd-maint@redhat.com>
Date: Tue, 8 Nov 2016 17:06:01 -0500
Subject: [PATCH 1/3] inject millisec in syslog date
Signed-off-by: Jim Somerville <Jim.Somerville@windriver.com>
---
src/journal/journald-syslog.c | 48 +++++++++++++++++++++++++++++++++++++------
1 file changed, 42 insertions(+), 6 deletions(-)
diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c
index 1a9db59..36288cb 100644
--- a/src/journal/journald-syslog.c
+++ b/src/journal/journald-syslog.c
@@ -25,6 +25,43 @@
/* Warn once every 30s if we missed syslog message */
#define WARN_FORWARD_SYSLOG_MISSED_USEC (30 * USEC_PER_SEC)
+/* internal function that builds a formatted time str of the
+ * tv parameter into the passed buffer. (ie Nov 7 16:28:38.109)
+ * If tv is NULL, then the clock function is used to build the formatted time
+ * returns (same as snprintf) - number of characters written to buffer.
+ */
+static int formatSyslogDate(char * buffer, int bufLen, const struct timeval *tv) {
+ struct timeval tv_tmp;
+ long int millisec;
+ char tmpbuf[64];
+ struct tm tm;
+ time_t t;
+
+ if (!tv) {
+ // no timeval input so get time data from clock
+ usec_t now_usec = now(CLOCK_REALTIME);
+ time_t now_sec = ((time_t) now_usec / USEC_PER_SEC);
+ long int now_fraction_secs = now_usec % USEC_PER_SEC;
+ tv_tmp.tv_sec = now_sec;
+ tv_tmp.tv_usec = now_fraction_secs;
+ tv = &tv_tmp;
+ }
+
+ t = tv->tv_sec;
+ if (!localtime_r(&t, &tm))
+ return 0;
+
+ // format time to the second granularity - ie Nov 7 16:28:38
+ if (strftime(tmpbuf,sizeof(tmpbuf),"%h %e %T", &tm) <= 0)
+ return 0;
+
+ millisec = tv->tv_usec / 1000;
+ // now append millisecond granularity (ie Nov 7 16:28:38.109) to
+ // the formatted string.
+ return snprintf(buffer, bufLen, "%s.%03lu", tmpbuf, millisec);
+}
+
+
static void forward_syslog_iovec(
Server *s,
const struct iovec *iovec,
@@ -125,8 +162,6 @@ void server_forward_syslog(Server *s, in
char header_priority[DECIMAL_STR_MAX(priority) + 3], header_time[64],
header_pid[STRLEN("[]: ") + DECIMAL_STR_MAX(pid_t) + 1];
int n = 0;
- time_t t;
- struct tm tm;
_cleanup_free_ char *ident_buf = NULL;
assert(s);
@@ -141,12 +176,11 @@ void server_forward_syslog(Server *s, in
xsprintf(header_priority, "<%i>", priority);
iovec[n++] = IOVEC_MAKE_STRING(header_priority);
+
/* Second: timestamp */
- t = tv ? tv->tv_sec : ((time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC));
- if (!localtime_r(&t, &tm))
- return;
- if (strftime(header_time, sizeof(header_time), "%h %e %T ", &tm) <= 0)
- return;
+ if (formatSyslogDate(header_time, sizeof(header_time), tv) <=0 )
+ return;
+
iovec[n++] = IOVEC_MAKE_STRING(header_time);
/* Third: identifier and PID */
--
1.8.3.1

View File

@ -0,0 +1,79 @@
From 77b772bce846db28dc447420fd380a51eadcde15 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 23 Nov 2020 11:40:24 +0100
Subject: [PATCH 09/20] 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
[commit 6cc0022115afbac9ac66c456b140601d90271687 from
https://github.com/systemd-rhel/rhel-8/]
Signed-off-by: Li Zhou <li.zhou@windriver.com>
---
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 7074520..8e6536f 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -1065,6 +1065,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,
@@ -1094,20 +1116,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;
--
2.17.1

View File

@ -0,0 +1,120 @@
From dad1d000b493f98f4f5eaf4bfa34c8617f41970f Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 23 Nov 2020 15:25:35 +0100
Subject: [PATCH 10/20] 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
[commit 88b2618e4de850060a1c5c22b049e6de0578fbb5 from
https://github.com/systemd-rhel/rhel-8/]
Signed-off-by: Li Zhou <li.zhou@windriver.com>
---
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 8e6536f..e0e0eaa 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -723,6 +723,19 @@ static void event_source_time_prioq_resh
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;
@@ -747,13 +760,8 @@ static void source_disconnect(sd_event_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;
}
@@ -1110,6 +1118,30 @@ static int setup_clock_data(sd_event *e,
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,
@@ -1140,8 +1172,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)
@@ -1158,13 +1189,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)
- return r;
-
- r = prioq_put(d->latest, s, &s->time.latest_index);
+ r = event_source_time_prioq_put(s, d);
if (r < 0)
return r;
--
2.17.1

View File

@ -0,0 +1,110 @@
From f72ca8a711fc406dc52f18c7dbc3bfc5397b26ea Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 23 Nov 2020 17:49:27 +0100
Subject: [PATCH 13/20] 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
[commit 97f599bf57fdaee688ae5750e9b2b2587e2b597a from
https://github.com/systemd-rhel/rhel-8/]
Signed-off-by: Li Zhou <li.zhou@windriver.com>
---
src/libsystemd/sd-event/sd-event.c | 25 +++++++++++++------------
1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/src/libsystemd/sd-event/event-source.h b/src/libsystemd/sd-event/event-source.h
index 62d07187a2..189d3b48df 100644
--- a/src/libsystemd/sd-event/event-source.h
+++ b/src/libsystemd/sd-event/event-source.h
@@ -72,6 +72,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;
@@ -84,8 +87,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;
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index a2f7868..82cb9ad 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -718,8 +718,8 @@ static void event_source_time_prioq_resh
/* 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;
}
@@ -730,9 +730,9 @@ static void event_source_time_prioq_remo
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;
}
@@ -1105,14 +1105,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;
}
@@ -1173,7 +1173,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;
--
2.17.1

View File

@ -0,0 +1,835 @@
From 69266c451910d2b57313b2fe7561e07cd5400d27 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 23 Nov 2020 18:02:40 +0100
Subject: [PATCH 19/20] 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
[commit 395eb7753a9772f505102fbbe3ba3261b57abbe9 from
https://github.com/systemd-rhel/rhel-8/
LZ: Moved the changes in libsystemd.sym to libsystemd.sym.m4 from the
file changing history; patch ratelimit.h in its old path; dropped
SOURCE_INOTIFY related parts in sd-event.c because it hasn't been
added in this systemd version.]
Signed-off-by: Li Zhou <li.zhou@windriver.com>
---
src/libsystemd/libsystemd.sym | 7 +
src/libsystemd/sd-event/event-source.h | 6 +
src/libsystemd/sd-event/sd-event.c | 396 +++++++++++++++++++++----
src/systemd/sd-event.h | 3 +
4 files changed, 350 insertions(+), 62 deletions(-)
diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym
index f83b364c96..b03bcd952f 100644
--- a/src/libsystemd/libsystemd.sym
+++ b/src/libsystemd/libsystemd.sym
@@ -736,3 +736,10 @@ global:
sd_device_has_current_tag;
sd_device_set_sysattr_valuef;
} LIBSYSTEMD_246;
+
+LIBSYSTEMD_248 {
+global:
+ sd_event_source_set_ratelimit;
+ sd_event_source_get_ratelimit;
+ sd_event_source_is_ratelimited;
+} LIBSYSTEMD_246;
diff --git a/src/libsystemd/sd-event/event-source.h b/src/libsystemd/sd-event/event-source.h
index 189d3b48df..f0d2a1b9e6 100644
--- a/src/libsystemd/sd-event/event-source.h
+++ b/src/libsystemd/sd-event/event-source.h
@@ -11,6 +11,7 @@
#include "hashmap.h"
#include "list.h"
#include "prioq.h"
+#include "ratelimit.h"
typedef enum EventSourceType {
SOURCE_IO,
@@ -61,6 +62,7 @@ struct sd_event_source {
bool dispatching:1;
bool floating:1;
bool exit_on_failure:1;
+ bool ratelimited:1;
int64_t priority;
unsigned pending_index;
@@ -72,6 +74,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;
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index 39f13cb409..3f1a6776fe 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -37,6 +37,16 @@ static bool EVENT_SOURCE_WATCH_PIDFD(sd_event_source *s) {
s->child.options == WEXITED;
}
+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 const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] = {
[SOURCE_IO] = "io",
[SOURCE_TIME_REALTIME] = "realtime",
@@ -55,7 +65,25 @@ static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX]
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(event_source_type, int);
-#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 sd_event {
unsigned n_ref;
@@ -81,7 +109,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;
@@ -146,6 +174,11 @@ 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 */
r = CMP(x->priority, y->priority);
if (r != 0)
@@ -168,6 +201,11 @@ 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 */
@@ -179,12 +217,30 @@ static int prepare_prioq_compare(const void *a, const void *b) {
return CMP(x->priority, y->priority);
}
+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;
@@ -198,19 +254,30 @@ static int earliest_time_prioq_compare(const void *a, const void *b) {
return 1;
/* Order by time */
- return CMP(x->time.next, y->time.next);
+ 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;
@@ -661,12 +728,12 @@ static void event_gc_signal_data(sd_event *e, const int64_t *priority, int sig)
* and possibly drop 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;
/*
@@ -713,11 +780,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;
@@ -758,12 +831,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) {
@@ -778,9 +857,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));
@@ -850,6 +929,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 = TAKE_PTR(s->event);
LIST_REMOVE(sources, event->sources, s);
event->n_sources--;
@@ -1322,7 +1404,7 @@ _public_ int sd_event_add_child(
if (!callback)
callback = child_exit_callback;
- if (e->n_enabled_child_sources == 0) {
+ if (e->n_online_child_sources == 0) {
/* Caller must block SIGCHLD before using us to watch children, even if pidfd is available,
* for compatibility with pre-pidfd and because we don't want the reap the child processes
* ourselves, i.e. call waitid(), and don't want Linux' default internal logic for that to
@@ -1387,7 +1469,7 @@ _public_ int sd_event_add_child(
e->need_process_child = true;
}
- e->n_enabled_child_sources++;
+ e->n_online_child_sources++;
if (ret)
*ret = s;
@@ -1419,7 +1501,7 @@ _public_ int sd_event_add_child_pidfd(
if (!callback)
callback = child_exit_callback;
- if (e->n_enabled_child_sources == 0) {
+ if (e->n_online_child_sources == 0) {
r = signal_is_blocked(SIGCHLD);
if (r < 0)
return r;
@@ -1469,7 +1551,7 @@ _public_ int sd_event_add_child_pidfd(
e->need_process_child = true;
}
- e->n_enabled_child_sources++;
+ e->n_online_child_sources++;
if (ret)
*ret = s;
@@ -2055,7 +2137,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 {
@@ -2122,7 +2204,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;
@@ -2225,7 +2307,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
@@ -2272,20 +2354,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) {
@@ -2306,8 +2397,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--;
+ }
if (EVENT_SOURCE_WATCH_PIDFD(s))
source_child_pidfd_unregister(s);
@@ -2328,26 +2421,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;
@@ -2365,7 +2474,7 @@ static int event_source_enable(sd_event_source *s, int enable) {
if (EVENT_SOURCE_WATCH_PIDFD(s)) {
/* yes, we have pidfd */
- r = source_child_pidfd_register(s, enable);
+ r = source_child_pidfd_register(s, enabled);
if (r < 0)
return r;
} else {
@@ -2378,8 +2487,8 @@ static int event_source_enable(sd_event_source *s, int enable) {
}
}
- s->event->n_enabled_child_sources++;
-
+ if (!was_online)
+ s->event->n_online_child_sources++;
break;
case SOURCE_TIME_REALTIME:
@@ -2397,7 +2506,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) {
@@ -2417,7 +2527,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) {
@@ -2435,7 +2545,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
@@ -2444,7 +2554,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;
@@ -2701,6 +2811,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);
@@ -2798,7 +2998,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;
@@ -2817,7 +3017,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;
@@ -2895,10 +3095,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);
@@ -2943,7 +3155,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;
if (s->child.exited)
@@ -2990,7 +3202,7 @@ static int process_pidfd(sd_event *e, sd_event_source *s, uint32_t revents) {
if (s->pending)
return 0;
- if (s->enabled == SD_EVENT_OFF)
+ if (event_source_is_offline(s))
return 0;
if (!EVENT_SOURCE_WATCH_PIDFD(s))
@@ -3150,7 +3362,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);
@@ -3186,7 +3398,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 &&
@@ -3240,6 +3452,16 @@ static int source_dispatch(sd_event_source *s) {
* 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)
@@ -3253,7 +3475,7 @@ static int source_dispatch(sd_event_source *s) {
* post sources as pending */
SET_FOREACH(z, s->event->post_sources) {
- if (z->enabled == SD_EVENT_OFF)
+ if (event_source_is_offline(z))
continue;
r = source_set_pending(z, true);
@@ -3373,7 +3595,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;
@@ -3413,7 +3635,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;
}
@@ -3435,7 +3657,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;
@@ -4049,3 +4271,53 @@ _public_ int sd_event_source_set_exit_on_failure(sd_event_source *s, int b) {
s->exit_on_failure = b;
return 1;
}
+
+_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;
+
+ s->rate_limit = (RateLimit) { 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 937c9bd460..2ae2a0da48 100644
--- a/src/systemd/sd-event.h
+++ b/src/systemd/sd-event.h
@@ -162,6 +162,9 @@ int sd_event_source_get_floating(sd_event_source *s);
int sd_event_source_set_floating(sd_event_source *s, int b);
int sd_event_source_get_exit_on_failure(sd_event_source *s);
int sd_event_source_set_exit_on_failure(sd_event_source *s, int b);
+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);
--
2.17.1

View File

@ -0,0 +1,37 @@
From dc3e079395816ce251c4794992f1816a61c1215d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michal=20Sekleta=CC=81r?= <msekleta@redhat.com>
Date: Thu, 9 Jul 2020 18:16:44 +0200
Subject: [PATCH 20/20] core: prevent excessive /proc/self/mountinfo parsing
(cherry picked from commit d586f642fd90e3bb378f7b6d3e3a64a753e51756)
Resolves: #1819868
[commit 51737206afaa10d902c86ec9b5ec97cf425039c2 from
https://github.com/systemd-rhel/rhel-8/]
Signed-off-by: Li Zhou <li.zhou@windriver.com>
---
src/core/mount.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/core/mount.c b/src/core/mount.c
index c7aed23..48427b7 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -1861,6 +1861,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");
}
--
2.17.1

View File

@ -0,0 +1,100 @@
From 762ba1d9cd3571f294965cb86525999e81fdec5d Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 8 Jun 2021 00:07:51 -0700
Subject: [PATCH 1/6] sd-event: change ordering of pending/ratelimited events
Instead of ordering non-pending before pending we should order
"non-pending OR ratelimited" before "pending AND not-ratelimited".
This fixes a bug where ratelimited events were ordered at the end of the
priority queue and could be stuck there for an indeterminate amount of
time.
(cherry picked from commit 81107b8419c39f726fd2805517a5b9faab204e59)
Related: #1984406
[commit 93de7820843c175f4c9661dbfcb312e8ee09fbd3 from
https://github.com/systemd-rhel/rhel-8/ (branch rhel-8.4.0)]
Signed-off-by: Li Zhou <li.zhou@windriver.com>
---
src/libsystemd/sd-event/sd-event.c | 48 +++++++++++++-----------------
1 file changed, 20 insertions(+), 28 deletions(-)
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index 282b38f..fcf333e 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -237,25 +237,6 @@ static usec_t time_event_source_next(const sd_event_source *s) {
return USEC_INFINITY;
}
-static int earliest_time_prioq_compare(const void *a, const void *b) {
- const sd_event_source *x = a, *y = b;
-
- /* Enabled ones first */
- if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
- return -1;
- if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
- return 1;
-
- /* Move the pending ones to the end */
- if (!x->pending && y->pending)
- return -1;
- if (x->pending && !y->pending)
- return 1;
-
- /* Order by time */
- return CMP(time_event_source_next(x), time_event_source_next(y));
-}
-
static usec_t time_event_source_latest(const sd_event_source *s) {
assert(s);
@@ -274,7 +255,15 @@ static usec_t time_event_source_latest(const sd_event_source *s) {
return USEC_INFINITY;
}
-static int latest_time_prioq_compare(const void *a, const void *b) {
+static bool event_source_timer_candidate(const sd_event_source *s) {
+ assert(s);
+
+ /* Returns true for event sources that either are not pending yet (i.e. where it's worth to mark them pending)
+ * or which are currently ratelimited (i.e. where it's worth leaving the ratelimited state) */
+ return !s->pending || s->ratelimited;
+}
+
+static int time_prioq_compare(const void *a, const void *b, usec_t (*time_func)(const sd_event_source *s)) {
const sd_event_source *x = a, *y = b;
/* Enabled ones first */
@@ -283,14 +272,22 @@ static int latest_time_prioq_compare(const void *a, const void *b) {
if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
return 1;
- /* Move the pending ones to the end */
- if (!x->pending && y->pending)
+ /* Order "non-pending OR ratelimited" before "pending AND not-ratelimited" */
+ if (event_source_timer_candidate(x) && !event_source_timer_candidate(y))
return -1;
- if (x->pending && !y->pending)
+ if (!event_source_timer_candidate(x) && event_source_timer_candidate(y))
return 1;
/* Order by time */
- return CMP(time_event_source_latest(x), time_event_source_latest(y));
+ return CMP(time_func(x), time_func(y));
+}
+
+static int earliest_time_prioq_compare(const void *a, const void *b) {
+ return time_prioq_compare(a, b, time_event_source_next);
+}
+
+static int latest_time_prioq_compare(const void *a, const void *b) {
+ return time_prioq_compare(a, b, time_event_source_latest);
}
static int exit_prioq_compare(const void *a, const void *b) {
--
2.17.1

View File

@ -0,0 +1,35 @@
From 9824f4e131b5ffea0be23dd25b24b953314f1a79 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 15 Jun 2021 00:44:04 +0900
Subject: [PATCH 2/6] sd-event: drop unnecessary "else"
(cherry picked from commit 7e2bf71ca3638e36ee33215ceee386ba8013da6d)
Related: #1984406
[commit 3e7e54c63236c65aa01bb332fd5135a13e51b992 from
https://github.com/systemd-rhel/rhel-8/ (branch rhel-8.4.0)]
Signed-off-by: Li Zhou <li.zhou@windriver.com>
---
src/libsystemd/sd-event/sd-event.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index fcf333e..9b6d2f0 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -2199,8 +2199,8 @@ static int event_arm_timer(
if (!d->needs_rearm)
return 0;
- else
- d->needs_rearm = false;
+
+ d->needs_rearm = false;
a = prioq_peek(d->earliest);
if (!a || a->enabled == SD_EVENT_OFF || time_event_source_next(a) == USEC_INFINITY) {
--
2.17.1

View File

@ -0,0 +1,98 @@
From 766177b0afd897e43504c1228fe46ea03833df29 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 15 Jun 2021 00:51:33 +0900
Subject: [PATCH 3/6] sd-event: use CMP() macro
(cherry picked from commit 06e131477d82b83c5d516e66d6e413affd7c774a)
Related: #1984406
[commit eaab8d57d9db0d98d7e618ba634983c34cdb9c06 from
https://github.com/systemd-rhel/rhel-8/ (branch rhel-8.4.0)]
Signed-off-by: Li Zhou <li.zhou@windriver.com>
---
src/libsystemd/sd-event/sd-event.c | 37 ++++++++++++++----------------
1 file changed, 17 insertions(+), 20 deletions(-)
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index 9b6d2f0..84a874d 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -168,10 +168,9 @@ static int pending_prioq_compare(const void *a, const void *b) {
assert(y->pending);
/* Enabled ones first */
- if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
- return -1;
- if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
- return 1;
+ r = CMP(x->enabled == SD_EVENT_OFF, y->enabled == SD_EVENT_OFF);
+ if (r != 0)
+ return r;
/* Non rate-limited ones first. */
r = CMP(!!x->ratelimited, !!y->ratelimited);
@@ -195,10 +194,9 @@ static int prepare_prioq_compare(const void *a, const void *b) {
assert(y->prepare);
/* Enabled ones first */
- if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
- return -1;
- if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
- return 1;
+ r = CMP(x->enabled == SD_EVENT_OFF, y->enabled == SD_EVENT_OFF);
+ if (r != 0)
+ return r;
/* Non rate-limited ones first. */
r = CMP(!!x->ratelimited, !!y->ratelimited);
@@ -265,18 +263,17 @@ static bool event_source_timer_candidate(const sd_event_source *s) {
static int time_prioq_compare(const void *a, const void *b, usec_t (*time_func)(const sd_event_source *s)) {
const sd_event_source *x = a, *y = b;
+ int r;
/* Enabled ones first */
- if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
- return -1;
- if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
- return 1;
+ r = CMP(x->enabled == SD_EVENT_OFF, y->enabled == SD_EVENT_OFF);
+ if (r != 0)
+ return r;
/* Order "non-pending OR ratelimited" before "pending AND not-ratelimited" */
- if (event_source_timer_candidate(x) && !event_source_timer_candidate(y))
- return -1;
- if (!event_source_timer_candidate(x) && event_source_timer_candidate(y))
- return 1;
+ r = CMP(!event_source_timer_candidate(x), !event_source_timer_candidate(y));
+ if (r != 0)
+ return r;
/* Order by time */
return CMP(time_func(x), time_func(y));
@@ -292,15 +289,15 @@ static int latest_time_prioq_compare(const void *a, const void *b) {
static int exit_prioq_compare(const void *a, const void *b) {
const sd_event_source *x = a, *y = b;
+ int r;
assert(x->type == SOURCE_EXIT);
assert(y->type == SOURCE_EXIT);
/* Enabled ones first */
- if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
- return -1;
- if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
- return 1;
+ r = CMP(x->enabled == SD_EVENT_OFF, y->enabled == SD_EVENT_OFF);
+ if (r != 0)
+ return r;
/* Lower priority values first */
return CMP(x->priority, y->priority);
--
2.17.1

View File

@ -0,0 +1,35 @@
From e2088e9fd7dd09c542d8c456b62dbd2d21ee9e51 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 15 Jun 2021 01:01:48 +0900
Subject: [PATCH 4/6] sd-event: use usec_add()
(cherry picked from commit a595fb5ca9c69c589e758e9ebe3b70ac90450ba3)
Related: #1984406
[commit b8732d647162b50ce9b34de2ad7ae11a53f6e7ba from
https://github.com/systemd-rhel/rhel-8/ (branch rhel-8.4.0)]
Signed-off-by: Li Zhou <li.zhou@windriver.com>
---
src/libsystemd/sd-event/sd-event.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index 84a874d..1cf1c41 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -3677,8 +3677,8 @@ static int arm_watchdog(sd_event *e) {
assert(e->watchdog_fd >= 0);
t = sleep_between(e,
- e->watchdog_last + (e->watchdog_period / 2),
- e->watchdog_last + (e->watchdog_period * 3 / 4));
+ usec_add(e->watchdog_last, (e->watchdog_period / 2)),
+ usec_add(e->watchdog_last, (e->watchdog_period * 3 / 4)));
timespec_store(&its.it_value, t);
--
2.17.1

View File

@ -0,0 +1,48 @@
From 9a3a48fde35fd02981b44ff6b2e184f33377d36c Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 15 Jun 2021 02:03:02 +0900
Subject: [PATCH 5/6] sd-event: make event_source_time_prioq_reshuffle() accept
all event source type
But it does nothing for an event source which is neither a timer nor
ratelimited.
(cherry picked from commit 5c08c7ab23dbf02aaf4e4bbae8e08a195da230a4)
Related: #1984406
[commit 9f044118dbc6a0f04b3820ffaa9d4c7807ae48a7
https://github.com/systemd-rhel/rhel-8/ (branch rhel-8.4.0)]
Signed-off-by: Li Zhou <li.zhou@windriver.com>
---
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 1cf1c41..6215bac 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -771,14 +771,15 @@ static void event_source_time_prioq_reshuffle(sd_event_source *s) {
assert(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. */
+ * pending, enable state, and ratelimiting state. Makes sure the two prioq's are ordered
+ * properly again. */
if (s->ratelimited)
d = &s->event->monotonic;
- else {
- assert(EVENT_SOURCE_IS_TIME(s->type));
+ else if (EVENT_SOURCE_IS_TIME(s->type))
assert_se(d = event_get_clock_data(s->event, s->type));
- }
+ else
+ return; /* no-op for an event source which is neither a timer nor ratelimited. */
prioq_reshuffle(d->earliest, s, &s->earliest_index);
prioq_reshuffle(d->latest, s, &s->latest_index);
--
2.17.1

View File

@ -0,0 +1,101 @@
From 71552a073ed08beb227b9b007fb9818f08923baa Mon Sep 17 00:00:00 2001
From: Li Zhou <li.zhou@windriver.com>
Date: Tue, 26 Oct 2021 11:46:48 +0800
Subject: [PATCH 6/6] sd-event: always reshuffle time prioq on changing
online/offline state
Before 81107b8419c39f726fd2805517a5b9faab204e59, the compare functions
for the latest or earliest prioq did not handle ratelimited flag.
So, it was ok to not reshuffle the time prioq when changing the flag.
But now, those two compare functions also compare the source is
ratelimited or not. So, it is necessary to reshuffle the time prioq
after changing the ratelimited flag.
Hopefully fixes #19903.
(cherry picked from commit 2115b9b6629eeba7bc9f42f757f38205febb1cb7)
Related: #1984406
[commit f5611a22d4a65ef440352792085774ce898adb0f from
https://github.com/systemd-rhel/rhel-8/ (branch rhel-8.4.0)
LZ: Adapt the patch for context changes and no real change on the
patch.]
Signed-off-by: Li Zhou <li.zhou@windriver.com>
---
src/libsystemd/sd-event/sd-event.c | 33 ++++++++++--------------------
1 file changed, 11 insertions(+), 22 deletions(-)
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index 6215bac..c17b368 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -2370,14 +2370,6 @@ static int event_source_offline(
source_io_unregister(s);
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:
event_gc_signal_data(s->event, &s->priority, s->signal.sig);
break;
@@ -2398,6 +2390,11 @@ static int event_source_offline(
prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
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_DEFER:
case SOURCE_POST:
case SOURCE_INOTIFY:
@@ -2407,6 +2404,9 @@ static int event_source_offline(
assert_not_reached("Wut? I shouldn't exist.");
}
+ /* Always reshuffle time prioq, as the ratelimited flag may be changed. */
+ event_source_time_prioq_reshuffle(s);
+
return 1;
}
@@ -2496,22 +2496,11 @@ static int event_source_online(
s->ratelimited = ratelimited;
/* 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:
+ if (s->type == SOURCE_EXIT)
prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
- break;
- default:
- break;
- }
+ /* Always reshuffle time prioq, as the ratelimited flag may be changed. */
+ event_source_time_prioq_reshuffle(s);
return 1;
}
--
2.17.1

View File

@ -0,0 +1,26 @@
# STX Patches
851-inject-millisec-in-syslog-date.patch
# This cluster of patches relates to fixing redhat bug #1819868
# "systemd excessively reads mountinfo and udev in dense container environments"
# Patch (3) for solving #1819868
909-sd-event-split-clock-data-allocation-out-of-sd_event.patch
# Patch (4) for solving #1819868
910-sd-event-split-out-code-to-add-remove-timer-event-so.patch
# Patch (6) for solving #1819868
913-sd-event-remove-earliest_index-latest_index-into-com.patch
# Patch (9) for solving #1819868
919-sd-event-add-ability-to-ratelimit-event-sources.patch
# Patch (10) for solving #1819868
920-core-prevent-excessive-proc-self-mountinfo-parsing.patch
skip-some-testcases.patch
# This cluster of patches relates to fixing redhat bug #1968528
# "fix rate-limiting of mount events"
922-sd-event-change-ordering-of-pending-ratelimited-even.patch
923-sd-event-drop-unnecessary-else.patch
924-sd-event-use-CMP-macro.patch
925-sd-event-use-usec_add.patch
926-sd-event-make-event_source_time_prioq_reshuffle-acce.patch
927-sd-event-always-reshuffle-time-prioq-on-changing-onl.patch

View File

@ -0,0 +1,30 @@
--- a/src/test/meson.build
+++ b/src/test/meson.build
@@ -224,9 +224,9 @@ tests += [
[],
[]],
- [['src/test/test-util.c'],
- [],
- []],
+# [['src/test/test-util.c'],
+# [],
+# []],
[['src/test/test-json.c'],
[],
@@ -1103,10 +1103,10 @@ tests += [
libsystemd_network],
[]],
- [['src/libsystemd-network/test-dhcp-server.c'],
- [libshared,
- libsystemd_network],
- []],
+# [['src/libsystemd-network/test-dhcp-server.c'],
+# [libshared,
+# libsystemd_network],
+# []],
[['src/libsystemd-network/test-ipv4ll.c',
'src/libsystemd-network/arp-util.h',