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 <gscrivan@redhat.com>
This commit is contained in:
parent
d8a414a535
commit
987031a01e
|
|
@ -9,6 +9,7 @@ import (
|
|||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
|
@ -96,6 +97,22 @@ 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) {
|
||||
if signal == unix.SIGKILL {
|
||||
if err := ioutil.WriteFile(filepath.Join(path, "cgroup.kill"), []byte("1"), 0600); err == nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
// 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 +135,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
|
||||
|
|
|
|||
Loading…
Reference in New Issue