From 330ecca8530a602fda31122d75e09233cd227dbe Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Wed, 29 May 2024 19:48:19 +0200 Subject: [PATCH 1/3] cgroup-util: Add debug logging for cg_kill_recursive() --- src/basic/cgroup-util.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index c0d0fe6f14..be7f7c787d 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -140,7 +140,7 @@ int cg_read_pidref(FILE *f, PidRef *ret, CGroupFlags flags) { r = cg_read_pid(f, &pid, flags); if (r < 0) - return r; + return log_debug_errno(r, "Failed to read pid from cgroup item: %m"); if (r == 0) { *ret = PIDREF_NULL; return 0; @@ -347,14 +347,14 @@ static int cg_kill_items( if (r == -ENOENT) break; if (r < 0) - return RET_GATHER(ret, r); + return RET_GATHER(ret, log_debug_errno(r, "Failed to enumerate cgroup items: %m")); for (;;) { _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; r = cg_read_pidref(f, &pidref, /* flags = */ 0); if (r < 0) - return RET_GATHER(ret, r); + return RET_GATHER(ret, log_debug_errno(r, "Failed to read pidref from cgroup '%s': %m", path)); if (r == 0) break; @@ -370,7 +370,7 @@ static int cg_kill_items( /* If we haven't killed this process yet, kill it */ r = pidref_kill(&pidref, sig); if (r < 0 && r != -ESRCH) - RET_GATHER(ret, r); + RET_GATHER(ret, log_debug_errno(r, "Failed to kill process with pid " PID_FMT " from cgroup '%s': %m", pidref.pid, path)); if (r >= 0) { if (flags & CGROUP_SIGCONT) (void) pidref_kill(&pidref, SIGCONT); @@ -409,6 +409,8 @@ int cg_kill( int r, ret; r = cg_kill_items(path, sig, flags, s, log_kill, userdata, "cgroup.procs"); + if (r < 0) + log_debug_errno(r, "Failed to kill processes in cgroup '%s' item cgroup.procs: %m", path); if (r < 0 || sig != SIGKILL) return r; @@ -425,7 +427,7 @@ int cg_kill( r = cg_kill_items(path, sig, flags, s, log_kill, userdata, "cgroup.threads"); if (r < 0) - return r; + return log_debug_errno(r, "Failed to kill processes in cgroup '%s' item cgroup.threads: %m", path); return r > 0 || ret > 0; } @@ -448,7 +450,7 @@ int cg_kill_kernel_sigkill(const char *path) { r = write_string_file(killfile, "1", WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) - return r; + return log_debug_errno(r, "Failed to write to cgroup.kill for cgroup '%s': %m", path); return 0; } @@ -485,7 +487,7 @@ int cg_kill_recursive( r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, path, &d); if (r < 0) { if (r != -ENOENT) - RET_GATHER(ret, r); + RET_GATHER(ret, log_debug_errno(r, "Failed to enumerate cgroup '%s' subgroups: %m", path)); return ret; } @@ -495,7 +497,7 @@ int cg_kill_recursive( r = cg_read_subgroup(d, &fn); if (r < 0) { - RET_GATHER(ret, r); + RET_GATHER(ret, log_debug_errno(r, "Failed to read subgroup from cgroup '%s': %m", path)); break; } if (r == 0) @@ -506,6 +508,8 @@ int cg_kill_recursive( return -ENOMEM; r = cg_kill_recursive(p, sig, flags, s, log_kill, userdata); + if (r < 0) + log_debug_errno(r, "Failed to recursively kill processes in cgroup '%s': %m", p); if (r != 0 && ret >= 0) ret = r; } @@ -514,7 +518,7 @@ int cg_kill_recursive( if (FLAGS_SET(flags, CGROUP_REMOVE)) { r = cg_rmdir(SYSTEMD_CGROUP_CONTROLLER, path); if (!IN_SET(r, -ENOENT, -EBUSY)) - RET_GATHER(ret, r); + RET_GATHER(ret, log_debug_errno(r, "Failed to remove cgroup '%s': %m", path)); } return ret; From 9ac8450e7f0a011654e947e996b0df5631e68c23 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Wed, 29 May 2024 21:04:13 +0200 Subject: [PATCH 2/3] basic: Add debug logging for pidref_set_pid() --- src/basic/pidref.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/basic/pidref.c b/src/basic/pidref.c index ae04dd72a4..69a010210d 100644 --- a/src/basic/pidref.c +++ b/src/basic/pidref.c @@ -54,7 +54,7 @@ int pidref_set_pid(PidRef *pidref, pid_t pid) { if (fd < 0) { /* Graceful fallback in case the kernel doesn't support pidfds or is out of fds */ if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno) && !ERRNO_IS_RESOURCE(errno)) - return -errno; + return log_debug_errno(errno, "Failed to open pidfd for pid " PID_FMT ": %m", pid); fd = -EBADF; } From 8783355fd98448c08dae68e80da9580d74ea8687 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Wed, 29 May 2024 22:03:38 +0200 Subject: [PATCH 3/3] cgroup-util: Don't try to open pidfd for pids from cgroup.threads Opening pidfds for non thread group leaders only works from 6.9 onwards with PIDFD_THREAD. On older kernels or without PIDFD_THREAD pidfd_open() fails with EINVAL. Since we might read non thread group leader IDs from cgroup.threads, we introduce and set CGROUP_NO_PIDFD to avoid trying open pidfd's for them and instead use the pid as is. --- src/basic/cgroup-util.c | 13 +++++++++++-- src/basic/cgroup-util.h | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index be7f7c787d..553ee6075a 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -149,6 +149,11 @@ int cg_read_pidref(FILE *f, PidRef *ret, CGroupFlags flags) { if (pid == 0) return -EREMOTE; + if (FLAGS_SET(flags, CGROUP_NO_PIDFD)) { + *ret = PIDREF_MAKE_FROM_PID(pid); + return 1; + } + r = pidref_set_pid(ret, pid); if (r >= 0) return 1; @@ -352,7 +357,7 @@ static int cg_kill_items( for (;;) { _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; - r = cg_read_pidref(f, &pidref, /* flags = */ 0); + r = cg_read_pidref(f, &pidref, flags); if (r < 0) return RET_GATHER(ret, log_debug_errno(r, "Failed to read pidref from cgroup '%s': %m", path)); if (r == 0) @@ -425,7 +430,11 @@ int cg_kill( if (r == 0) return ret; - r = cg_kill_items(path, sig, flags, s, log_kill, userdata, "cgroup.threads"); + /* Opening pidfds for non thread group leaders only works from 6.9 onwards with PIDFD_THREAD. On + * older kernels or without PIDFD_THREAD pidfd_open() fails with EINVAL. Since we might read non + * thread group leader IDs from cgroup.threads, we set CGROUP_NO_PIDFD to avoid trying open pidfd's + * for them and instead use the regular pid. */ + r = cg_kill_items(path, sig, flags|CGROUP_NO_PIDFD, s, log_kill, userdata, "cgroup.threads"); if (r < 0) return log_debug_errno(r, "Failed to kill processes in cgroup '%s' item cgroup.threads: %m", path); diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index 29417b39ad..a8871785b6 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -188,6 +188,7 @@ typedef enum CGroupFlags { CGROUP_IGNORE_SELF = 1 << 1, CGROUP_REMOVE = 1 << 2, CGROUP_DONT_SKIP_UNMAPPED = 1 << 3, + CGROUP_NO_PIDFD = 1 << 4, } CGroupFlags; int cg_enumerate_processes(const char *controller, const char *path, FILE **ret);