core: add ReloadCount to Manager and bump on successful reload
Introduce a counter that tracks how many configuration reloads have been successfully completed by the manager. The increment lives in manager_reload() right after the "point of no return", so failed reload attempts that bail out earlier (e.g. during serialization) do not bump the counter. It is accessible as a new ReloadCount property to org.freedesktop.systemd1.Manager (D-Bus) and ReloadCount to io.systemd.Manager.Describe (Varlink). Also add an integration test for ReloadCount that verifies that the new ReloadCount property increments by one per daemon-reload, accumulates correctly across multiple reloads, and that D-Bus and Varlink return identical values. Also tests that the counter reset after a reexec. Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com> Signed-off-by: Simon Lucido <simonlucido@meta.com>
This commit is contained in:
committed by
Luca Boccassi
parent
db28490c9f
commit
d667b6b97f
@@ -63,6 +63,12 @@ CHANGES WITH 261 in spe:
|
||||
require direct IMDS access. The new meson option "-Dimds-network="
|
||||
can be used to change the default mode to "locked" at build-time.
|
||||
|
||||
* The manager exposes a new ReloadCount property on its D-Bus and
|
||||
Varlink interfaces (org.freedesktop.systemd1.Manager and
|
||||
io.systemd.Manager respectively). The counter increments after
|
||||
each successfully completed daemon-reload. It is not preserved
|
||||
across daemon-reexec.
|
||||
|
||||
Changes in systemd-sysext/systemd-confext:
|
||||
|
||||
* New initrd services systemd-sysext-sysroot.service and
|
||||
|
||||
@@ -572,6 +572,8 @@ node /org/freedesktop/systemd1 {
|
||||
readonly s CtrlAltDelBurstAction = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly u SoftRebootsCount = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||
readonly t ReloadCount = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly b DefaultMemoryZSwapWriteback = ...;
|
||||
};
|
||||
@@ -1279,6 +1281,8 @@ node /org/freedesktop/systemd1 {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="SoftRebootsCount"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="ReloadCount"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="DefaultMemoryZSwapWriteback"/>
|
||||
|
||||
<!--End of Autogenerated section-->
|
||||
@@ -1866,6 +1870,10 @@ node /org/freedesktop/systemd1 {
|
||||
<para><varname>SoftRebootsCount</varname> encodes how many soft-reboots were successfully completed
|
||||
since the last full boot. Starts at <literal>0</literal>.</para>
|
||||
|
||||
<para><varname>ReloadCount</varname> encodes the number of successfully completed configuration
|
||||
reloads of the manager. The counter is reset to <literal>0</literal> on
|
||||
<command>daemon-reexec</command> and on the initial boot.</para>
|
||||
|
||||
<para><varname>Virtualization</varname> contains a short ID string describing the virtualization
|
||||
technology the system runs in. On bare-metal hardware this is the empty string. Otherwise, it contains
|
||||
an identifier such as <literal>kvm</literal>, <literal>vmware</literal> and so on. For a full list of
|
||||
@@ -12646,8 +12654,9 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
|
||||
<para><varname>DefaultMemoryZSwapWriteback</varname>,
|
||||
<varname>DefaultCPUPressureThresholdUSec</varname>,
|
||||
<varname>DefaultCPUPressureWatch</varname>,
|
||||
<varname>DefaultIOPressureThresholdUSec</varname>, and
|
||||
<varname>DefaultIOPressureWatch</varname> were added in version 261.</para>
|
||||
<varname>DefaultIOPressureThresholdUSec</varname>,
|
||||
<varname>DefaultIOPressureWatch</varname>, and
|
||||
<varname>ReloadCount</varname> were added in version 261.</para>
|
||||
</refsect2>
|
||||
<refsect2>
|
||||
<title>Unit Objects</title>
|
||||
|
||||
@@ -2978,6 +2978,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
|
||||
SD_BUS_PROPERTY("DefaultRestrictSUIDSGID", "b", bus_property_get_bool, offsetof(Manager, defaults.restrict_suid_sgid), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("CtrlAltDelBurstAction", "s", bus_property_get_emergency_action, offsetof(Manager, cad_burst_action), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("SoftRebootsCount", "u", bus_property_get_unsigned, offsetof(Manager, soft_reboots_count), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("ReloadCount", "t", NULL, offsetof(Manager, reload_count), 0),
|
||||
SD_BUS_PROPERTY("DefaultMemoryZSwapWriteback", "b", bus_property_get_bool, offsetof(Manager, defaults.memory_zswap_writeback), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
|
||||
/* deprecated cgroup v1 property */
|
||||
|
||||
@@ -3650,6 +3650,10 @@ int manager_reload(Manager *m) {
|
||||
/* 💀 This is the point of no return, from here on there is no way back. 💀 */
|
||||
reloading = NULL;
|
||||
|
||||
/* Bump before sending the Reloading signal, so any client that reads
|
||||
* ReloadCount in response to that signal observes the new value. */
|
||||
m->reload_count = saturate_add(m->reload_count, 1, UINT64_MAX);
|
||||
|
||||
bus_manager_send_reloading(m, true);
|
||||
|
||||
/* Start by flushing out all jobs and units, all generated units, all runtime environments, all dynamic users
|
||||
|
||||
@@ -492,6 +492,9 @@ typedef struct Manager {
|
||||
|
||||
unsigned soft_reboots_count;
|
||||
|
||||
/* The number of successfully completed configuration reloads. */
|
||||
uint64_t reload_count;
|
||||
|
||||
/* Original ambient capabilities when we were initialized */
|
||||
uint64_t saved_ambient_set;
|
||||
} Manager;
|
||||
|
||||
@@ -193,7 +193,8 @@ static int manager_runtime_build_json(sd_json_variant **ret, const char *name, v
|
||||
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("WatchdogLastPingTimestamp", watchdog_get_last_ping_as_dual_timestamp(&watchdog_last_ping)),
|
||||
SD_JSON_BUILD_PAIR_STRING("SystemState", manager_state_to_string(manager_state(m))),
|
||||
SD_JSON_BUILD_PAIR_UNSIGNED("ExitCode", m->return_value),
|
||||
SD_JSON_BUILD_PAIR_UNSIGNED("SoftRebootsCount", m->soft_reboots_count));
|
||||
SD_JSON_BUILD_PAIR_UNSIGNED("SoftRebootsCount", m->soft_reboots_count),
|
||||
SD_JSON_BUILD_PAIR_UNSIGNED("ReloadCount", m->reload_count));
|
||||
}
|
||||
|
||||
int vl_method_describe_manager(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
|
||||
|
||||
@@ -194,7 +194,9 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
|
||||
SD_VARLINK_FIELD_COMMENT("Exit code of the manager"),
|
||||
SD_VARLINK_DEFINE_FIELD(ExitCode, SD_VARLINK_INT, 0),
|
||||
SD_VARLINK_FIELD_COMMENT("Encodes how many soft-reboots were successfully completed"),
|
||||
SD_VARLINK_DEFINE_FIELD(SoftRebootsCount, SD_VARLINK_INT, 0));
|
||||
SD_VARLINK_DEFINE_FIELD(SoftRebootsCount, SD_VARLINK_INT, 0),
|
||||
SD_VARLINK_FIELD_COMMENT("Number of successfully completed configuration reloads"),
|
||||
SD_VARLINK_DEFINE_FIELD(ReloadCount, SD_VARLINK_INT, 0));
|
||||
|
||||
static SD_VARLINK_DEFINE_METHOD(
|
||||
Describe,
|
||||
|
||||
Executable
+51
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
set -eux
|
||||
set -o pipefail
|
||||
|
||||
# Verify that the manager exposes a ReloadCount property that increments on
|
||||
# every daemon-reload, resets to zero across daemon-reexec (since the count
|
||||
# is not serialized), and is reachable over both D-Bus and Varlink.
|
||||
|
||||
read_count_dbus() {
|
||||
busctl -j get-property org.freedesktop.systemd1 \
|
||||
/org/freedesktop/systemd1 \
|
||||
org.freedesktop.systemd1.Manager \
|
||||
ReloadCount | jq -r '.data'
|
||||
}
|
||||
|
||||
read_count_varlink() {
|
||||
varlinkctl call /run/systemd/io.systemd.Manager \
|
||||
io.systemd.Manager.Describe '{}' | jq -r '.runtime.ReloadCount'
|
||||
}
|
||||
|
||||
# Sanity: both transports must agree.
|
||||
dbus_count=$(read_count_dbus)
|
||||
varlink_count=$(read_count_varlink)
|
||||
(( dbus_count == varlink_count ))
|
||||
|
||||
# A single reload bumps the counter by one.
|
||||
before=$(read_count_dbus)
|
||||
systemctl daemon-reload
|
||||
(( $(read_count_dbus) == before + 1 ))
|
||||
|
||||
# Multiple reloads accumulate.
|
||||
systemctl daemon-reload
|
||||
systemctl daemon-reload
|
||||
(( $(read_count_dbus) == before + 3 ))
|
||||
|
||||
# And both transports still agree after the reload.
|
||||
dbus_count=$(read_count_dbus)
|
||||
varlink_count=$(read_count_varlink)
|
||||
(( dbus_count == varlink_count ))
|
||||
|
||||
# A daemon-reexec resets the counter back to zero on both transports, since
|
||||
# reload_count lives only in memory and is not carried across the reexec.
|
||||
# `systemctl daemon-reexec` returns as soon as the old PID 1 closes its bus
|
||||
# connection, which is before the new PID 1 has rebound /run/systemd/private.
|
||||
# Use --watch-bind=yes to block on inotify until the new socket is live.
|
||||
systemctl daemon-reexec
|
||||
busctl --watch-bind=yes call org.freedesktop.systemd1 /org/freedesktop/systemd1 \
|
||||
org.freedesktop.DBus.Peer Ping >/dev/null
|
||||
(( $(read_count_dbus) == 0 ))
|
||||
(( $(read_count_varlink) == 0 ))
|
||||
Reference in New Issue
Block a user