From 084e7706c25bf6cf0d6af4cc07fb1bb47e26b25e Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 13 Feb 2022 20:39:04 +0900 Subject: [PATCH 1/2] cgroup-util: introduce cg_is_threaded() --- src/basic/cgroup-util.c | 24 ++++++++++++++++++++++++ src/basic/cgroup-util.h | 2 ++ 2 files changed, 26 insertions(+) diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index 289e4fe073..95bf177a6b 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -1688,6 +1688,30 @@ int cg_slice_to_path(const char *unit, char **ret) { return 0; } +int cg_is_threaded(const char *controller, const char *path) { + _cleanup_free_ char *fs = NULL, *contents = NULL; + _cleanup_strv_free_ char **v = NULL; + int r; + + r = cg_get_path(controller, path, "cgroup.type", &fs); + if (r < 0) + return r; + + r = read_full_virtual_file(fs, &contents, NULL); + if (r == -ENOENT) + return false; /* Assume no. */ + if (r < 0) + return r; + + v = strv_split(contents, NULL); + if (!v) + return -ENOMEM; + + /* If the cgroup is in the threaded mode, it contains "threaded". + * If one of the parents or siblings is in the threaded mode, it may contain "invalid". */ + return strv_contains(v, "threaded") || strv_contains(v, "invalid"); +} + int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value) { _cleanup_free_ char *p = NULL; int r; diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index 461c01b3c2..4c413a8d17 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -205,6 +205,8 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **path); int cg_rmdir(const char *controller, const char *path); +int cg_is_threaded(const char *controller, const char *path); + typedef enum { CG_KEY_MODE_GRACEFUL = 1 << 0, } CGroupKeyMode; From 702cf08fceaa7df8476e56e3648b211e58700bc0 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 13 Feb 2022 20:52:53 +0900 Subject: [PATCH 2/2] core/execute: warn when threaded mode is detected Prompted by #22486. --- src/core/execute.c | 6 ++++++ src/shared/cgroup-setup.c | 3 +++ 2 files changed, 9 insertions(+) diff --git a/src/core/execute.c b/src/core/execute.c index 380755eb09..72f3534908 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -4250,6 +4250,12 @@ static int exec_child( } r = cg_attach_everywhere(params->cgroup_supported, p, 0, NULL, NULL); + if (r == -EUCLEAN) { + *exit_status = EXIT_CGROUP; + return log_unit_error_errno(unit, r, "Failed to attach process to cgroup %s " + "because the cgroup or one of its parents or " + "siblings is in the threaded mode: %m", p); + } if (r < 0) { *exit_status = EXIT_CGROUP; return log_unit_error_errno(unit, r, "Failed to attach to cgroup %s: %m", p); diff --git a/src/shared/cgroup-setup.c b/src/shared/cgroup-setup.c index 8bda66ca36..38a6755d17 100644 --- a/src/shared/cgroup-setup.c +++ b/src/shared/cgroup-setup.c @@ -346,6 +346,9 @@ int cg_attach(const char *controller, const char *path, pid_t pid) { xsprintf(c, PID_FMT "\n", pid); r = write_string_file(fs, c, WRITE_STRING_FILE_DISABLE_BUFFER); + if (r == -EOPNOTSUPP && cg_is_threaded(controller, path) > 0) + /* When the threaded mode is used, we cannot read/write the file. Let's return recognizable error. */ + return -EUCLEAN; if (r < 0) return r;