From c39f87a47a7d5ba0251063ba27cb49c165ad9540 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 2 Apr 2020 19:38:25 -0700 Subject: [PATCH] Revert "Merge pull request #2280 from kolyshkin/errors-unwrap" Using errors.Unwrap() is not the best thing to do, since it returns nil in case of an error which was not wrapped. More to say, errors package provides more elegant ways to check for underlying errors, such as errors.As() and errors.Is(). This reverts commit f8e138855d4a630006e88fb7476d35e10e31bf22, reversing changes made to 6ca9d8e6dae9f5a8f141cf0a3d6a26d74984b2ee. Signed-off-by: Kir Kolyshkin --- libcontainer/cgroups/fs/apply_raw.go | 16 ++++++++++++---- libcontainer/cgroups/fs/kmem.go | 10 ++++++++-- libcontainer/cgroups/fs2/pids.go | 12 +++++++++++- libcontainer/cgroups/fscommon/fscommon.go | 12 +++++++++++- libcontainer/cgroups/utils.go | 11 ++++++++++- libcontainer/container_linux.go | 5 ++++- 6 files changed, 56 insertions(+), 10 deletions(-) diff --git a/libcontainer/cgroups/fs/apply_raw.go b/libcontainer/cgroups/fs/apply_raw.go index a861bf7a..ec148b48 100644 --- a/libcontainer/cgroups/fs/apply_raw.go +++ b/libcontainer/cgroups/fs/apply_raw.go @@ -110,13 +110,21 @@ func isIgnorableError(rootless bool, err error) bool { if !rootless { return false } - err = errors.Cause(err) // Is it an ordinary EPERM? - if os.IsPermission(err) { + if os.IsPermission(errors.Cause(err)) { return true } - // Handle some specific syscall errors. - errno := errors.Unwrap(err) + + // Try to handle other errnos. + var errno error + switch err := errors.Cause(err).(type) { + case *os.PathError: + errno = err.Err + case *os.LinkError: + errno = err.Err + case *os.SyscallError: + errno = err.Err + } return errno == unix.EROFS || errno == unix.EPERM || errno == unix.EACCES } diff --git a/libcontainer/cgroups/fs/kmem.go b/libcontainer/cgroups/fs/kmem.go index 4191d977..69b5a194 100644 --- a/libcontainer/cgroups/fs/kmem.go +++ b/libcontainer/cgroups/fs/kmem.go @@ -6,8 +6,10 @@ import ( "errors" "fmt" "io/ioutil" + "os" "path/filepath" "strconv" + "syscall" // for Errno type only "github.com/opencontainers/runc/libcontainer/cgroups" "golang.org/x/sys/unix" @@ -47,8 +49,12 @@ func setKernelMemory(path string, kernelMemoryLimit int64) error { // The EBUSY signal is returned on attempts to write to the // memory.kmem.limit_in_bytes file if the cgroup has children or // once tasks have been attached to the cgroup - if errors.Unwrap(err) == unix.EBUSY { - return fmt.Errorf("failed to set %s, because either tasks have already joined this cgroup or it has children", cgroupKernelMemoryLimit) + if pathErr, ok := err.(*os.PathError); ok { + if errNo, ok := pathErr.Err.(syscall.Errno); ok { + if errNo == unix.EBUSY { + return fmt.Errorf("failed to set %s, because either tasks have already joined this cgroup or it has children", cgroupKernelMemoryLimit) + } + } } return fmt.Errorf("failed to write %v to %v: %v", kernelMemoryLimit, cgroupKernelMemoryLimit, err) } diff --git a/libcontainer/cgroups/fs2/pids.go b/libcontainer/cgroups/fs2/pids.go index feafce75..99d912cf 100644 --- a/libcontainer/cgroups/fs2/pids.go +++ b/libcontainer/cgroups/fs2/pids.go @@ -4,6 +4,7 @@ package fs2 import ( "io/ioutil" + "os" "path/filepath" "strings" @@ -24,11 +25,20 @@ func setPids(dirPath string, cgroup *configs.Cgroup) error { return nil } +func isNOTSUP(err error) bool { + switch err := err.(type) { + case *os.PathError: + return err.Err == unix.ENOTSUP + default: + return false + } +} + func statPidsWithoutController(dirPath string, stats *cgroups.Stats) error { // if the controller is not enabled, let's read PIDS from cgroups.procs // (or threads if cgroup.threads is enabled) contents, err := ioutil.ReadFile(filepath.Join(dirPath, "cgroup.procs")) - if err != nil && errors.Unwrap(err) == unix.ENOTSUP { + if err != nil && isNOTSUP(err) { contents, err = ioutil.ReadFile(filepath.Join(dirPath, "cgroup.threads")) } if err != nil { diff --git a/libcontainer/cgroups/fscommon/fscommon.go b/libcontainer/cgroups/fscommon/fscommon.go index cd3d9d9b..dc53987e 100644 --- a/libcontainer/cgroups/fscommon/fscommon.go +++ b/libcontainer/cgroups/fscommon/fscommon.go @@ -41,10 +41,20 @@ func ReadFile(dir, file string) (string, error) { func retryingWriteFile(filename string, data []byte, perm os.FileMode) error { for { err := ioutil.WriteFile(filename, data, perm) - if errors.Unwrap(err) == syscall.EINTR { + if isInterruptedWriteFile(err) { logrus.Infof("interrupted while writing %s to %s", string(data), filename) continue } return err } } + +func isInterruptedWriteFile(err error) bool { + if patherr, ok := err.(*os.PathError); ok { + errno, ok2 := patherr.Err.(syscall.Errno) + if ok2 && errno == syscall.EINTR { + return true + } + } + return false +} diff --git a/libcontainer/cgroups/utils.go b/libcontainer/cgroups/utils.go index 8a53cb09..7808c093 100644 --- a/libcontainer/cgroups/utils.go +++ b/libcontainer/cgroups/utils.go @@ -576,7 +576,7 @@ func WriteCgroupProc(dir string, pid int) error { // EINVAL might mean that the task being added to cgroup.procs is in state // TASK_NEW. We should attempt to do so again. - if errors.Unwrap(err) == unix.EINVAL { + if isEINVAL(err) { time.Sleep(30 * time.Millisecond) continue } @@ -586,6 +586,15 @@ func WriteCgroupProc(dir string, pid int) error { return err } +func isEINVAL(err error) bool { + switch err := err.(type) { + case *os.PathError: + return err.Err == unix.EINVAL + default: + return false + } +} + // Since the OCI spec is designed for cgroup v1, in some cases // there is need to convert from the cgroup v1 configuration to cgroup v2 // the formula for BlkIOWeight is y = (1 + (x - 10) * 9999 / 990) diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go index cd5a4f4e..43b7219c 100644 --- a/libcontainer/container_linux.go +++ b/libcontainer/container_linux.go @@ -1855,7 +1855,10 @@ func (c *linuxContainer) isPaused() (bool, error) { data, err := ioutil.ReadFile(filepath.Join(fcg, filename)) if err != nil { // If freezer cgroup is not mounted, the container would just be not paused. - if os.IsNotExist(err) || errors.Unwrap(err) == syscall.ENODEV { + if os.IsNotExist(err) { + return false, nil + } + if pathError, isPathError := err.(*os.PathError); isPathError && pathError.Err == syscall.ENODEV { return false, nil } return false, newSystemErrorWithCause(err, "checking if container is paused")