core: deserialize soft-reboot shutdown timestamps into previous-* fields
Until now the SHUTDOWN_START/FINISH timestamps were carried across a soft-reboot in the same fields, so afterwards they described the previous boot rather than the current one, mixing current- and previous-boot data in the same set. Mirror what is now done on kexec and move them into the PREVIOUS_SHUTDOWN_* fields on deserialization. Also reset local timestamps for events that rerun (eg: generators, units loading, etc) on soft-reboot and switch-root.
This commit is contained in:
@@ -45,7 +45,6 @@ int acquire_boot_times(sd_bus *bus, bool require_finished, BootTimes **ret) {
|
||||
{ "FinishTimestampMonotonic", "t", NULL, offsetof(BootTimes, finish_time) },
|
||||
{ "SecurityStartTimestampMonotonic", "t", NULL, offsetof(BootTimes, security_start_time) },
|
||||
{ "SecurityFinishTimestampMonotonic", "t", NULL, offsetof(BootTimes, security_finish_time) },
|
||||
{ "ShutdownStartTimestampMonotonic", "t", NULL, offsetof(BootTimes, shutdown_start_time) },
|
||||
{ "PreviousShutdownStartTimestampMonotonic", "t", NULL, offsetof(BootTimes, previous_shutdown_start_time) },
|
||||
{ "PreviousShutdownFinishTimestampMonotonic", "t", NULL, offsetof(BootTimes, previous_shutdown_finish_time) },
|
||||
{ "PreviousShutdownLateStartTimestampMonotonic", "t", NULL, offsetof(BootTimes, previous_shutdown_late_start_time) },
|
||||
@@ -100,7 +99,7 @@ int acquire_boot_times(sd_bus *bus, bool require_finished, BootTimes **ret) {
|
||||
times.initrd_security_start_time = times.initrd_security_finish_time =
|
||||
times.initrd_generators_start_time = times.initrd_generators_finish_time =
|
||||
times.initrd_unitsload_start_time = times.initrd_unitsload_finish_time = 0;
|
||||
times.reverse_offset = times.shutdown_start_time;
|
||||
times.reverse_offset = times.previous_shutdown_start_time;
|
||||
|
||||
/* Clamp all timestamps to avoid showing huge graphs */
|
||||
if (timestamp_is_set(times.finish_time))
|
||||
@@ -366,8 +365,8 @@ int acquire_time_data(sd_bus *bus, bool require_finished, UnitTimes **out) {
|
||||
|
||||
/* Activated in the previous soft-reboot iteration? Ignore it, we want new activations */
|
||||
if (boot_times->soft_reboots_count > 0 &&
|
||||
((t->activated > 0 && t->activated < boot_times->shutdown_start_time) ||
|
||||
(t->activating > 0 && t->activating < boot_times->shutdown_start_time)))
|
||||
((t->activated > 0 && t->activated < boot_times->previous_shutdown_start_time) ||
|
||||
(t->activating > 0 && t->activating < boot_times->previous_shutdown_start_time)))
|
||||
continue;
|
||||
|
||||
subtract_timestamp(&t->activating, boot_times->reverse_offset);
|
||||
|
||||
@@ -12,7 +12,6 @@ typedef struct BootTimes {
|
||||
usec_t initrd_time;
|
||||
usec_t userspace_time;
|
||||
usec_t finish_time;
|
||||
usec_t shutdown_start_time;
|
||||
usec_t previous_shutdown_start_time;
|
||||
usec_t previous_shutdown_finish_time;
|
||||
usec_t previous_shutdown_late_start_time;
|
||||
|
||||
@@ -35,12 +35,12 @@ int manager_open_serialization(Manager *m, FILE **ret_f) {
|
||||
return open_serialization_file("systemd-state", ret_f);
|
||||
}
|
||||
|
||||
static bool manager_timestamp_shall_serialize(ManagerObjective o, ManagerTimestamp t) {
|
||||
if (!in_initrd() && o != MANAGER_SOFT_REBOOT)
|
||||
static bool manager_timestamp_shall_serialize(ManagerTimestamp t) {
|
||||
if (!in_initrd())
|
||||
return true;
|
||||
|
||||
/* The following timestamps only apply to the host system (or first boot in case of soft-reboot),
|
||||
* hence only serialize them there. */
|
||||
/* In the initrd the following timestamps describe the host boot we are about to hand over to,
|
||||
* which re-takes them, so don't serialize them. */
|
||||
return !IN_SET(t,
|
||||
MANAGER_TIMESTAMP_USERSPACE, MANAGER_TIMESTAMP_FINISH,
|
||||
MANAGER_TIMESTAMP_SECURITY_START, MANAGER_TIMESTAMP_SECURITY_FINISH,
|
||||
@@ -48,6 +48,39 @@ static bool manager_timestamp_shall_serialize(ManagerObjective o, ManagerTimesta
|
||||
MANAGER_TIMESTAMP_UNITS_LOAD_START, MANAGER_TIMESTAMP_UNITS_LOAD_FINISH);
|
||||
}
|
||||
|
||||
static ManagerTimestamp map_timestamp_serialization(ManagerObjective previous_objective, ManagerTimestamp t) {
|
||||
/* Returns the timestamp field a serialized timestamp 't' should be deserialized into, given the
|
||||
* objective the previous instance serialized under, or _MANAGER_TIMESTAMP_INVALID to drop it. */
|
||||
|
||||
/* Both across a soft-reboot and a switch-root the new instance runs through the early boot phases
|
||||
* again, so drop those timestamps to have them re-measured; the firmware/loader/kernel/initrd ones
|
||||
* are kept. */
|
||||
if (IN_SET(previous_objective, MANAGER_SOFT_REBOOT, MANAGER_SWITCH_ROOT) &&
|
||||
IN_SET(t,
|
||||
MANAGER_TIMESTAMP_USERSPACE, MANAGER_TIMESTAMP_FINISH,
|
||||
MANAGER_TIMESTAMP_SECURITY_START, MANAGER_TIMESTAMP_SECURITY_FINISH,
|
||||
MANAGER_TIMESTAMP_GENERATORS_START, MANAGER_TIMESTAMP_GENERATORS_FINISH,
|
||||
MANAGER_TIMESTAMP_UNITS_LOAD_START, MANAGER_TIMESTAMP_UNITS_LOAD_FINISH))
|
||||
return _MANAGER_TIMESTAMP_INVALID;
|
||||
|
||||
/* Across a soft-reboot the old instance's shutdown timestamps describe the boot that is going away,
|
||||
* so move them into the previous-shutdown-* fields. */
|
||||
if (previous_objective == MANAGER_SOFT_REBOOT)
|
||||
switch (t) {
|
||||
|
||||
case MANAGER_TIMESTAMP_SHUTDOWN_START:
|
||||
return MANAGER_TIMESTAMP_PREVIOUS_SHUTDOWN_START;
|
||||
|
||||
case MANAGER_TIMESTAMP_SHUTDOWN_FINISH:
|
||||
return MANAGER_TIMESTAMP_PREVIOUS_SHUTDOWN_FINISH;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static void manager_serialize_uid_refs_internal(
|
||||
FILE *f,
|
||||
Hashmap *uid_refs,
|
||||
@@ -130,7 +163,7 @@ int manager_serialize(
|
||||
for (ManagerTimestamp q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) {
|
||||
_cleanup_free_ char *joined = NULL;
|
||||
|
||||
if (!manager_timestamp_shall_serialize(m->objective, q))
|
||||
if (!manager_timestamp_shall_serialize(q))
|
||||
continue;
|
||||
|
||||
joined = strjoin(manager_timestamp_to_string(q), "-timestamp");
|
||||
@@ -791,9 +824,11 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (q < _MANAGER_TIMESTAMP_MAX) /* found it */
|
||||
(void) deserialize_dual_timestamp(val, m->timestamps + q);
|
||||
else if (!STARTSWITH_SET(l, "kdbus-fd=", "honor-device-enumeration=", "ready-sent=", "cgroups-agent-fd=")) /* ignore deprecated values */
|
||||
if (q < _MANAGER_TIMESTAMP_MAX) { /* found it */
|
||||
ManagerTimestamp target = map_timestamp_serialization(m->previous_objective, q);
|
||||
if (target >= 0)
|
||||
(void) deserialize_dual_timestamp(val, m->timestamps + target);
|
||||
} else if (!STARTSWITH_SET(l, "kdbus-fd=", "honor-device-enumeration=", "ready-sent=", "cgroups-agent-fd=")) /* ignore deprecated values */
|
||||
log_notice("Unknown serialization item '%s', ignoring.", l);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -4038,7 +4038,7 @@ static void manager_notify_finished(Manager *m) {
|
||||
/* The soft-reboot case, where we only report data for the last reboot */
|
||||
firmware_usec = loader_usec = initrd_usec = kernel_usec = 0;
|
||||
total_usec = userspace_usec = usec_sub_unsigned(m->timestamps[MANAGER_TIMESTAMP_FINISH].monotonic,
|
||||
m->timestamps[MANAGER_TIMESTAMP_SHUTDOWN_START].monotonic);
|
||||
m->timestamps[MANAGER_TIMESTAMP_PREVIOUS_SHUTDOWN_START].monotonic);
|
||||
|
||||
log_struct(LOG_INFO,
|
||||
LOG_MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED_STR),
|
||||
|
||||
+6
-4
@@ -84,10 +84,12 @@ typedef enum ManagerObjective {
|
||||
*
|
||||
* 9. TIMESTAMP_PREVIOUS_SHUTDOWN_START, TIMESTAMP_PREVIOUS_SHUTDOWN_FINISH,
|
||||
* TIMESTAMP_PREVIOUS_SHUTDOWN_LATE_START and TIMESTAMP_PREVIOUS_SHUTDOWN_LATE_FINISH describe the
|
||||
* shutdown of the *previous* boot, restored from the LUO payload after a kexec-based live update
|
||||
* (the LATE_* ones are taken by systemd-shutdown). Like TIMESTAMP_FIRMWARE/LOADER/KERNEL they refer
|
||||
* to events before the current systemd cycle took over, hence they are kept distinct from the
|
||||
* current cycle's SHUTDOWN_START/FINISH instead of overwriting them.
|
||||
* shutdown of the *previous* boot: either restored from the LUO payload after a kexec-based live
|
||||
* update, or carried over from the current cycle's SHUTDOWN_START/FINISH across a soft-reboot. The
|
||||
* LATE_* ones are taken by systemd-shutdown and hence only set for the kexec case. Like
|
||||
* TIMESTAMP_FIRMWARE/LOADER/KERNEL they refer to events before the current systemd cycle took over,
|
||||
* hence they are kept distinct from the current cycle's SHUTDOWN_START/FINISH instead of overwriting
|
||||
* them.
|
||||
*/
|
||||
|
||||
typedef enum ManagerTimestamp {
|
||||
|
||||
Reference in New Issue
Block a user