diff --git a/libcontainer/cgroups/fs/apply_raw.go b/libcontainer/cgroups/fs/apply_raw.go index a861bf7a4..ec148b489 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 4191d9770..69b5a1946 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 feafce756..99d912cf2 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 cd3d9d9b2..dc53987e0 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 8a53cb09a..7808c0936 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 cd5a4f4ec..43b7219ce 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")