diff --git a/libcontainer/cgroups/fscommon/open.go b/libcontainer/cgroups/file.go similarity index 72% rename from libcontainer/cgroups/fscommon/open.go rename to libcontainer/cgroups/file.go index e95876a2176..5f6ab9fd699 100644 --- a/libcontainer/cgroups/fscommon/open.go +++ b/libcontainer/cgroups/file.go @@ -1,6 +1,7 @@ -package fscommon +package cgroups import ( + "bytes" "os" "strings" "sync" @@ -10,6 +11,54 @@ import ( "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. +func OpenFile(dir, file string, flags int) (*os.File, error) { + if dir == "" { + return nil, errors.Errorf("no directory specified for %s", file) + } + return openFile(dir, file, flags) +} + +// ReadFile reads data from a cgroup file in dir. +// It is supposed to be used for cgroup files only. +func ReadFile(dir, file string) (string, error) { + fd, err := OpenFile(dir, file, unix.O_RDONLY) + if err != nil { + return "", err + } + defer fd.Close() + var buf bytes.Buffer + + _, err = buf.ReadFrom(fd) + return buf.String(), err +} + +// WriteFile writes data to a cgroup file in dir. +// It is supposed to be used for cgroup files only. +func WriteFile(dir, file, data string) error { + fd, err := OpenFile(dir, file, unix.O_WRONLY) + if err != nil { + return err + } + defer fd.Close() + if err := retryingWriteFile(fd, data); err != nil { + return errors.Wrapf(err, "failed to write %q", data) + } + return nil +} + +func retryingWriteFile(fd *os.File, data string) error { + for { + _, err := fd.Write([]byte(data)) + if errors.Is(err, unix.EINTR) { + logrus.Infof("interrupted while writing %s to %s", data, fd.Name()) + continue + } + return err + } +} + const ( cgroupfsDir = "/sys/fs/cgroup" cgroupfsPrefix = cgroupfsDir + "/" @@ -60,10 +109,7 @@ func prepareOpenat2() error { // 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) { - if dir == "" { - return nil, errors.Errorf("no directory specified for %s", file) - } +func openFile(dir, file string, flags int) (*os.File, error) { mode := os.FileMode(0) if TestMode && flags&os.O_WRONLY != 0 { // "emulate" cgroup fs for unit tests diff --git a/libcontainer/cgroups/fscommon/fscommon_test.go b/libcontainer/cgroups/file_test.go similarity index 98% rename from libcontainer/cgroups/fscommon/fscommon_test.go rename to libcontainer/cgroups/file_test.go index bed66cbbe5f..4b2cb895007 100644 --- a/libcontainer/cgroups/fscommon/fscommon_test.go +++ b/libcontainer/cgroups/file_test.go @@ -1,6 +1,6 @@ // +build linux -package fscommon +package cgroups import ( "fmt" diff --git a/libcontainer/cgroups/fs/blkio.go b/libcontainer/cgroups/fs/blkio.go index e5240a17c4e..8aa8fcdc41e 100644 --- a/libcontainer/cgroups/fs/blkio.go +++ b/libcontainer/cgroups/fs/blkio.go @@ -11,7 +11,6 @@ import ( "strings" "github.com/opencontainers/runc/libcontainer/cgroups" - "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" "github.com/opencontainers/runc/libcontainer/configs" ) @@ -31,41 +30,41 @@ func (s *BlkioGroup) Apply(path string, d *cgroupData) error { func (s *BlkioGroup) Set(path string, r *configs.Resources) error { s.detectWeightFilenames(path) if r.BlkioWeight != 0 { - if err := fscommon.WriteFile(path, s.weightFilename, strconv.FormatUint(uint64(r.BlkioWeight), 10)); err != nil { + if err := cgroups.WriteFile(path, s.weightFilename, strconv.FormatUint(uint64(r.BlkioWeight), 10)); err != nil { return err } } if r.BlkioLeafWeight != 0 { - if err := fscommon.WriteFile(path, "blkio.leaf_weight", strconv.FormatUint(uint64(r.BlkioLeafWeight), 10)); err != nil { + if err := cgroups.WriteFile(path, "blkio.leaf_weight", strconv.FormatUint(uint64(r.BlkioLeafWeight), 10)); err != nil { return err } } for _, wd := range r.BlkioWeightDevice { - if err := fscommon.WriteFile(path, s.weightDeviceFilename, wd.WeightString()); err != nil { + if err := cgroups.WriteFile(path, s.weightDeviceFilename, wd.WeightString()); err != nil { return err } - if err := fscommon.WriteFile(path, "blkio.leaf_weight_device", wd.LeafWeightString()); err != nil { + if err := cgroups.WriteFile(path, "blkio.leaf_weight_device", wd.LeafWeightString()); err != nil { return err } } for _, td := range r.BlkioThrottleReadBpsDevice { - if err := fscommon.WriteFile(path, "blkio.throttle.read_bps_device", td.String()); err != nil { + if err := cgroups.WriteFile(path, "blkio.throttle.read_bps_device", td.String()); err != nil { return err } } for _, td := range r.BlkioThrottleWriteBpsDevice { - if err := fscommon.WriteFile(path, "blkio.throttle.write_bps_device", td.String()); err != nil { + if err := cgroups.WriteFile(path, "blkio.throttle.write_bps_device", td.String()); err != nil { return err } } for _, td := range r.BlkioThrottleReadIOPSDevice { - if err := fscommon.WriteFile(path, "blkio.throttle.read_iops_device", td.String()); err != nil { + if err := cgroups.WriteFile(path, "blkio.throttle.read_iops_device", td.String()); err != nil { return err } } for _, td := range r.BlkioThrottleWriteIOPSDevice { - if err := fscommon.WriteFile(path, "blkio.throttle.write_iops_device", td.String()); err != nil { + if err := cgroups.WriteFile(path, "blkio.throttle.write_iops_device", td.String()); err != nil { return err } } @@ -110,7 +109,7 @@ func splitBlkioStatLine(r rune) bool { func getBlkioStat(dir, file string) ([]cgroups.BlkioStatEntry, error) { var blkioStats []cgroups.BlkioStatEntry - f, err := fscommon.OpenFile(dir, file, os.O_RDONLY) + f, err := cgroups.OpenFile(dir, file, os.O_RDONLY) if err != nil { if os.IsNotExist(err) { return blkioStats, nil diff --git a/libcontainer/cgroups/fs/cpu.go b/libcontainer/cgroups/fs/cpu.go index 062c9e88cdc..31c1c874ea0 100644 --- a/libcontainer/cgroups/fs/cpu.go +++ b/libcontainer/cgroups/fs/cpu.go @@ -41,12 +41,12 @@ func (s *CpuGroup) Apply(path string, d *cgroupData) error { func (s *CpuGroup) SetRtSched(path string, r *configs.Resources) error { if r.CpuRtPeriod != 0 { - if err := fscommon.WriteFile(path, "cpu.rt_period_us", strconv.FormatUint(r.CpuRtPeriod, 10)); err != nil { + if err := cgroups.WriteFile(path, "cpu.rt_period_us", strconv.FormatUint(r.CpuRtPeriod, 10)); err != nil { return err } } if r.CpuRtRuntime != 0 { - if err := fscommon.WriteFile(path, "cpu.rt_runtime_us", strconv.FormatInt(r.CpuRtRuntime, 10)); err != nil { + if err := cgroups.WriteFile(path, "cpu.rt_runtime_us", strconv.FormatInt(r.CpuRtRuntime, 10)); err != nil { return err } } @@ -56,7 +56,7 @@ func (s *CpuGroup) SetRtSched(path string, r *configs.Resources) error { func (s *CpuGroup) Set(path string, r *configs.Resources) error { if r.CpuShares != 0 { shares := r.CpuShares - if err := fscommon.WriteFile(path, "cpu.shares", strconv.FormatUint(shares, 10)); err != nil { + if err := cgroups.WriteFile(path, "cpu.shares", strconv.FormatUint(shares, 10)); err != nil { return err } // read it back @@ -72,12 +72,12 @@ func (s *CpuGroup) Set(path string, r *configs.Resources) error { } } if r.CpuPeriod != 0 { - if err := fscommon.WriteFile(path, "cpu.cfs_period_us", strconv.FormatUint(r.CpuPeriod, 10)); err != nil { + if err := cgroups.WriteFile(path, "cpu.cfs_period_us", strconv.FormatUint(r.CpuPeriod, 10)); err != nil { return err } } if r.CpuQuota != 0 { - if err := fscommon.WriteFile(path, "cpu.cfs_quota_us", strconv.FormatInt(r.CpuQuota, 10)); err != nil { + if err := cgroups.WriteFile(path, "cpu.cfs_quota_us", strconv.FormatInt(r.CpuQuota, 10)); err != nil { return err } } @@ -85,7 +85,7 @@ func (s *CpuGroup) Set(path string, r *configs.Resources) error { } func (s *CpuGroup) GetStats(path string, stats *cgroups.Stats) error { - f, err := fscommon.OpenFile(path, "cpu.stat", os.O_RDONLY) + f, err := cgroups.OpenFile(path, "cpu.stat", os.O_RDONLY) if err != nil { if os.IsNotExist(err) { return nil diff --git a/libcontainer/cgroups/fs/cpuacct.go b/libcontainer/cgroups/fs/cpuacct.go index 94b845c1144..4fbf078494c 100644 --- a/libcontainer/cgroups/fs/cpuacct.go +++ b/libcontainer/cgroups/fs/cpuacct.go @@ -90,7 +90,7 @@ func getCpuUsageBreakdown(path string) (uint64, uint64, error) { // Expected format: // user // system - data, err := fscommon.ReadFile(path, cgroupCpuacctStat) + data, err := cgroups.ReadFile(path, cgroupCpuacctStat) if err != nil { return 0, 0, err } @@ -116,7 +116,7 @@ func getCpuUsageBreakdown(path string) (uint64, uint64, error) { func getPercpuUsage(path string) ([]uint64, error) { percpuUsage := []uint64{} - data, err := fscommon.ReadFile(path, "cpuacct.usage_percpu") + data, err := cgroups.ReadFile(path, "cpuacct.usage_percpu") if err != nil { return percpuUsage, err } @@ -134,7 +134,7 @@ func getPercpuUsageInModes(path string) ([]uint64, []uint64, error) { usageKernelMode := []uint64{} usageUserMode := []uint64{} - file, err := fscommon.OpenFile(path, cgroupCpuacctUsageAll, os.O_RDONLY) + file, err := cgroups.OpenFile(path, cgroupCpuacctUsageAll, os.O_RDONLY) if os.IsNotExist(err) { return usageKernelMode, usageUserMode, nil } else if err != nil { diff --git a/libcontainer/cgroups/fs/cpuset.go b/libcontainer/cgroups/fs/cpuset.go index f9d3fb18547..58a0f040644 100644 --- a/libcontainer/cgroups/fs/cpuset.go +++ b/libcontainer/cgroups/fs/cpuset.go @@ -28,12 +28,12 @@ func (s *CpusetGroup) Apply(path string, d *cgroupData) error { func (s *CpusetGroup) Set(path string, r *configs.Resources) error { if r.CpusetCpus != "" { - if err := fscommon.WriteFile(path, "cpuset.cpus", r.CpusetCpus); err != nil { + if err := cgroups.WriteFile(path, "cpuset.cpus", r.CpusetCpus); err != nil { return err } } if r.CpusetMems != "" { - if err := fscommon.WriteFile(path, "cpuset.mems", r.CpusetMems); err != nil { + if err := cgroups.WriteFile(path, "cpuset.mems", r.CpusetMems); err != nil { return err } } @@ -175,10 +175,10 @@ func (s *CpusetGroup) ApplyDir(dir string, r *configs.Resources, pid int) error } func getCpusetSubsystemSettings(parent string) (cpus, mems string, err error) { - if cpus, err = fscommon.ReadFile(parent, "cpuset.cpus"); err != nil { + if cpus, err = cgroups.ReadFile(parent, "cpuset.cpus"); err != nil { return } - if mems, err = fscommon.ReadFile(parent, "cpuset.mems"); err != nil { + if mems, err = cgroups.ReadFile(parent, "cpuset.mems"); err != nil { return } return cpus, mems, nil @@ -224,12 +224,12 @@ func cpusetCopyIfNeeded(current, parent string) error { } if isEmptyCpuset(currentCpus) { - if err := fscommon.WriteFile(current, "cpuset.cpus", string(parentCpus)); err != nil { + if err := cgroups.WriteFile(current, "cpuset.cpus", string(parentCpus)); err != nil { return err } } if isEmptyCpuset(currentMems) { - if err := fscommon.WriteFile(current, "cpuset.mems", string(parentMems)); err != nil { + if err := cgroups.WriteFile(current, "cpuset.mems", string(parentMems)); err != nil { return err } } diff --git a/libcontainer/cgroups/fs/devices.go b/libcontainer/cgroups/fs/devices.go index 048f11398a9..dcf69ce13e7 100644 --- a/libcontainer/cgroups/fs/devices.go +++ b/libcontainer/cgroups/fs/devices.go @@ -9,7 +9,6 @@ import ( "github.com/opencontainers/runc/libcontainer/cgroups" cgroupdevices "github.com/opencontainers/runc/libcontainer/cgroups/devices" - "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/devices" "github.com/opencontainers/runc/libcontainer/userns" @@ -36,7 +35,7 @@ func (s *DevicesGroup) Apply(path string, d *cgroupData) error { } func loadEmulator(path string) (*cgroupdevices.Emulator, error) { - list, err := fscommon.ReadFile(path, "devices.list") + list, err := cgroups.ReadFile(path, "devices.list") if err != nil { return nil, err } @@ -81,7 +80,7 @@ func (s *DevicesGroup) Set(path string, r *configs.Resources) error { if rule.Allow { file = "devices.allow" } - if err := fscommon.WriteFile(path, file, rule.CgroupString()); err != nil { + if err := cgroups.WriteFile(path, file, rule.CgroupString()); err != nil { return err } } diff --git a/libcontainer/cgroups/fs/freezer.go b/libcontainer/cgroups/fs/freezer.go index f621c59962f..519bd5136d1 100644 --- a/libcontainer/cgroups/fs/freezer.go +++ b/libcontainer/cgroups/fs/freezer.go @@ -10,7 +10,6 @@ import ( "time" "github.com/opencontainers/runc/libcontainer/cgroups" - "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" "github.com/opencontainers/runc/libcontainer/configs" "github.com/sirupsen/logrus" "golang.org/x/sys/unix" @@ -34,7 +33,7 @@ func (s *FreezerGroup) Set(path string, r *configs.Resources) (Err error) { // Freezing failed, and it is bad and dangerous // to leave the cgroup in FROZEN or FREEZING // state, so (try to) thaw it back. - _ = fscommon.WriteFile(path, "freezer.state", string(configs.Thawed)) + _ = cgroups.WriteFile(path, "freezer.state", string(configs.Thawed)) } }() @@ -67,11 +66,11 @@ func (s *FreezerGroup) Set(path string, r *configs.Resources) (Err error) { // the chances to succeed in freezing // in case new processes keep appearing // in the cgroup. - _ = fscommon.WriteFile(path, "freezer.state", string(configs.Thawed)) + _ = cgroups.WriteFile(path, "freezer.state", string(configs.Thawed)) time.Sleep(10 * time.Millisecond) } - if err := fscommon.WriteFile(path, "freezer.state", string(configs.Frozen)); err != nil { + if err := cgroups.WriteFile(path, "freezer.state", string(configs.Frozen)); err != nil { return err } @@ -82,7 +81,7 @@ func (s *FreezerGroup) Set(path string, r *configs.Resources) (Err error) { // system. time.Sleep(10 * time.Microsecond) } - state, err := fscommon.ReadFile(path, "freezer.state") + state, err := cgroups.ReadFile(path, "freezer.state") if err != nil { return err } @@ -103,7 +102,7 @@ func (s *FreezerGroup) Set(path string, r *configs.Resources) (Err error) { // Despite our best efforts, it got stuck in FREEZING. return errors.New("unable to freeze") case configs.Thawed: - return fscommon.WriteFile(path, "freezer.state", string(configs.Thawed)) + return cgroups.WriteFile(path, "freezer.state", string(configs.Thawed)) case configs.Undefined: return nil default: @@ -117,7 +116,7 @@ func (s *FreezerGroup) GetStats(path string, stats *cgroups.Stats) error { func (s *FreezerGroup) GetState(path string) (configs.FreezerState, error) { for { - state, err := fscommon.ReadFile(path, "freezer.state") + state, err := cgroups.ReadFile(path, "freezer.state") if err != nil { // If the kernel is too old, then we just treat the freezer as // being in an "undefined" state. diff --git a/libcontainer/cgroups/fs/fs_test.go b/libcontainer/cgroups/fs/fs_test.go index b19b26e44b3..1d16ca5e76d 100644 --- a/libcontainer/cgroups/fs/fs_test.go +++ b/libcontainer/cgroups/fs/fs_test.go @@ -8,7 +8,6 @@ import ( "testing" "github.com/opencontainers/runc/libcontainer/cgroups" - "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" "github.com/opencontainers/runc/libcontainer/configs" ) @@ -113,9 +112,9 @@ func BenchmarkGetStats(b *testing.B) { // Unset TestMode as we work with real cgroupfs here, // and we want OpenFile to perform the fstype check. - fscommon.TestMode = false + cgroups.TestMode = false defer func() { - fscommon.TestMode = true + cgroups.TestMode = true }() cg := &configs.Cgroup{ diff --git a/libcontainer/cgroups/fs/hugetlb.go b/libcontainer/cgroups/fs/hugetlb.go index 44f786dafa7..3cafc5399ee 100644 --- a/libcontainer/cgroups/fs/hugetlb.go +++ b/libcontainer/cgroups/fs/hugetlb.go @@ -23,7 +23,7 @@ func (s *HugetlbGroup) Apply(path string, d *cgroupData) error { func (s *HugetlbGroup) Set(path string, r *configs.Resources) error { for _, hugetlb := range r.HugetlbLimit { - if err := fscommon.WriteFile(path, "hugetlb."+hugetlb.Pagesize+".limit_in_bytes", strconv.FormatUint(hugetlb.Limit, 10)); err != nil { + if err := cgroups.WriteFile(path, "hugetlb."+hugetlb.Pagesize+".limit_in_bytes", strconv.FormatUint(hugetlb.Limit, 10)); err != nil { return err } } diff --git a/libcontainer/cgroups/fs/memory.go b/libcontainer/cgroups/fs/memory.go index 35c77dc58d5..33946726f15 100644 --- a/libcontainer/cgroups/fs/memory.go +++ b/libcontainer/cgroups/fs/memory.go @@ -40,7 +40,7 @@ func setMemory(path string, val int64) error { return nil } - err := fscommon.WriteFile(path, cgroupMemoryLimit, strconv.FormatInt(val, 10)) + err := cgroups.WriteFile(path, cgroupMemoryLimit, strconv.FormatInt(val, 10)) if !errors.Is(err, unix.EBUSY) { return err } @@ -64,7 +64,7 @@ func setSwap(path string, val int64) error { return nil } - return fscommon.WriteFile(path, cgroupMemorySwapLimit, strconv.FormatInt(val, 10)) + return cgroups.WriteFile(path, cgroupMemorySwapLimit, strconv.FormatInt(val, 10)) } func setMemoryAndSwap(path string, r *configs.Resources) error { @@ -117,20 +117,20 @@ func (s *MemoryGroup) Set(path string, r *configs.Resources) error { // ignore KernelMemory and KernelMemoryTCP if r.MemoryReservation != 0 { - if err := fscommon.WriteFile(path, "memory.soft_limit_in_bytes", strconv.FormatInt(r.MemoryReservation, 10)); err != nil { + if err := cgroups.WriteFile(path, "memory.soft_limit_in_bytes", strconv.FormatInt(r.MemoryReservation, 10)); err != nil { return err } } if r.OomKillDisable { - if err := fscommon.WriteFile(path, "memory.oom_control", "1"); err != nil { + if err := cgroups.WriteFile(path, "memory.oom_control", "1"); err != nil { return err } } if r.MemorySwappiness == nil || int64(*r.MemorySwappiness) == -1 { return nil } else if *r.MemorySwappiness <= 100 { - if err := fscommon.WriteFile(path, "memory.swappiness", strconv.FormatUint(*r.MemorySwappiness, 10)); err != nil { + if err := cgroups.WriteFile(path, "memory.swappiness", strconv.FormatUint(*r.MemorySwappiness, 10)); err != nil { return err } } else { @@ -142,7 +142,7 @@ func (s *MemoryGroup) Set(path string, r *configs.Resources) error { func (s *MemoryGroup) GetStats(path string, stats *cgroups.Stats) error { // Set stats from memory.stat. - statsFile, err := fscommon.OpenFile(path, "memory.stat", os.O_RDONLY) + statsFile, err := cgroups.OpenFile(path, "memory.stat", os.O_RDONLY) if err != nil { if os.IsNotExist(err) { return nil @@ -249,7 +249,7 @@ func getPageUsageByNUMA(cgroupPath string) (cgroups.PageUsageByNUMA, error) { ) stats := cgroups.PageUsageByNUMA{} - file, err := fscommon.OpenFile(cgroupPath, filename, os.O_RDONLY) + file, err := cgroups.OpenFile(cgroupPath, filename, os.O_RDONLY) if os.IsNotExist(err) { return stats, nil } else if err != nil { diff --git a/libcontainer/cgroups/fs/net_cls.go b/libcontainer/cgroups/fs/net_cls.go index 9f0230404d1..f2617aa4442 100644 --- a/libcontainer/cgroups/fs/net_cls.go +++ b/libcontainer/cgroups/fs/net_cls.go @@ -6,7 +6,6 @@ import ( "strconv" "github.com/opencontainers/runc/libcontainer/cgroups" - "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" "github.com/opencontainers/runc/libcontainer/configs" ) @@ -22,7 +21,7 @@ func (s *NetClsGroup) Apply(path string, d *cgroupData) error { func (s *NetClsGroup) Set(path string, r *configs.Resources) error { if r.NetClsClassid != 0 { - if err := fscommon.WriteFile(path, "net_cls.classid", strconv.FormatUint(uint64(r.NetClsClassid), 10)); err != nil { + if err := cgroups.WriteFile(path, "net_cls.classid", strconv.FormatUint(uint64(r.NetClsClassid), 10)); err != nil { return err } } diff --git a/libcontainer/cgroups/fs/net_prio.go b/libcontainer/cgroups/fs/net_prio.go index 4944318cbd2..d0ac5e66bbb 100644 --- a/libcontainer/cgroups/fs/net_prio.go +++ b/libcontainer/cgroups/fs/net_prio.go @@ -4,7 +4,6 @@ package fs import ( "github.com/opencontainers/runc/libcontainer/cgroups" - "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" "github.com/opencontainers/runc/libcontainer/configs" ) @@ -20,7 +19,7 @@ func (s *NetPrioGroup) Apply(path string, d *cgroupData) error { func (s *NetPrioGroup) Set(path string, r *configs.Resources) error { for _, prioMap := range r.NetPrioIfpriomap { - if err := fscommon.WriteFile(path, "net_prio.ifpriomap", prioMap.CgroupString()); err != nil { + if err := cgroups.WriteFile(path, "net_prio.ifpriomap", prioMap.CgroupString()); err != nil { return err } } diff --git a/libcontainer/cgroups/fs/pids.go b/libcontainer/cgroups/fs/pids.go index 49d2764cafa..1b08433c450 100644 --- a/libcontainer/cgroups/fs/pids.go +++ b/libcontainer/cgroups/fs/pids.go @@ -31,7 +31,7 @@ func (s *PidsGroup) Set(path string, r *configs.Resources) error { limit = strconv.FormatInt(r.PidsLimit, 10) } - if err := fscommon.WriteFile(path, "pids.max", limit); err != nil { + if err := cgroups.WriteFile(path, "pids.max", limit); err != nil { return err } } diff --git a/libcontainer/cgroups/fs/util_test.go b/libcontainer/cgroups/fs/util_test.go index 572c3882bb1..e35509b8fdf 100644 --- a/libcontainer/cgroups/fs/util_test.go +++ b/libcontainer/cgroups/fs/util_test.go @@ -13,12 +13,12 @@ import ( "path/filepath" "testing" - "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" + "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/configs" ) func init() { - fscommon.TestMode = true + cgroups.TestMode = true } type cgroupTestUtil struct { @@ -64,7 +64,7 @@ func (c *cgroupTestUtil) cleanup() { // Write the specified contents on the mock of the specified cgroup files. func (c *cgroupTestUtil) writeFileContents(fileContents map[string]string) { for file, contents := range fileContents { - err := fscommon.WriteFile(c.CgroupPath, file, contents) + err := cgroups.WriteFile(c.CgroupPath, file, contents) if err != nil { c.t.Fatal(err) } diff --git a/libcontainer/cgroups/fs2/cpu.go b/libcontainer/cgroups/fs2/cpu.go index f09b7d5167c..25c47c9617e 100644 --- a/libcontainer/cgroups/fs2/cpu.go +++ b/libcontainer/cgroups/fs2/cpu.go @@ -23,7 +23,7 @@ func setCpu(dirPath string, r *configs.Resources) error { // NOTE: .CpuShares is not used here. Conversion is the caller's responsibility. if r.CpuWeight != 0 { - if err := fscommon.WriteFile(dirPath, "cpu.weight", strconv.FormatUint(r.CpuWeight, 10)); err != nil { + if err := cgroups.WriteFile(dirPath, "cpu.weight", strconv.FormatUint(r.CpuWeight, 10)); err != nil { return err } } @@ -40,7 +40,7 @@ func setCpu(dirPath string, r *configs.Resources) error { period = 100000 } str += " " + strconv.FormatUint(period, 10) - if err := fscommon.WriteFile(dirPath, "cpu.max", str); err != nil { + if err := cgroups.WriteFile(dirPath, "cpu.max", str); err != nil { return err } } @@ -49,7 +49,7 @@ func setCpu(dirPath string, r *configs.Resources) error { } func statCpu(dirPath string, stats *cgroups.Stats) error { - f, err := fscommon.OpenFile(dirPath, "cpu.stat", os.O_RDONLY) + f, err := cgroups.OpenFile(dirPath, "cpu.stat", os.O_RDONLY) if err != nil { return err } diff --git a/libcontainer/cgroups/fs2/cpuset.go b/libcontainer/cgroups/fs2/cpuset.go index 713c430dc4d..da29d7f2bbb 100644 --- a/libcontainer/cgroups/fs2/cpuset.go +++ b/libcontainer/cgroups/fs2/cpuset.go @@ -3,7 +3,7 @@ package fs2 import ( - "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" + "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/configs" ) @@ -17,12 +17,12 @@ func setCpuset(dirPath string, r *configs.Resources) error { } if r.CpusetCpus != "" { - if err := fscommon.WriteFile(dirPath, "cpuset.cpus", r.CpusetCpus); err != nil { + if err := cgroups.WriteFile(dirPath, "cpuset.cpus", r.CpusetCpus); err != nil { return err } } if r.CpusetMems != "" { - if err := fscommon.WriteFile(dirPath, "cpuset.mems", r.CpusetMems); err != nil { + if err := cgroups.WriteFile(dirPath, "cpuset.mems", r.CpusetMems); err != nil { return err } } diff --git a/libcontainer/cgroups/fs2/create.go b/libcontainer/cgroups/fs2/create.go index 4246fbdcf82..641123a4d84 100644 --- a/libcontainer/cgroups/fs2/create.go +++ b/libcontainer/cgroups/fs2/create.go @@ -6,12 +6,12 @@ import ( "path/filepath" "strings" - "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" + "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/configs" ) func supportedControllers() (string, error) { - return fscommon.ReadFile(UnifiedMountpoint, "/cgroup.controllers") + return cgroups.ReadFile(UnifiedMountpoint, "/cgroup.controllers") } // needAnyControllers returns whether we enable some supported controllers or not, @@ -105,7 +105,7 @@ func CreateCgroupPath(path string, c *configs.Cgroup) (Err error) { } }() } - cgType, _ := fscommon.ReadFile(current, cgTypeFile) + cgType, _ := cgroups.ReadFile(current, cgTypeFile) cgType = strings.TrimSpace(cgType) switch cgType { // If the cgroup is in an invalid mode (usually this means there's an internal @@ -122,7 +122,7 @@ func CreateCgroupPath(path string, c *configs.Cgroup) (Err error) { // since that means we're a properly delegated cgroup subtree) but in // this case there's not much we can do and it's better than giving an // error. - _ = fscommon.WriteFile(current, cgTypeFile, "threaded") + _ = cgroups.WriteFile(current, cgTypeFile, "threaded") } // If the cgroup is in (threaded) or (domain threaded) mode, we can only use thread-aware controllers // (and you cannot usually take a cgroup out of threaded mode). @@ -136,11 +136,11 @@ func CreateCgroupPath(path string, c *configs.Cgroup) (Err error) { } // enable all supported controllers if i < len(elements)-1 { - if err := fscommon.WriteFile(current, cgStCtlFile, res); err != nil { + if err := cgroups.WriteFile(current, cgStCtlFile, res); err != nil { // try write one by one allCtrs := strings.Split(res, " ") for _, ctr := range allCtrs { - _ = fscommon.WriteFile(current, cgStCtlFile, ctr) + _ = cgroups.WriteFile(current, cgStCtlFile, ctr) } } // Some controllers might not be enabled when rootless or containerized, diff --git a/libcontainer/cgroups/fs2/freezer.go b/libcontainer/cgroups/fs2/freezer.go index 6afd17851ad..e901f7a07b1 100644 --- a/libcontainer/cgroups/fs2/freezer.go +++ b/libcontainer/cgroups/fs2/freezer.go @@ -10,7 +10,7 @@ import ( "strings" "time" - "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" + "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/configs" "github.com/pkg/errors" "golang.org/x/sys/unix" @@ -29,7 +29,7 @@ func setFreezer(dirPath string, state configs.FreezerState) error { return errors.Errorf("invalid freezer state %q requested", state) } - fd, err := fscommon.OpenFile(dirPath, "cgroup.freeze", unix.O_RDWR) + fd, err := cgroups.OpenFile(dirPath, "cgroup.freeze", unix.O_RDWR) if err != nil { // We can ignore this request as long as the user didn't ask us to // freeze the container (since without the freezer cgroup, that's a @@ -54,7 +54,7 @@ func setFreezer(dirPath string, state configs.FreezerState) error { } func getFreezer(dirPath string) (configs.FreezerState, error) { - fd, err := fscommon.OpenFile(dirPath, "cgroup.freeze", unix.O_RDONLY) + fd, err := cgroups.OpenFile(dirPath, "cgroup.freeze", unix.O_RDONLY) if err != nil { // If the kernel is too old, then we just treat the freezer as being in // an "undefined" state. @@ -88,7 +88,7 @@ func readFreezer(dirPath string, fd *os.File) (configs.FreezerState, error) { // waitFrozen polls cgroup.events until it sees "frozen 1" in it. func waitFrozen(dirPath string) (configs.FreezerState, error) { - fd, err := fscommon.OpenFile(dirPath, "cgroup.events", unix.O_RDONLY) + fd, err := cgroups.OpenFile(dirPath, "cgroup.events", unix.O_RDONLY) if err != nil { return configs.Undefined, err } diff --git a/libcontainer/cgroups/fs2/fs2.go b/libcontainer/cgroups/fs2/fs2.go index 39e017af0a6..afba0ab1c88 100644 --- a/libcontainer/cgroups/fs2/fs2.go +++ b/libcontainer/cgroups/fs2/fs2.go @@ -51,7 +51,7 @@ func (m *manager) getControllers() error { return nil } - data, err := fscommon.ReadFile(m.dirPath, "cgroup.controllers") + data, err := cgroups.ReadFile(m.dirPath, "cgroup.controllers") if err != nil { if m.rootless && m.config.Path == "" { return nil @@ -197,7 +197,7 @@ func (m *manager) setUnified(res map[string]string) error { if strings.Contains(k, "/") { return fmt.Errorf("unified resource %q must be a file name (no slashes)", k) } - if err := fscommon.WriteFile(m.dirPath, k, v); err != nil { + if err := cgroups.WriteFile(m.dirPath, k, v); err != nil { errC := errors.Cause(err) // Check for both EPERM and ENOENT since O_CREAT is used by WriteFile. if errors.Is(errC, os.ErrPermission) || errors.Is(errC, os.ErrNotExist) { diff --git a/libcontainer/cgroups/fs2/hugetlb.go b/libcontainer/cgroups/fs2/hugetlb.go index 76df770109c..3f513975bd3 100644 --- a/libcontainer/cgroups/fs2/hugetlb.go +++ b/libcontainer/cgroups/fs2/hugetlb.go @@ -21,7 +21,7 @@ func setHugeTlb(dirPath string, r *configs.Resources) error { return nil } for _, hugetlb := range r.HugetlbLimit { - if err := fscommon.WriteFile(dirPath, "hugetlb."+hugetlb.Pagesize+".max", strconv.FormatUint(hugetlb.Limit, 10)); err != nil { + if err := cgroups.WriteFile(dirPath, "hugetlb."+hugetlb.Pagesize+".max", strconv.FormatUint(hugetlb.Limit, 10)); err != nil { return err } } diff --git a/libcontainer/cgroups/fs2/io.go b/libcontainer/cgroups/fs2/io.go index 77174f437fe..864a4c1ca6a 100644 --- a/libcontainer/cgroups/fs2/io.go +++ b/libcontainer/cgroups/fs2/io.go @@ -11,7 +11,6 @@ import ( "github.com/sirupsen/logrus" "github.com/opencontainers/runc/libcontainer/cgroups" - "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" "github.com/opencontainers/runc/libcontainer/configs" ) @@ -30,7 +29,7 @@ func setIo(dirPath string, r *configs.Resources) error { if r.BlkioWeight != 0 { filename := "io.bfq.weight" - if err := fscommon.WriteFile(dirPath, filename, + if err := cgroups.WriteFile(dirPath, filename, strconv.FormatUint(uint64(r.BlkioWeight), 10)); err != nil { // if io.bfq.weight does not exist, then bfq module is not loaded. // Fallback to use io.weight with a conversion scheme @@ -38,28 +37,28 @@ func setIo(dirPath string, r *configs.Resources) error { return err } v := cgroups.ConvertBlkIOToIOWeightValue(r.BlkioWeight) - if err := fscommon.WriteFile(dirPath, "io.weight", strconv.FormatUint(v, 10)); err != nil { + if err := cgroups.WriteFile(dirPath, "io.weight", strconv.FormatUint(v, 10)); err != nil { return err } } } for _, td := range r.BlkioThrottleReadBpsDevice { - if err := fscommon.WriteFile(dirPath, "io.max", td.StringName("rbps")); err != nil { + if err := cgroups.WriteFile(dirPath, "io.max", td.StringName("rbps")); err != nil { return err } } for _, td := range r.BlkioThrottleWriteBpsDevice { - if err := fscommon.WriteFile(dirPath, "io.max", td.StringName("wbps")); err != nil { + if err := cgroups.WriteFile(dirPath, "io.max", td.StringName("wbps")); err != nil { return err } } for _, td := range r.BlkioThrottleReadIOPSDevice { - if err := fscommon.WriteFile(dirPath, "io.max", td.StringName("riops")); err != nil { + if err := cgroups.WriteFile(dirPath, "io.max", td.StringName("riops")); err != nil { return err } } for _, td := range r.BlkioThrottleWriteIOPSDevice { - if err := fscommon.WriteFile(dirPath, "io.max", td.StringName("wiops")); err != nil { + if err := cgroups.WriteFile(dirPath, "io.max", td.StringName("wiops")); err != nil { return err } } @@ -69,7 +68,7 @@ func setIo(dirPath string, r *configs.Resources) error { func readCgroup2MapFile(dirPath string, name string) (map[string][]string, error) { ret := map[string][]string{} - f, err := fscommon.OpenFile(dirPath, name, os.O_RDONLY) + f, err := cgroups.OpenFile(dirPath, name, os.O_RDONLY) if err != nil { return nil, err } diff --git a/libcontainer/cgroups/fs2/io_test.go b/libcontainer/cgroups/fs2/io_test.go index 71e5c7185a9..9b27061732c 100644 --- a/libcontainer/cgroups/fs2/io_test.go +++ b/libcontainer/cgroups/fs2/io_test.go @@ -9,7 +9,6 @@ import ( "testing" "github.com/opencontainers/runc/libcontainer/cgroups" - "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" ) const exampleIoStatData = `254:1 rbytes=6901432320 wbytes=14245535744 rios=263278 wios=248603 dbytes=0 dios=0 @@ -59,7 +58,7 @@ func sortBlkioStats(stats *cgroups.BlkioStats) { func TestStatIo(t *testing.T) { // We're using a fake cgroupfs. - fscommon.TestMode = true + cgroups.TestMode = true fakeCgroupDir, err := ioutil.TempDir("", "runc-stat-io-test.*") if err != nil { diff --git a/libcontainer/cgroups/fs2/memory.go b/libcontainer/cgroups/fs2/memory.go index 7308f5a205c..53e8f1e9349 100644 --- a/libcontainer/cgroups/fs2/memory.go +++ b/libcontainer/cgroups/fs2/memory.go @@ -52,13 +52,13 @@ func setMemory(dirPath string, r *configs.Resources) error { } // never write empty string to `memory.swap.max`, it means set to 0. if swapStr != "" { - if err := fscommon.WriteFile(dirPath, "memory.swap.max", swapStr); err != nil { + if err := cgroups.WriteFile(dirPath, "memory.swap.max", swapStr); err != nil { return err } } if val := numToStr(r.Memory); val != "" { - if err := fscommon.WriteFile(dirPath, "memory.max", val); err != nil { + if err := cgroups.WriteFile(dirPath, "memory.max", val); err != nil { return err } } @@ -66,7 +66,7 @@ func setMemory(dirPath string, r *configs.Resources) error { // cgroup.Resources.KernelMemory is ignored if val := numToStr(r.MemoryReservation); val != "" { - if err := fscommon.WriteFile(dirPath, "memory.low", val); err != nil { + if err := cgroups.WriteFile(dirPath, "memory.low", val); err != nil { return err } } @@ -76,7 +76,7 @@ func setMemory(dirPath string, r *configs.Resources) error { func statMemory(dirPath string, stats *cgroups.Stats) error { // Set stats from memory.stat. - statsFile, err := fscommon.OpenFile(dirPath, "memory.stat", os.O_RDONLY) + statsFile, err := cgroups.OpenFile(dirPath, "memory.stat", os.O_RDONLY) if err != nil { return err } diff --git a/libcontainer/cgroups/fs2/pids.go b/libcontainer/cgroups/fs2/pids.go index 346fdb67873..e2050002d0e 100644 --- a/libcontainer/cgroups/fs2/pids.go +++ b/libcontainer/cgroups/fs2/pids.go @@ -23,7 +23,7 @@ func setPids(dirPath string, r *configs.Resources) error { return nil } if val := numToStr(r.PidsLimit); val != "" { - if err := fscommon.WriteFile(dirPath, "pids.max", val); err != nil { + if err := cgroups.WriteFile(dirPath, "pids.max", val); err != nil { return err } } @@ -34,9 +34,9 @@ func setPids(dirPath string, r *configs.Resources) error { func statPidsFromCgroupProcs(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 := fscommon.ReadFile(dirPath, "cgroup.procs") + contents, err := cgroups.ReadFile(dirPath, "cgroup.procs") if errors.Is(err, unix.ENOTSUP) { - contents, err = fscommon.ReadFile(dirPath, "cgroup.threads") + contents, err = cgroups.ReadFile(dirPath, "cgroup.threads") } if err != nil { return err diff --git a/libcontainer/cgroups/fscommon/fscommon.go b/libcontainer/cgroups/fscommon/fscommon.go deleted file mode 100644 index ae2613cdbd1..00000000000 --- a/libcontainer/cgroups/fscommon/fscommon.go +++ /dev/null @@ -1,51 +0,0 @@ -// +build linux - -package fscommon - -import ( - "bytes" - "os" - - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "golang.org/x/sys/unix" -) - -// WriteFile writes data to a cgroup file in dir. -// It is supposed to be used for cgroup files only. -func WriteFile(dir, file, data string) error { - fd, err := OpenFile(dir, file, unix.O_WRONLY) - if err != nil { - return err - } - defer fd.Close() - if err := retryingWriteFile(fd, data); err != nil { - return errors.Wrapf(err, "failed to write %q", data) - } - return nil -} - -// ReadFile reads data from a cgroup file in dir. -// It is supposed to be used for cgroup files only. -func ReadFile(dir, file string) (string, error) { - fd, err := OpenFile(dir, file, unix.O_RDONLY) - if err != nil { - return "", err - } - defer fd.Close() - var buf bytes.Buffer - - _, err = buf.ReadFrom(fd) - return buf.String(), err -} - -func retryingWriteFile(fd *os.File, data string) error { - for { - _, err := fd.Write([]byte(data)) - if errors.Is(err, unix.EINTR) { - logrus.Infof("interrupted while writing %s to %s", data, fd.Name()) - continue - } - return err - } -} diff --git a/libcontainer/cgroups/fscommon/utils.go b/libcontainer/cgroups/fscommon/utils.go index 44d57f478e9..cbac9740741 100644 --- a/libcontainer/cgroups/fscommon/utils.go +++ b/libcontainer/cgroups/fscommon/utils.go @@ -8,6 +8,8 @@ import ( "math" "strconv" "strings" + + "github.com/opencontainers/runc/libcontainer/cgroups" ) var ErrNotValidFormat = errors.New("line is not a valid key value format") @@ -55,7 +57,7 @@ func ParseKeyValue(t string) (string, uint64, error) { // and returns a value of the specified key. ParseUint is used for value // conversion. func GetValueByKey(path, file, key string) (uint64, error) { - content, err := ReadFile(path, file) + content, err := cgroups.ReadFile(path, file) if err != nil { return 0, err } @@ -93,7 +95,7 @@ func GetCgroupParamUint(path, file string) (uint64, error) { // GetCgroupParamInt reads a single int64 value from specified cgroup file. // If the value read is "max", the math.MaxInt64 is returned. func GetCgroupParamInt(path, file string) (int64, error) { - contents, err := ReadFile(path, file) + contents, err := cgroups.ReadFile(path, file) if err != nil { return 0, err } @@ -111,7 +113,7 @@ func GetCgroupParamInt(path, file string) (int64, error) { // GetCgroupParamString reads a string from the specified cgroup file. func GetCgroupParamString(path, file string) (string, error) { - contents, err := ReadFile(path, file) + contents, err := cgroups.ReadFile(path, file) if err != nil { return "", err } diff --git a/libcontainer/cgroups/fscommon/utils_test.go b/libcontainer/cgroups/fscommon/utils_test.go index ba18435ee4f..103b9bed225 100644 --- a/libcontainer/cgroups/fscommon/utils_test.go +++ b/libcontainer/cgroups/fscommon/utils_test.go @@ -9,6 +9,8 @@ import ( "path/filepath" "strconv" "testing" + + "github.com/opencontainers/runc/libcontainer/cgroups" ) const ( @@ -18,7 +20,7 @@ const ( ) func init() { - TestMode = true + cgroups.TestMode = true } func TestGetCgroupParamsInt(t *testing.T) { diff --git a/libcontainer/cgroups/utils.go b/libcontainer/cgroups/utils.go index 35de12dd81c..92606525b4d 100644 --- a/libcontainer/cgroups/utils.go +++ b/libcontainer/cgroups/utils.go @@ -15,7 +15,6 @@ import ( "sync" "time" - "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" "github.com/opencontainers/runc/libcontainer/userns" "github.com/sirupsen/logrus" "golang.org/x/sys/unix" @@ -88,7 +87,7 @@ func GetAllSubsystems() ([]string, error) { // - freezer: implemented in kernel 5.2 // We assume these are always available, as it is hard to detect availability. pseudo := []string{"devices", "freezer"} - data, err := fscommon.ReadFile("/sys/fs/cgroup", "cgroup.controllers") + data, err := ReadFile("/sys/fs/cgroup", "cgroup.controllers") if err != nil { return nil, err } @@ -375,7 +374,7 @@ func WriteCgroupProc(dir string, pid int) error { return nil } - file, err := fscommon.OpenFile(dir, CgroupProcesses, os.O_WRONLY) + file, err := OpenFile(dir, CgroupProcesses, os.O_WRONLY) if err != nil { return fmt.Errorf("failed to write %v to %v: %v", pid, CgroupProcesses, err) }