From: Albert Brox Date: Tue, 20 Jul 2021 22:24:20 +0000 (-0400) Subject: pid1: add support for cgroup.kill X-Git-Tag: v250-rc1~862 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=8a513eee30ac5128d3176bec90c8ed118764c54f;p=thirdparty%2Fsystemd.git pid1: add support for cgroup.kill --- diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index 1ff6160dc88..5bf7c03c00e 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -160,6 +160,24 @@ bool cg_freezer_supported(void) { return supported; } +bool cg_kill_supported(void) { + static thread_local int supported = -1; + + if (supported >= 0) + return supported; + + if (cg_all_unified() <= 0) + supported = false; + else if (access("/sys/fs/cgroup/init.scope/cgroup.kill", F_OK) < 0) { + if (errno != ENOENT) + log_debug_errno(errno, "Failed to check if cgroup.kill is available, assuming not: %m"); + supported = false; + } else + supported = true; + + return supported; +} + int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) { _cleanup_free_ char *fs = NULL; int r; @@ -358,6 +376,29 @@ int cg_kill( return cg_kill_items(controller, path, sig, flags, s, log_kill, userdata, "cgroup.threads"); } +int cg_kill_kernel_sigkill(const char *controller, const char *path) { + /* Kills the cgroup at `path` directly by writing to its cgroup.kill file. + * This sends SIGKILL to all processes in the cgroup and has the advantage of + * being completely atomic, unlike cg_kill_items. */ + int r; + _cleanup_free_ char *killfile = NULL; + + assert(path); + + if (!cg_kill_supported()) + return -EOPNOTSUPP; + + r = cg_get_path(controller, path, "cgroup.kill", &killfile); + if (r < 0) + return r; + + r = write_string_file(killfile, "1", WRITE_STRING_FILE_DISABLE_BUFFER); + if (r < 0) + return r; + + return 0; +} + int cg_kill_recursive( const char *controller, const char *path, @@ -375,38 +416,46 @@ int cg_kill_recursive( assert(path); assert(sig >= 0); - if (!s) { - s = allocated_set = set_new(NULL); - if (!s) - return -ENOMEM; - } + if (sig == SIGKILL && cg_kill_supported() && + !FLAGS_SET(flags, CGROUP_IGNORE_SELF) && !s && !log_kill) { + /* ignore CGROUP_SIGCONT, since this is a no-op alongside SIGKILL */ + ret = cg_kill_kernel_sigkill(controller, path); + if (ret < 0) + return ret; + } else { + if (!s) { + s = allocated_set = set_new(NULL); + if (!s) + return -ENOMEM; + } - ret = cg_kill(controller, path, sig, flags, s, log_kill, userdata); + ret = cg_kill(controller, path, sig, flags, s, log_kill, userdata); - r = cg_enumerate_subgroups(controller, path, &d); - if (r < 0) { - if (ret >= 0 && r != -ENOENT) - return r; + r = cg_enumerate_subgroups(controller, path, &d); + if (r < 0) { + if (ret >= 0 && r != -ENOENT) + return r; - return ret; - } + return ret; + } - while ((r = cg_read_subgroup(d, &fn)) > 0) { - _cleanup_free_ char *p = NULL; + while ((r = cg_read_subgroup(d, &fn)) > 0) { + _cleanup_free_ char *p = NULL; - p = path_join(empty_to_root(path), fn); - free(fn); - if (!p) - return -ENOMEM; + p = path_join(empty_to_root(path), fn); + free(fn); + if (!p) + return -ENOMEM; - r = cg_kill_recursive(controller, p, sig, flags, s, log_kill, userdata); - if (r != 0 && ret >= 0) + r = cg_kill_recursive(controller, p, sig, flags, s, log_kill, userdata); + if (r != 0 && ret >= 0) + ret = r; + } + if (ret >= 0 && r < 0) ret = r; } - if (ret >= 0 && r < 0) - ret = r; - if (flags & CGROUP_REMOVE) { + if (FLAGS_SET(flags, CGROUP_REMOVE)) { r = cg_rmdir(controller, path); if (r < 0 && ret >= 0 && !IN_SET(r, -ENOENT, -EBUSY)) return r; diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index ce2f4c6589b..b2dd9b56a54 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -172,6 +172,7 @@ typedef enum CGroupFlags { typedef int (*cg_kill_log_func_t)(pid_t pid, int sig, void *userdata); int cg_kill(const char *controller, const char *path, int sig, CGroupFlags flags, Set *s, cg_kill_log_func_t kill_log, void *userdata); +int cg_kill_kernel_sigkill(const char *controller, const char *path); int cg_kill_recursive(const char *controller, const char *path, int sig, CGroupFlags flags, Set *s, cg_kill_log_func_t kill_log, void *userdata); int cg_split_spec(const char *spec, char **ret_controller, char **ret_path); @@ -272,6 +273,7 @@ int cg_kernel_controllers(Set **controllers); bool cg_ns_supported(void); bool cg_freezer_supported(void); +bool cg_kill_supported(void); int cg_all_unified(void); int cg_hybrid_unified(void);