summaryrefslogtreecommitdiff
path: root/vendor/github.com/opencontainers/runc/libcontainer/cgroups
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/opencontainers/runc/libcontainer/cgroups')
-rw-r--r--vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go2
-rw-r--r--vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups_unsupported.go3
-rw-r--r--vendor/github.com/opencontainers/runc/libcontainer/cgroups/file.go60
-rw-r--r--vendor/github.com/opencontainers/runc/libcontainer/cgroups/getallpids.go27
-rw-r--r--vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go16
-rw-r--r--vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go115
-rw-r--r--vendor/github.com/opencontainers/runc/libcontainer/cgroups/v1_utils.go19
7 files changed, 161 insertions, 81 deletions
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go
index 68a346ca5..ba2b2266c 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go
@@ -1,5 +1,3 @@
-// +build linux
-
package cgroups
import (
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups_unsupported.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups_unsupported.go
deleted file mode 100644
index 278d507e2..000000000
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups_unsupported.go
+++ /dev/null
@@ -1,3 +0,0 @@
-// +build !linux
-
-package cgroups
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/file.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/file.go
index 5f6ab9fd6..0cdaf7478 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/file.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/file.go
@@ -2,20 +2,27 @@ package cgroups
import (
"bytes"
+ "errors"
+ "fmt"
"os"
+ "path"
+ "strconv"
"strings"
"sync"
- "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
// OpenFile opens a cgroup file in a given dir with given flags.
-// It is supposed to be used for cgroup files only.
+// It is supposed to be used for cgroup files only, and returns
+// an error if the file is not a cgroup file.
+//
+// Arguments dir and file are joined together to form an absolute path
+// to a file being opened.
func OpenFile(dir, file string, flags int) (*os.File, error) {
if dir == "" {
- return nil, errors.Errorf("no directory specified for %s", file)
+ return nil, fmt.Errorf("no directory specified for %s", file)
}
return openFile(dir, file, flags)
}
@@ -43,7 +50,8 @@ func WriteFile(dir, file, data string) error {
}
defer fd.Close()
if err := retryingWriteFile(fd, data); err != nil {
- return errors.Wrapf(err, "failed to write %q", data)
+ // Having data in the error message helps in debugging.
+ return fmt.Errorf("failed to write %q: %w", data, err)
}
return nil
}
@@ -81,7 +89,7 @@ func prepareOpenat2() error {
})
if err != nil {
prepErr = &os.PathError{Op: "openat2", Path: cgroupfsDir, Err: err}
- if err != unix.ENOSYS {
+ if err != unix.ENOSYS { //nolint:errorlint // unix errors are bare
logrus.Warnf("falling back to securejoin: %s", prepErr)
} else {
logrus.Debug("openat2 not available, falling back to securejoin")
@@ -107,8 +115,6 @@ func prepareOpenat2() error {
return prepErr
}
-// OpenFile opens a cgroup file in a given dir with given flags.
-// It is supposed to be used for cgroup files only.
func openFile(dir, file string, flags int) (*os.File, error) {
mode := os.FileMode(0)
if TestMode && flags&os.O_WRONLY != 0 {
@@ -116,34 +122,52 @@ func openFile(dir, file string, flags int) (*os.File, error) {
flags |= os.O_TRUNC | os.O_CREATE
mode = 0o600
}
+ path := path.Join(dir, file)
if prepareOpenat2() != nil {
- return openFallback(dir, file, flags, mode)
+ return openFallback(path, flags, mode)
}
- reldir := strings.TrimPrefix(dir, cgroupfsPrefix)
- if len(reldir) == len(dir) { // non-standard path, old system?
- return openFallback(dir, file, flags, mode)
+ relPath := strings.TrimPrefix(path, cgroupfsPrefix)
+ if len(relPath) == len(path) { // non-standard path, old system?
+ return openFallback(path, flags, mode)
}
- relname := reldir + "/" + file
- fd, err := unix.Openat2(cgroupFd, relname,
+ fd, err := unix.Openat2(cgroupFd, relPath,
&unix.OpenHow{
Resolve: resolveFlags,
Flags: uint64(flags) | unix.O_CLOEXEC,
Mode: uint64(mode),
})
if err != nil {
- return nil, &os.PathError{Op: "openat2", Path: dir + "/" + file, Err: err}
+ err = &os.PathError{Op: "openat2", Path: path, Err: err}
+ // Check if cgroupFd is still opened to cgroupfsDir
+ // (happens when this package is incorrectly used
+ // across the chroot/pivot_root/mntns boundary, or
+ // when /sys/fs/cgroup is remounted).
+ //
+ // TODO: if such usage will ever be common, amend this
+ // to reopen cgroupFd and retry openat2.
+ fdStr := strconv.Itoa(cgroupFd)
+ fdDest, _ := os.Readlink("/proc/self/fd/" + fdStr)
+ if fdDest != cgroupfsDir {
+ // Wrap the error so it is clear that cgroupFd
+ // is opened to an unexpected/wrong directory.
+ err = fmt.Errorf("cgroupFd %s unexpectedly opened to %s != %s: %w",
+ fdStr, fdDest, cgroupfsDir, err)
+ }
+ return nil, err
}
- return os.NewFile(uintptr(fd), cgroupfsPrefix+relname), nil
+ return os.NewFile(uintptr(fd), path), nil
}
var errNotCgroupfs = errors.New("not a cgroup file")
-// openFallback is used when openat2(2) is not available. It checks the opened
+// Can be changed by unit tests.
+var openFallback = openAndCheck
+
+// openAndCheck is used when openat2(2) is not available. It checks the opened
// file is on cgroupfs, returning an error otherwise.
-func openFallback(dir, file string, flags int, mode os.FileMode) (*os.File, error) {
- path := dir + "/" + file
+func openAndCheck(path string, flags int, mode os.FileMode) (*os.File, error) {
fd, err := os.OpenFile(path, flags, mode)
if err != nil {
return nil, err
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/getallpids.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/getallpids.go
new file mode 100644
index 000000000..1355a5101
--- /dev/null
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/getallpids.go
@@ -0,0 +1,27 @@
+package cgroups
+
+import (
+ "io/fs"
+ "path/filepath"
+)
+
+// GetAllPids returns all pids from the cgroup identified by path, and all its
+// sub-cgroups.
+func GetAllPids(path string) ([]int, error) {
+ var pids []int
+ err := filepath.WalkDir(path, func(p string, d fs.DirEntry, iErr error) error {
+ if iErr != nil {
+ return iErr
+ }
+ if !d.IsDir() {
+ return nil
+ }
+ cPids, err := readProcsFile(p)
+ if err != nil {
+ return err
+ }
+ pids = append(pids, cPids...)
+ return nil
+ })
+ return pids, err
+}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go
index e7f9c4626..40a81dd5a 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go
@@ -1,5 +1,3 @@
-// +build linux
-
package cgroups
type ThrottlingData struct {
@@ -126,7 +124,7 @@ type BlkioStatEntry struct {
}
type BlkioStats struct {
- // number of bytes tranferred to and from the block device
+ // number of bytes transferred to and from the block device
IoServiceBytesRecursive []BlkioStatEntry `json:"io_service_bytes_recursive,omitempty"`
IoServicedRecursive []BlkioStatEntry `json:"io_serviced_recursive,omitempty"`
IoQueuedRecursive []BlkioStatEntry `json:"io_queue_recursive,omitempty"`
@@ -146,6 +144,17 @@ type HugetlbStats struct {
Failcnt uint64 `json:"failcnt"`
}
+type RdmaEntry struct {
+ Device string `json:"device,omitempty"`
+ HcaHandles uint32 `json:"hca_handles,omitempty"`
+ HcaObjects uint32 `json:"hca_objects,omitempty"`
+}
+
+type RdmaStats struct {
+ RdmaLimit []RdmaEntry `json:"rdma_limit,omitempty"`
+ RdmaCurrent []RdmaEntry `json:"rdma_current,omitempty"`
+}
+
type Stats struct {
CpuStats CpuStats `json:"cpu_stats,omitempty"`
CPUSetStats CPUSetStats `json:"cpuset_stats,omitempty"`
@@ -154,6 +163,7 @@ type Stats struct {
BlkioStats BlkioStats `json:"blkio_stats,omitempty"`
// the map is in the format "size of hugepage: stats of the hugepage"
HugetlbStats map[string]HugetlbStats `json:"hugetlb_stats,omitempty"`
+ RdmaStats RdmaStats `json:"rdma_stats,omitempty"`
}
func NewStats() *Stats {
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go
index 92606525b..13ebf52ab 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go
@@ -1,5 +1,3 @@
-// +build linux
-
package cgroups
import (
@@ -7,7 +5,6 @@ import (
"errors"
"fmt"
"io"
- "io/ioutil"
"os"
"path/filepath"
"strconv"
@@ -23,11 +20,14 @@ import (
const (
CgroupProcesses = "cgroup.procs"
unifiedMountpoint = "/sys/fs/cgroup"
+ hybridMountpoint = "/sys/fs/cgroup/unified"
)
var (
isUnifiedOnce sync.Once
isUnified bool
+ isHybridOnce sync.Once
+ isHybrid bool
)
// IsCgroup2UnifiedMode returns whether we are running in cgroup v2 unified mode.
@@ -49,6 +49,24 @@ func IsCgroup2UnifiedMode() bool {
return isUnified
}
+// IsCgroup2HybridMode returns whether we are running in cgroup v2 hybrid mode.
+func IsCgroup2HybridMode() bool {
+ isHybridOnce.Do(func() {
+ var st unix.Statfs_t
+ err := unix.Statfs(hybridMountpoint, &st)
+ if err != nil {
+ if os.IsNotExist(err) {
+ // ignore the "not found" error
+ isHybrid = false
+ return
+ }
+ panic(fmt.Sprintf("cannot statfs cgroup root: %s", err))
+ }
+ isHybrid = st.Type == unix.CGROUP2_SUPER_MAGIC
+ })
+ return isHybrid
+}
+
type Mount struct {
Mountpoint string
Root string
@@ -118,8 +136,8 @@ func GetAllSubsystems() ([]string, error) {
return subsystems, nil
}
-func readProcsFile(file string) ([]int, error) {
- f, err := os.Open(file)
+func readProcsFile(dir string) ([]int, error) {
+ f, err := OpenFile(dir, CgroupProcesses, os.O_RDONLY)
if err != nil {
return nil, err
}
@@ -210,7 +228,7 @@ func EnterPid(cgroupPaths map[string]string, pid int) error {
func rmdir(path string) error {
err := unix.Rmdir(path)
- if err == nil || err == unix.ENOENT {
+ if err == nil || err == unix.ENOENT { //nolint:errorlint // unix errors are bare
return nil
}
return &os.PathError{Op: "rmdir", Path: path, Err: err}
@@ -224,7 +242,7 @@ func RemovePath(path string) error {
return nil
}
- infos, err := ioutil.ReadDir(path)
+ infos, err := os.ReadDir(path)
if err != nil {
if os.IsNotExist(err) {
err = nil
@@ -284,40 +302,61 @@ func RemovePaths(paths map[string]string) (err error) {
return fmt.Errorf("Failed to remove paths: %v", paths)
}
-func GetHugePageSize() ([]string, error) {
- dir, err := os.OpenFile("/sys/kernel/mm/hugepages", unix.O_DIRECTORY|unix.O_RDONLY, 0)
- if err != nil {
- return nil, err
- }
- files, err := dir.Readdirnames(0)
- dir.Close()
- if err != nil {
- return nil, err
- }
+var (
+ hugePageSizes []string
+ initHPSOnce sync.Once
+)
- return getHugePageSizeFromFilenames(files)
+func HugePageSizes() []string {
+ initHPSOnce.Do(func() {
+ dir, err := os.OpenFile("/sys/kernel/mm/hugepages", unix.O_DIRECTORY|unix.O_RDONLY, 0)
+ if err != nil {
+ return
+ }
+ files, err := dir.Readdirnames(0)
+ dir.Close()
+ if err != nil {
+ return
+ }
+
+ hugePageSizes, err = getHugePageSizeFromFilenames(files)
+ if err != nil {
+ logrus.Warn("HugePageSizes: ", err)
+ }
+ })
+
+ return hugePageSizes
}
func getHugePageSizeFromFilenames(fileNames []string) ([]string, error) {
pageSizes := make([]string, 0, len(fileNames))
+ var warn error
for _, file := range fileNames {
// example: hugepages-1048576kB
val := strings.TrimPrefix(file, "hugepages-")
if len(val) == len(file) {
- // unexpected file name: no prefix found
+ // Unexpected file name: no prefix found, ignore it.
continue
}
- // The suffix is always "kB" (as of Linux 5.9)
+ // The suffix is always "kB" (as of Linux 5.13). If we find
+ // something else, produce an error but keep going.
eLen := len(val) - 2
val = strings.TrimSuffix(val, "kB")
if len(val) != eLen {
- logrus.Warnf("GetHugePageSize: %s: invalid filename suffix (expected \"kB\")", file)
+ // Highly unlikely.
+ if warn == nil {
+ warn = errors.New(file + `: invalid suffix (expected "kB")`)
+ }
continue
}
size, err := strconv.Atoi(val)
if err != nil {
- return nil, err
+ // Highly unlikely.
+ if warn == nil {
+ warn = fmt.Errorf("%s: %w", file, err)
+ }
+ continue
}
// Model after https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/mm/hugetlb_cgroup.c?id=eff48ddeab782e35e58ccc8853f7386bbae9dec4#n574
// but in our case the size is in KB already.
@@ -331,34 +370,12 @@ func getHugePageSizeFromFilenames(fileNames []string) ([]string, error) {
pageSizes = append(pageSizes, val)
}
- return pageSizes, nil
+ return pageSizes, warn
}
// GetPids returns all pids, that were added to cgroup at path.
func GetPids(dir string) ([]int, error) {
- return readProcsFile(filepath.Join(dir, CgroupProcesses))
-}
-
-// GetAllPids returns all pids, that were added to cgroup at path and to all its
-// subcgroups.
-func GetAllPids(path string) ([]int, error) {
- var pids []int
- // collect pids from all sub-cgroups
- err := filepath.Walk(path, func(p string, info os.FileInfo, iErr error) error {
- if iErr != nil {
- return iErr
- }
- if info.IsDir() || info.Name() != CgroupProcesses {
- return nil
- }
- cPids, err := readProcsFile(p)
- if err != nil {
- return err
- }
- pids = append(pids, cPids...)
- return nil
- })
- return pids, err
+ return readProcsFile(dir)
}
// WriteCgroupProc writes the specified pid into the cgroup's cgroup.procs file
@@ -376,7 +393,7 @@ func WriteCgroupProc(dir string, pid int) error {
file, err := OpenFile(dir, CgroupProcesses, os.O_WRONLY)
if err != nil {
- return fmt.Errorf("failed to write %v to %v: %v", pid, CgroupProcesses, err)
+ return fmt.Errorf("failed to write %v: %w", pid, err)
}
defer file.Close()
@@ -393,7 +410,7 @@ func WriteCgroupProc(dir string, pid int) error {
continue
}
- return fmt.Errorf("failed to write %v to %v: %v", pid, CgroupProcesses, err)
+ return fmt.Errorf("failed to write %v: %w", pid, err)
}
return err
}
@@ -446,5 +463,5 @@ func ConvertBlkIOToIOWeightValue(blkIoWeight uint16) uint64 {
if blkIoWeight == 0 {
return 0
}
- return uint64(1 + (uint64(blkIoWeight)-10)*9999/990)
+ return 1 + (uint64(blkIoWeight)-10)*9999/990
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/v1_utils.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/v1_utils.go
index 95ec9dff0..47c75f22b 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/v1_utils.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/v1_utils.go
@@ -46,11 +46,8 @@ func NewNotFoundError(sub string) error {
}
func IsNotFound(err error) bool {
- if err == nil {
- return false
- }
- _, ok := err.(*NotFoundError)
- return ok
+ var nfErr *NotFoundError
+ return errors.As(err, &nfErr)
}
func tryDefaultPath(cgroupPath, subsystem string) string {
@@ -116,6 +113,11 @@ func FindCgroupMountpoint(cgroupPath, subsystem string) (string, error) {
return "", errUnified
}
+ // If subsystem is empty, we look for the cgroupv2 hybrid path.
+ if len(subsystem) == 0 {
+ return hybridMountpoint, nil
+ }
+
// Avoid parsing mountinfo by trying the default path first, if possible.
if path := tryDefaultPath(cgroupPath, subsystem); path != "" {
return path, nil
@@ -154,7 +156,7 @@ func findCgroupMountpointAndRootFromMI(mounts []*mountinfo.Info, cgroupPath, sub
func (m Mount) GetOwnCgroup(cgroups map[string]string) (string, error) {
if len(m.Subsystems) == 0 {
- return "", fmt.Errorf("no subsystem for mount")
+ return "", errors.New("no subsystem for mount")
}
return getControllerPath(m.Subsystems[0], cgroups)
@@ -226,6 +228,11 @@ func GetOwnCgroupPath(subsystem string) (string, error) {
return "", err
}
+ // If subsystem is empty, we look for the cgroupv2 hybrid path.
+ if len(subsystem) == 0 {
+ return hybridMountpoint, nil
+ }
+
return getCgroupPathHelper(subsystem, cgroup)
}