From: Daan De Meyer Date: Sat, 4 May 2024 14:54:41 +0000 (+0200) Subject: core: Record ExecMainStartTimestamp before forking X-Git-Tag: v256-rc2~102 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7e0e6b50b4d26f13ccfc1df9f0daf50f839f8d00;p=thirdparty%2Fsystemd.git core: Record ExecMainStartTimestamp before forking Otherwise there's a chance the handover timestamp is less than the start timestamp depending on the whims of the scheduler. For non-forking services, we also propagate the start timestamp into Service->main_exec_status to make sure it starts earlier than the handoff timestamp. --- diff --git a/src/core/execute.c b/src/core/execute.c index 80d5b30720b..9b953f980fd 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -366,6 +366,7 @@ int exec_spawn(Unit *unit, _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; _cleanup_fdset_free_ FDSet *fdset = NULL; _cleanup_fclose_ FILE *f = NULL; + dual_timestamp start_timestamp; int r; assert(unit); @@ -446,6 +447,10 @@ int exec_spawn(Unit *unit, xsprintf(serialization_fd_number, "%i", fileno(f)); + /* Record the start timestamp before we fork so that it is guaranteed to be earlier than the + * handoff timestamp. */ + dual_timestamp_now(&start_timestamp); + /* The executor binary is pinned, to avoid compatibility problems during upgrades. */ r = posix_spawn_wrapper( FORMAT_PROC_FD_PATH(unit->manager->executor_fd), @@ -473,7 +478,7 @@ int exec_spawn(Unit *unit, log_unit_debug(unit, "Forked %s as " PID_FMT " (%s CLONE_INTO_CGROUP)", command->path, pidref.pid, r > 0 ? "via" : "without"); - exec_status_start(&command->exec_status, pidref.pid); + exec_status_start(&command->exec_status, pidref.pid, &start_timestamp); *ret = TAKE_PIDREF(pidref); return 0; @@ -1816,14 +1821,17 @@ char** exec_context_get_restrict_filesystems(const ExecContext *c) { return l ? TAKE_PTR(l) : strv_new(NULL); } -void exec_status_start(ExecStatus *s, pid_t pid) { +void exec_status_start(ExecStatus *s, pid_t pid, const dual_timestamp *ts) { assert(s); *s = (ExecStatus) { .pid = pid, }; - dual_timestamp_now(&s->start_timestamp); + if (ts) + s->start_timestamp = *ts; + else + dual_timestamp_now(&s->start_timestamp); } void exec_status_exit(ExecStatus *s, const ExecContext *context, pid_t pid, int code, int status) { diff --git a/src/core/execute.h b/src/core/execute.h index 77ca1901e7e..b782967c876 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -542,7 +542,7 @@ char** exec_context_get_syscall_log(const ExecContext *c); char** exec_context_get_address_families(const ExecContext *c); char** exec_context_get_restrict_filesystems(const ExecContext *c); -void exec_status_start(ExecStatus *s, pid_t pid); +void exec_status_start(ExecStatus *s, pid_t pid, const dual_timestamp *ts); 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); diff --git a/src/core/service.c b/src/core/service.c index c527ad36bc7..36671ae1c0f 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -192,7 +192,7 @@ static void service_unwatch_pid_file(Service *s) { s->pid_file_pathspec = mfree(s->pid_file_pathspec); } -static int service_set_main_pidref(Service *s, PidRef pidref_consume) { +static int service_set_main_pidref(Service *s, PidRef pidref_consume, const dual_timestamp *start_timestamp) { _cleanup_(pidref_done) PidRef pidref = pidref_consume; int r; @@ -214,7 +214,7 @@ static int service_set_main_pidref(Service *s, PidRef pidref_consume) { if (!pidref_equal(&s->main_pid, &pidref)) { service_unwatch_main_pid(s); - exec_status_start(&s->main_exec_status, pidref.pid); + exec_status_start(&s->main_exec_status, pidref.pid, start_timestamp); } s->main_pid = TAKE_PIDREF(pidref); @@ -1166,7 +1166,7 @@ static int service_load_pid_file(Service *s, bool may_warn) { } else log_unit_debug(UNIT(s), "Main PID loaded: "PID_FMT, pidref.pid); - r = service_set_main_pidref(s, TAKE_PIDREF(pidref)); + r = service_set_main_pidref(s, TAKE_PIDREF(pidref), /* start_timestamp = */ NULL); if (r < 0) return r; @@ -1196,7 +1196,7 @@ static void service_search_main_pid(Service *s) { return; log_unit_debug(UNIT(s), "Main PID guessed: "PID_FMT, pid.pid); - if (service_set_main_pidref(s, TAKE_PIDREF(pid)) < 0) + if (service_set_main_pidref(s, TAKE_PIDREF(pid), /* start_timestamp = */ NULL) < 0) return; r = unit_watch_pidref(UNIT(s), &s->main_pid, /* exclusive= */ false); @@ -2417,7 +2417,7 @@ static void service_enter_start(Service *s) { /* For simple services we immediately start * the START_POST binaries. */ - (void) service_set_main_pidref(s, TAKE_PIDREF(pidref)); + (void) service_set_main_pidref(s, TAKE_PIDREF(pidref), &c->exec_status.start_timestamp); service_enter_start_post(s); } else if (s->type == SERVICE_FORKING) { @@ -2436,7 +2436,7 @@ static void service_enter_start(Service *s) { /* For D-Bus services we know the main pid right away, but wait for the bus name to appear on the * bus. 'notify' and 'exec' services are similar. */ - (void) service_set_main_pidref(s, TAKE_PIDREF(pidref)); + (void) service_set_main_pidref(s, TAKE_PIDREF(pidref), &c->exec_status.start_timestamp); service_set_state(s, SERVICE_START); } else assert_not_reached(); @@ -2709,7 +2709,7 @@ static void service_run_next_main(Service *s) { return; } - (void) service_set_main_pidref(s, TAKE_PIDREF(pidref)); + (void) service_set_main_pidref(s, TAKE_PIDREF(pidref), &s->main_command->exec_status.start_timestamp); } static int service_start(Unit *u) { @@ -3187,7 +3187,7 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, PidRef pidref; if (!pidref_is_set(&s->main_pid) && deserialize_pidref(fds, value, &pidref) >= 0) - (void) service_set_main_pidref(s, pidref); + (void) service_set_main_pidref(s, pidref, /* start_timestamp = */ NULL); } else if (streq(key, "main-pid-known")) { int b; @@ -4380,7 +4380,7 @@ static void service_notify_message( log_unit_warning(u, "New main PID "PID_FMT" does not belong to service, refusing.", new_main_pid.pid); } if (r > 0) { - (void) service_set_main_pidref(s, TAKE_PIDREF(new_main_pid)); + (void) service_set_main_pidref(s, TAKE_PIDREF(new_main_pid), /* start_timestamp = */ NULL); r = unit_watch_pidref(UNIT(s), &s->main_pid, /* exclusive= */ false); if (r < 0) @@ -4676,7 +4676,7 @@ static int bus_name_pid_lookup_callback(sd_bus_message *reply, void *userdata, s log_unit_debug(UNIT(s), "D-Bus name %s is now owned by process " PID_FMT, s->bus_name, pidref.pid); - (void) service_set_main_pidref(s, TAKE_PIDREF(pidref)); + (void) service_set_main_pidref(s, TAKE_PIDREF(pidref), /* start_timestamp = */ NULL); (void) unit_watch_pidref(UNIT(s), &s->main_pid, /* exclusive= */ false); return 1; }