cgroup-util: kill also threads
authorTopi Miettinen <toiwoton@gmail.com>
Mon, 20 May 2019 09:20:58 +0000 (12:20 +0300)
committerLennart Poettering <lennart@poettering.net>
Sat, 22 Jun 2019 16:35:48 +0000 (18:35 +0200)
It's possible for a zombie process to have live threads. These are not listed
in /sys in "cgroup.procs" for cgroupsv2, but they show up in
"cgroup.threads" (cgroupv2) or "tasks" (cgroupv1) nodes. When killing a
cgroup (v2 only) with SIGKILL, let's also kill threads after killing processes,
so the live threads of a zombie get killed too.

Closes #12262.

src/basic/cgroup-util.c

index 156a360..60ce9b7 100644 (file)
 #include "unit-name.h"
 #include "user-util.h"
 
-int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
+static int cg_enumerate_items(const char *controller, const char *path, FILE **_f, const char *item) {
         _cleanup_free_ char *fs = NULL;
         FILE *f;
         int r;
 
         assert(_f);
 
-        r = cg_get_path(controller, path, "cgroup.procs", &fs);
+        r = cg_get_path(controller, path, item, &fs);
         if (r < 0)
                 return r;
 
@@ -62,6 +62,10 @@ int cg_enumerate_processes(const char *controller, const char *path, FILE **_f)
         return 0;
 }
 
+int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
+        return cg_enumerate_items(controller, path, _f, "cgroup.procs");
+}
+
 int cg_read_pid(FILE *f, pid_t *_pid) {
         unsigned long ul;
 
@@ -221,14 +225,15 @@ int cg_rmdir(const char *controller, const char *path) {
         return 0;
 }
 
-int cg_kill(
+static int cg_kill_items(
                 const char *controller,
                 const char *path,
                 int sig,
                 CGroupFlags flags,
                 Set *s,
                 cg_kill_log_func_t log_kill,
-                void *userdata) {
+                void *userdata,
+                const char *item) {
 
         _cleanup_set_free_ Set *allocated_set = NULL;
         bool done = false;
@@ -259,7 +264,7 @@ int cg_kill(
                 pid_t pid = 0;
                 done = true;
 
-                r = cg_enumerate_processes(controller, path, &f);
+                r = cg_enumerate_items(controller, path, &f, item);
                 if (r < 0) {
                         if (ret >= 0 && r != -ENOENT)
                                 return r;
@@ -322,6 +327,31 @@ int cg_kill(
         return ret;
 }
 
+int cg_kill(
+                const char *controller,
+                const char *path,
+                int sig,
+                CGroupFlags flags,
+                Set *s,
+                cg_kill_log_func_t log_kill,
+                void *userdata) {
+        int r;
+
+        r = cg_kill_items(controller, path, sig, flags, s, log_kill, userdata, "cgroup.procs");
+        if (r < 0 || sig != SIGKILL)
+                return r;
+
+        /* Only in case of killing with SIGKILL and when using cgroupsv2, kill remaining threads manually as
+           a workaround for kernel bug. It was fixed in 5.2-rc5 (c03cd7738a83). */
+        r = cg_unified_controller(controller);
+        if (r < 0)
+                return r;
+        if (r == 0) /* doesn't apply to legacy hierarchy */
+                return 0;
+
+        return cg_kill_items(controller, path, sig, flags, s, log_kill, userdata, "cgroup.threads");
+}
+
 int cg_kill_recursive(
                 const char *controller,
                 const char *path,