From 0d91c259bf82245ad717eb8df371c626d9e197f5 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 3 May 2022 11:24:15 +0200 Subject: [PATCH] cgroups: kill processes when deleting a cgroup if the cgroup cleanup fails with EBUSY, attempt to kill the processes. Related to: https://github.com/containers/podman/issues/14057 Signed-off-by: Giuseppe Scrivano --- pkg/cgroups/cgroups_supported.go | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/pkg/cgroups/cgroups_supported.go b/pkg/cgroups/cgroups_supported.go index edb28ad18..1021bc3ea 100644 --- a/pkg/cgroups/cgroups_supported.go +++ b/pkg/cgroups/cgroups_supported.go @@ -9,6 +9,7 @@ import ( "io/ioutil" "os" "path/filepath" + "strconv" "strings" "sync" "syscall" @@ -96,6 +97,17 @@ func UserOwnsCurrentSystemdCgroup() (bool, error) { // It differs from os.RemoveAll as it doesn't attempt to unlink files. // On cgroupfs we are allowed only to rmdir empty directories. func rmDirRecursively(path string) error { + killProcesses := func(signal syscall.Signal) { + // kill all the processes that are still part of the cgroup + if procs, err := ioutil.ReadFile(filepath.Join(path, "cgroup.procs")); err == nil { + for _, pidS := range strings.Split(string(procs), "\n") { + if pid, err := strconv.Atoi(pidS); err == nil { + _ = unix.Kill(pid, signal) + } + } + } + } + if err := os.Remove(path); err == nil || os.IsNotExist(err) { return nil } @@ -118,8 +130,16 @@ func rmDirRecursively(path string) error { return nil } if errors.Is(err, unix.EBUSY) { - // attempt up to 5 seconds if the cgroup is busy - if attempts < 500 { + // send a SIGTERM after 3 second + if attempts == 300 { + killProcesses(unix.SIGTERM) + } + // send SIGKILL after 8 seconds + if attempts == 800 { + killProcesses(unix.SIGKILL) + } + // give up after 10 seconds + if attempts < 1000 { time.Sleep(time.Millisecond * 10) attempts++ continue