From 98a85454ed3f2f4aa7b506e3c6444ab633fea9c6 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Fri, 11 Jun 2021 13:31:19 -0700 Subject: [PATCH] libct/cg: mv fscommon.{Open,Read,Write}File to cgroups This is a better place as cgroups itself is using these. Should help with moving more stuff common in between fs and fs2 to fscommon. Looks big, but this is just moving the code around: fscommon/{fscommon,open}.go -> cgroups/file.go fscommon/fscommon_test.go -> cgroups/file_test.go There's no functional change. Signed-off-by: Kir Kolyshkin --- .../cgroups/{fscommon/open.go => file.go} | 56 +++++++++++++++++-- .../fscommon_test.go => file_test.go} | 2 +- libcontainer/cgroups/fs/blkio.go | 19 +++---- libcontainer/cgroups/fs/cpu.go | 12 ++-- libcontainer/cgroups/fs/cpuacct.go | 6 +- libcontainer/cgroups/fs/cpuset.go | 12 ++-- libcontainer/cgroups/fs/devices.go | 5 +- libcontainer/cgroups/fs/freezer.go | 13 ++--- libcontainer/cgroups/fs/hugetlb.go | 2 +- libcontainer/cgroups/fs/memory.go | 14 ++--- libcontainer/cgroups/fs/net_cls.go | 3 +- libcontainer/cgroups/fs/net_prio.go | 3 +- libcontainer/cgroups/fs/pids.go | 2 +- libcontainer/cgroups/fs/util_test.go | 2 +- libcontainer/cgroups/fs2/cpu.go | 6 +- libcontainer/cgroups/fs2/cpuset.go | 6 +- libcontainer/cgroups/fs2/create.go | 12 ++-- libcontainer/cgroups/fs2/freezer.go | 8 +-- libcontainer/cgroups/fs2/fs2.go | 4 +- libcontainer/cgroups/fs2/hugetlb.go | 2 +- libcontainer/cgroups/fs2/io.go | 15 +++-- libcontainer/cgroups/fs2/memory.go | 8 +-- libcontainer/cgroups/fs2/pids.go | 6 +- libcontainer/cgroups/fscommon/fscommon.go | 51 ----------------- libcontainer/cgroups/fscommon/utils.go | 8 ++- libcontainer/cgroups/utils.go | 5 +- 26 files changed, 136 insertions(+), 146 deletions(-) rename libcontainer/cgroups/{fscommon/open.go => file.go} (72%) rename libcontainer/cgroups/{fscommon/fscommon_test.go => file_test.go} (98%) delete mode 100644 libcontainer/cgroups/fscommon/fscommon.go 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/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..9ec9886c4f3 100644 --- a/libcontainer/cgroups/fs/util_test.go +++ b/libcontainer/cgroups/fs/util_test.go @@ -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/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/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) }