readonly s CtrlAltDelBurstAction = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly u SoftRebootsCount = ...;
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly u KExecsCount = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly t ReloadCount = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
<variablelist class="dbus-property" generated="True" extra-ref="SoftRebootsCount"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="KExecsCount"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="ReloadCount"/>
<variablelist class="dbus-property" generated="True" extra-ref="DefaultMemoryZSwapWriteback"/>
<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>KExecsCount</varname> encodes how many kexec-based live updates were successfully
+ completed since the last full boot. Starts at <literal>0</literal>. The counter is preserved across the
+ kexec through the Live Update Orchestrator (LUO), and is hence <literal>0</literal> when the kernel does
+ not provide LUO support.</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>
<varname>ReloadCount</varname>,
<varname>EventLoopRateLimitIntervalUSec</varname>, and
<varname>EventLoopRateLimitBurst</varname> were added in version 261.</para>
+ <para><varname>KExecsCount</varname> was added in version 262.</para>
</refsect2>
<refsect2>
<title>Unit Objects</title>
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("KExecsCount", "u", bus_property_get_unsigned, offsetof(Manager, kexecs_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),
struct {
uint64_t version;
+ sd_json_variant *state;
sd_json_variant *units;
} q = {};
static const sd_json_dispatch_field mapping_dispatch_table[] = {
{ "version", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, voffsetof(q, version), SD_JSON_MANDATORY },
+ { "state", SD_JSON_VARIANT_OBJECT, sd_json_dispatch_variant_noref, voffsetof(q, state), 0 },
{ "units", SD_JSON_VARIANT_OBJECT, sd_json_dispatch_variant_noref, voffsetof(q, units), 0 },
{}
};
return 0;
}
+ struct {
+ unsigned kexecs_count;
+ } state_data = {};
+
+ static const sd_json_dispatch_field state_dispatch_table[] = {
+ { "kexecsCount", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint, voffsetof(state_data, kexecs_count), 0 },
+ {}
+ };
+
+ r = sd_json_dispatch(q.state, state_dispatch_table, SD_JSON_ALLOW_EXTENSIONS|SD_JSON_LOG, &state_data);
+ if (r >= 0)
+ m->kexecs_count = state_data.kexecs_count;
+
+ /* If we found a LUO session then by definition we have just successfully kexec rebooted */
+ (void) INC_SAFE(&m->kexecs_count, 1);
+
/* Retrieve all fds from the session and dispatch each to the named unit, eagerly loading the
* unit if necessary. */
JSON_VARIANT_OBJECT_FOREACH(unit_id, unit_json, q.units) {
return log_error_errno(r, "Failed to add unit to LUO serialization JSON: %m");
}
- if (n_serialized == 0) {
- log_debug("No fd store entries to serialize for LUO.");
- *ret_f = NULL;
- *ret_fds = NULL;
- return 0;
- }
-
r = sd_json_buildo(
&root,
SD_JSON_BUILD_PAIR_UNSIGNED("version", LUO_PROTOCOL_VERSION),
+ SD_JSON_BUILD_PAIR("state",
+ SD_JSON_BUILD_OBJECT(
+ SD_JSON_BUILD_PAIR_UNSIGNED("kexecsCount", m->kexecs_count))),
SD_JSON_BUILD_PAIR_CONDITION(!!units, "units", SD_JSON_BUILD_VARIANT(units)));
if (r < 0)
return log_error_errno(r, "Failed to build LUO serialization JSON: %m");
(void) serialize_item(f, "previous-objective", manager_objective_to_string(m->objective));
(void) serialize_item_format(f, "soft-reboots-count", "%u", m->soft_reboots_count);
+ (void) serialize_item_format(f, "kexecs-count", "%u", m->kexecs_count);
(void) serialize_item_format(f, "fd-store-upstream-next-index", "%" PRIu64, m->fd_store_upstream_next_index);
for (ManagerTimestamp q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) {
log_notice("Failed to parse soft reboots counter '%s', ignoring.", val);
else
m->soft_reboots_count = n;
+ } else if ((val = startswith(l, "kexecs-count="))) {
+ unsigned n;
+
+ if (safe_atou(val, &n) < 0)
+ log_notice("Failed to parse kexecs counter '%s', ignoring.", val);
+ else
+ m->kexecs_count = n;
} else if ((val = startswith(l, "fd-store-upstream-next-index="))) {
if (safe_atou64(val, &m->fd_store_upstream_next_index) < 0)
log_notice("Failed to parse fd-store-upstream-next-index '%s', ignoring.", val);
unsigned soft_reboots_count;
+ /* When LUO is enabled we can count consecutive kexec reboots. */
+ unsigned kexecs_count;
+
/* The number of successfully completed configuration reloads. */
uint64_t reload_count;
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("KExecsCount", m->kexecs_count),
SD_JSON_BUILD_PAIR_UNSIGNED("ReloadCount", m->reload_count));
}
if (!sd_json_variant_is_unsigned(version))
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "LUO serialization 'version' field is missing or not an unsigned integer");
+ sd_json_variant *state = sd_json_variant_by_key(serialization, "state");
+
r = sd_json_buildo(
&mapping,
SD_JSON_BUILD_PAIR("version", SD_JSON_BUILD_VARIANT(version)),
+ SD_JSON_BUILD_PAIR_CONDITION(!!state, "state", SD_JSON_BUILD_VARIANT(state)),
SD_JSON_BUILD_PAIR_CONDITION(!!units, "units", SD_JSON_BUILD_VARIANT(units)));
if (r < 0)
return log_error_errno(r, "Failed to build LUO mapping: %m");
*
* {
* "version": 1,
+ * "state": { },
* "units": {
* "unit-name.service": {
* "fdstore": [
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_FIELD_COMMENT("Encodes how many consecutive kexec reboots were successfully completed since the last full boot. Zero if the Live Update Orchestrator is not available."),
+ SD_VARLINK_DEFINE_FIELD(KExecsCount, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Number of successfully completed configuration reloads"),
SD_VARLINK_DEFINE_FIELD(ReloadCount, SD_VARLINK_INT, 0));
# Verify that the fd store of the main test service survived the kexec.
/usr/lib/systemd/tests/unit-tests/manual/test-luo check
+ assert_eq "$(busctl -j get-property org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager KExecsCount | jq -r '.data')" "1"
+
# Negative path: a unit stored a child LUO session named like PID 1's own
# ("systemd") on the first boot. PID 1's serialize step must have refused to
# serialize that fd store entry (anti-hijack guard in