From 678a7b043711515cb864a4f43490acce08449db6 Mon Sep 17 00:00:00 2001 From: ningmingxiao Date: Wed, 14 Jun 2023 16:39:37 +0800 Subject: [PATCH] add D status check for container when killing it Signed-off-by: ningmingxiao --- daemon/container_operations_unix.go | 18 ++++++++++++++---- pkg/process/process_unix.go | 23 +++++++++++++++++------ 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/daemon/container_operations_unix.go b/daemon/container_operations_unix.go index 961b87cd5cb42..d4fc8a66a5e68 100644 --- a/daemon/container_operations_unix.go +++ b/daemon/container_operations_unix.go @@ -351,16 +351,26 @@ func killProcessDirectly(container *container.Container) error { return err } - // In case there were some exceptions(e.g., state of zombie and D) if process.Alive(pid) { - // Since we can not kill a zombie pid, add zombie check here - isZombie, err := process.Zombie(pid) + status, err := process.Status(pid) if err != nil { logrus.WithError(err).WithField("container", container.ID).Warn("Container state is invalid") return err } - if isZombie { + // Since we can not kill a zombie and D status pid, add check here + switch status { + case "D": + return errdefs.System(errors.Errorf("container %s PID %d is uninterruptible and can not be killed", stringid.TruncateID(container.ID), pid)) + case "Z": return errdefs.System(errors.Errorf("container %s PID %d is zombie and can not be killed. Use the --init option when creating containers to run an init inside the container that forwards signals and reaps processes", stringid.TruncateID(container.ID), pid)) + case "S": + return errdefs.System(errors.Errorf("container %s PID %d is %s and can not be killed", stringid.TruncateID(container.ID), pid, status)) + case "T", "X", "x": + case "": + return errdefs.System(errors.Errorf("container %s PID %d status is nil", stringid.TruncateID(container.ID), pid)) + default: + // If process can't be killed and status is not D or Z print some warning log.It is almost impossible to happen. + logrus.Warnf("container %s PID %d status is \"%s\"", container.ID, pid, status) } } return nil diff --git a/pkg/process/process_unix.go b/pkg/process/process_unix.go index baa1693a241e6..a4a7e6dc8537f 100644 --- a/pkg/process/process_unix.go +++ b/pkg/process/process_unix.go @@ -64,18 +64,29 @@ func Kill(pid int) error { // // [PROC(5)]: https://man7.org/linux/man-pages/man5/proc.5.html func Zombie(pid int) (bool, error) { + status, err := Status(pid) + return status == "Z", err +} + +// Status returns the status of the given process. It only considers positive +// PIDs; 0 (all processes in the current process group), -1 (all processes with +// a PID larger than 1), and negative (-n, all processes in process group "n") +// values for pid are ignored. Refer to [PROC(5)] for details. +// +// [PROC(5)]: https://man7.org/linux/man-pages/man5/proc.5.html +func Status(pid int) (string, error) { if pid < 1 { - return false, nil + return "", nil } data, err := os.ReadFile(fmt.Sprintf("/proc/%d/stat", pid)) if err != nil { if os.IsNotExist(err) { - return false, nil + return "", nil } - return false, err + return "", err } - if cols := bytes.SplitN(data, []byte(" "), 4); len(cols) >= 3 && string(cols[2]) == "Z" { - return true, nil + if cols := bytes.SplitN(data, []byte(" "), 4); len(cols) >= 3 { + return string(cols[2]), nil } - return false, nil + return "", nil }