mirror of
https://github.com/systemd/systemd.git
synced 2026-11-06 05:17:24 +00:00
journald: prefer stream's unit ID over stale cached one if process is gone
Commit 44a9316bf4 made us refresh the cached client context if a stdout
stream tells us about a unit that doesn't match the cached one. That
covers the case where sd-executor logs a few messages while still in the
service manager's cgroup (on kernels lacking CLONE_INTO_CGROUP) and only
then moves itself into the unit's cgroup and connects stdout/stderr to
us.
However, the refresh doesn't help if the process already exited by the
time we process its output: reading its cgroup then fails, and we only
used the stream's unit ID as fallback if nothing was cached at all.
Hence the output was still attributed to init.scope, and "journalctl -u"
would not show it. This made the "systemctl --verbose wait" check in
TEST-03-JOBS flaky on CentOS 9 CI, where the unit's single line of
output was attributed to init.scope:
_SYSTEMD_CGROUP=/init.scope
_SYSTEMD_UNIT=init.scope
_TRANSPORT=stdout
MESSAGE=hello-from-wait
Fix that by flushing out the cached data entirely if a stream tells us
about a unit while the cached data still refers to init.scope. This way
we neither keep sd-executor's identity (_COMM=, _EXE=, …) nor any of
init.scope's per-unit settings (log filters, max log level, extra
fields, rate limits) around, and if the process already exited we fall
back to the stream's unit ID as before. We deliberately do not do this
if the cached data refers to any other unit, since processes of a unit
might legitimately have been migrated elsewhere (e.g. into a session
scope) while still writing to the stream they inherited.
This commit is contained in:
1 parent
84b71c1525
commit
bdea819a2f
1 file changed
+18
-3
@@ -25,6 +25,7 @@
|
||||
#include "procfs-util.h"
|
||||
#include "selinux-util.h"
|
||||
#include "set.h"
|
||||
#include "special.h"
|
||||
#include "string-util.h"
|
||||
#include "syslog-util.h"
|
||||
#include "time-util.h"
|
||||
@@ -286,9 +287,10 @@ static int client_context_read_cgroup(Manager *m, ClientContext *c, const char *
|
||||
/* Try to acquire the current cgroup path */
|
||||
r = cg_pid_get_path_shifted(c->pid, m->cgroup_root, &t);
|
||||
if (r < 0 || empty_or_root(t)) {
|
||||
/* We use the unit ID passed in as fallback if we have nothing cached yet and cg_pid_get_path_shifted()
|
||||
* failed or process is running in a root cgroup. Zombie processes are automatically migrated to root cgroup
|
||||
* on cgroup v1 and we want to be able to map log messages from them too. */
|
||||
/* We use the unit ID passed in as fallback if cg_pid_get_path_shifted() failed (e.g. because
|
||||
* the process already exited by the time we process the stdout stream it connected to us) or
|
||||
* the process is running in a root cgroup. Zombie processes are automatically migrated to root
|
||||
* cgroup on cgroup v1 and we want to be able to map log messages from them too. */
|
||||
if (unit_id && !c->unit) {
|
||||
c->unit = strdup(unit_id);
|
||||
if (c->unit)
|
||||
@@ -539,6 +541,19 @@ static void client_context_really_refresh(
|
||||
if (timestamp == USEC_INFINITY)
|
||||
timestamp = now(CLOCK_MONOTONIC);
|
||||
|
||||
/* If the caller tells us about a unit (i.e. the one a stdout stream was opened for, which is always
|
||||
* a system unit), but we have the process cached as part of PID 1's own cgroup, then the cached data
|
||||
* is stale: on kernels lacking CLONE_INTO_CGROUP sd-executor logs a few messages while still in
|
||||
* init.scope, and only then attaches itself to the unit's cgroup and connects stdout/stderr to
|
||||
* us. Flush out everything we know in that case, so that we don't keep sd-executor's identity or
|
||||
* init.scope's per-unit settings around. If the process is still around we'll reacquire everything
|
||||
* below, and if it already exited we'll at least use the stream's unit ID as fallback. Note that we
|
||||
* do not do this if the cached data refers to any other unit, since processes of a unit might very
|
||||
* well have been migrated elsewhere (e.g. into a session scope) while still writing to the stream
|
||||
* they inherited. */
|
||||
if (unit_id && streq_ptr(c->unit, SPECIAL_INIT_SCOPE) && !streq(unit_id, SPECIAL_INIT_SCOPE))
|
||||
client_context_reset(m, c);
|
||||
|
||||
client_context_read_uid_gid(c, ucred);
|
||||
client_context_read_basic(c);
|
||||
(void) client_context_read_label(c, label);
|
||||
|
||||
Reference in new issue
Block a user