From: Lennart Poettering Date: Tue, 23 Apr 2024 21:27:23 +0000 (+0200) Subject: manager: switch service unit type over to using new handoff timestamping logic X-Git-Tag: v256-rc1~14^2~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3c1d1ca146d59c6dad808e7fc6e778ee65875ab8;p=thirdparty%2Fsystemd.git manager: switch service unit type over to using new handoff timestamping logic Also: rename Handover → Handoff. I think it makes it clearer that this is not really about handing over any resources, but that the executor is out off the game from that point on. --- diff --git a/NEWS b/NEWS index e587ade01f1..ac7f0f1154d 100644 --- a/NEWS +++ b/NEWS @@ -198,13 +198,12 @@ CHANGES WITH 256-rc1: PID 1 will start to have the effect of shutting down the system cleanly). - * New D-Bus properties ExecMainHandoverTimestamp and - ExecMainHandoverTimestampMonotonic are now published by services of - type exec, dbus, notify, and notify-reload. - This timestamp is taken as the very last operation before executing - a service's binary, which allows users to accurately track when - execution control of the process is handed over from systemd to the - payload. + * New D-Bus properties ExecMainHandoffTimestamp and + ExecMainHandoffTimestampMonotonic are now published by services + units. This timestamp is taken as the very last operation before + handing off control to invoked binaries. This information is + available for other unit types that fork off processes (i.e. mount, + swap, socket units), but currently only via "systemd-analyze dump". Journal: diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml index ca8696bed5e..9e29eda4e07 100644 --- a/man/org.freedesktop.systemd1.xml +++ b/man/org.freedesktop.systemd1.xml @@ -2766,8 +2766,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { readonly t ExecMainStartTimestampMonotonic = ...; readonly t ExecMainExitTimestamp = ...; readonly t ExecMainExitTimestampMonotonic = ...; - readonly t ExecMainHandoverTimestamp = ...; - readonly t ExecMainHandoverTimestampMonotonic = ...; + readonly t ExecMainHandoffTimestamp = ...; + readonly t ExecMainHandoffTimestampMonotonic = ...; readonly u ExecMainPID = ...; readonly i ExecMainCode = ...; readonly i ExecMainStatus = ...; @@ -4057,9 +4057,9 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { - + - + @@ -4710,18 +4710,20 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { ExecMainStartTimestamp, ExecMainStartTimestampMonotonic, ExecMainExitTimestamp, ExecMainExitTimestampMonotonic, - ExecMainHandoverTimestamp, ExecMainHandoverTimestampMonotonic, + ExecMainHandoffTimestamp, ExecMainHandoffTimestampMonotonic, ExecMainPID, ExecMainCode, ExecMainStatus contain information about the main process of the service as far as it is known. The - ExecMainStartTimestamp timestamps record when the main child process is spawned by - the service manager. ExecMainExitTimestamp timestamps record when the main child - process exit has been detected by the service manager. ExecMainHandoverTimestamp - timestamps record when the service executable is executed by systemd-executor for - services of type exec, dbus, notify, and - notify-reload. This is often the same runtime information that is stored in - ExecStart=. However, it deviates for Type=forking services where - the main process of the service is not forked off systemd directly. These fields either contain - information of the last run of the process or of the current running process. + ExecMainStartTimestamp timestamps record when the main process of the service is + created. ExecMainExitTimestamp timestamps record when the main process exit has been + detected by the service manager. ExecMainHandoffTimestamp timestamps records when + the service binary is about to be executed by systemd-executor (this timestamp is + recorded regardless if the immediately following execve() system call succeeds or + fails). This is often the same runtime information that is also maintained for + ExecStart=. However, it deviates for services with Type=forking + as well as services that use MAINPID= sd_notify() messages as + the main process of the service is not forked off by the service manager directly in that case. These + fields either contain information of the last run of the process or of the current running + process. MainPID and ControlPID contain the main and control PID of the service. The main PID is the current main PID of the service and is 0 when the service currently @@ -12067,8 +12069,8 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \ EffectiveMemoryMax, EffectiveTasksMax, MemoryZSwapWriteback, - ExecMainHandoverTimestampMonotonic, and - ExecMainHandoverTimestamp were added in version 256. + ExecMainHandoffTimestampMonotonic, and + ExecMainHandoffTimestamp were added in version 256. Socket Unit Objects diff --git a/src/core/dbus-execute.h b/src/core/dbus-execute.h index a1205b09971..4b7cb86d3e5 100644 --- a/src/core/dbus-execute.h +++ b/src/core/dbus-execute.h @@ -9,7 +9,7 @@ #define BUS_EXEC_STATUS_VTABLE(prefix, offset, flags) \ BUS_PROPERTY_DUAL_TIMESTAMP(prefix "StartTimestamp", (offset) + offsetof(ExecStatus, start_timestamp), flags), \ BUS_PROPERTY_DUAL_TIMESTAMP(prefix "ExitTimestamp", (offset) + offsetof(ExecStatus, exit_timestamp), flags), \ - BUS_PROPERTY_DUAL_TIMESTAMP(prefix "HandoverTimestamp", (offset) + offsetof(ExecStatus, handover_timestamp), flags), \ + BUS_PROPERTY_DUAL_TIMESTAMP(prefix "HandoffTimestamp", (offset) + offsetof(ExecStatus, handoff_timestamp), flags), \ SD_BUS_PROPERTY(prefix "PID", "u", bus_property_get_pid, (offset) + offsetof(ExecStatus, pid), flags), \ SD_BUS_PROPERTY(prefix "Code", "i", bus_property_get_int, (offset) + offsetof(ExecStatus, code), flags), \ SD_BUS_PROPERTY(prefix "Status", "i", bus_property_get_int, (offset) + offsetof(ExecStatus, status), flags) diff --git a/src/core/execute.c b/src/core/execute.c index 26a4bf1b6f5..7528629739b 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1842,6 +1842,19 @@ void exec_status_exit(ExecStatus *s, const ExecContext *context, pid_t pid, int (void) utmp_put_dead_process(context->utmp_id, pid, code, status); } +void exec_status_handoff(ExecStatus *s, const struct ucred *ucred, const dual_timestamp *ts) { + assert(s); + assert(ucred); + assert(ts); + + if (ucred->pid != s->pid) + *s = (ExecStatus) { + .pid = ucred->pid, + }; + + s->handoff_timestamp = *ts; +} + void exec_status_reset(ExecStatus *s) { assert(s); @@ -1866,10 +1879,10 @@ void exec_status_dump(const ExecStatus *s, FILE *f, const char *prefix) { "%sStart Timestamp: %s\n", prefix, FORMAT_TIMESTAMP(s->start_timestamp.realtime)); - if (dual_timestamp_is_set(&s->handover_timestamp)) + if (dual_timestamp_is_set(&s->handoff_timestamp)) fprintf(f, - "%sHandover Timestamp: %s\n", - prefix, FORMAT_TIMESTAMP(s->handover_timestamp.realtime)); + "%sHandoff Timestamp: %s\n", + prefix, FORMAT_TIMESTAMP(s->handoff_timestamp.realtime)); if (dual_timestamp_is_set(&s->exit_timestamp)) fprintf(f, diff --git a/src/core/execute.h b/src/core/execute.h index 202ef5f82b9..6a313640de2 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -91,7 +91,7 @@ typedef enum ExecKeyringMode { struct ExecStatus { dual_timestamp start_timestamp; dual_timestamp exit_timestamp; - dual_timestamp handover_timestamp; + dual_timestamp handoff_timestamp; pid_t pid; int code; /* as in siginfo_t::si_code */ int status; /* as in siginfo_t::si_status */ @@ -444,9 +444,7 @@ struct ExecParameters { int stdout_fd; int stderr_fd; - /* An fd that is closed by the execve(), and thus will result in EOF when the execve() is done. It - * will also be used to send a timestamp taken as the very last operation before execve, for - * tracking purposes. */ + /* An fd that is closed by the execve(), and thus will result in EOF when the execve() is done. */ int exec_fd; char *notify_socket; @@ -547,6 +545,7 @@ char** exec_context_get_restrict_filesystems(const ExecContext *c); void exec_status_start(ExecStatus *s, pid_t pid); void exec_status_exit(ExecStatus *s, const ExecContext *context, pid_t pid, int code, int status); +void exec_status_handoff(ExecStatus *s, const struct ucred *ucred, const dual_timestamp *ts); void exec_status_dump(const ExecStatus *s, FILE *f, const char *prefix); void exec_status_reset(ExecStatus *s); diff --git a/src/core/service.c b/src/core/service.c index 4a512fd24b2..b3fe2c0b1f8 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -3009,7 +3009,7 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) { (void) serialize_item_format(f, "main-exec-status-pid", PID_FMT, s->main_exec_status.pid); (void) serialize_dual_timestamp(f, "main-exec-status-start", &s->main_exec_status.start_timestamp); (void) serialize_dual_timestamp(f, "main-exec-status-exit", &s->main_exec_status.exit_timestamp); - (void) serialize_dual_timestamp(f, "main-exec-status-handover", &s->main_exec_status.handover_timestamp); + (void) serialize_dual_timestamp(f, "main-exec-status-handoff", &s->main_exec_status.handoff_timestamp); if (dual_timestamp_is_set(&s->main_exec_status.exit_timestamp)) { (void) serialize_item_format(f, "main-exec-status-code", "%i", s->main_exec_status.code); @@ -3294,8 +3294,8 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, deserialize_dual_timestamp(value, &s->main_exec_status.start_timestamp); else if (streq(key, "main-exec-status-exit")) deserialize_dual_timestamp(value, &s->main_exec_status.exit_timestamp); - else if (streq(key, "main-exec-status-handover")) - deserialize_dual_timestamp(value, &s->main_exec_status.handover_timestamp); + else if (streq(key, "main-exec-status-handoff")) + deserialize_dual_timestamp(value, &s->main_exec_status.handoff_timestamp); else if (streq(key, "notify-access-override")) { NotifyAccess notify_access; @@ -4578,6 +4578,29 @@ static void service_notify_message( unit_add_to_dbus_queue(u); } +static void service_handoff_timestamp( + Unit *u, + const struct ucred *ucred, + const dual_timestamp *ts) { + + Service *s = ASSERT_PTR(SERVICE(u)); + + assert(ucred); + assert(ts); + + if (s->main_pid.pid == ucred->pid) { + if (s->main_command) + exec_status_handoff(&s->main_command->exec_status, ucred, ts); + + exec_status_handoff(&s->main_exec_status, ucred, ts); + } else if (s->control_pid.pid == ucred->pid && s->control_command) + exec_status_handoff(&s->control_command->exec_status, ucred, ts); + else + return; + + unit_add_to_dbus_queue(u); +} + static int service_get_timeout(Unit *u, usec_t *timeout) { Service *s = ASSERT_PTR(SERVICE(u)); uint64_t t; @@ -5163,6 +5186,7 @@ const UnitVTable service_vtable = { .notify_cgroup_empty = service_notify_cgroup_empty_event, .notify_cgroup_oom = service_notify_cgroup_oom_event, .notify_message = service_notify_message, + .notify_handoff_timestamp = service_handoff_timestamp, .main_pid = service_main_pid, .control_pid = service_control_pid, diff --git a/test/units/testsuite-07.exec-timestamps.sh b/test/units/testsuite-07.exec-timestamps.sh index 799bc89e06e..0211166ae3c 100755 --- a/test/units/testsuite-07.exec-timestamps.sh +++ b/test/units/testsuite-07.exec-timestamps.sh @@ -8,10 +8,10 @@ set -o pipefail systemd-run --service-type notify --property NotifyAccess=all --unit notify.service --wait sh -c 'systemd-notify --ready; exit 1' || : start=$(systemctl show --property=ExecMainStartTimestampMonotonic --value notify.service) -handover=$(systemctl show --property=ExecMainHandoverTimestampMonotonic --value notify.service) +handoff=$(systemctl show --property=ExecMainHandoffTimestampMonotonic --value notify.service) active=$(systemctl show --property=ActiveEnterTimestampMonotonic --value notify.service) exit=$(systemctl show --property=ExecMainExitTimestampMonotonic --value notify.service) -[[ $start -le $handover ]] -[[ $handover -le $active ]] +[[ $start -le $handoff ]] +[[ $handoff -le $active ]] [[ $active -le $exit ]]