Revert "Merge pull request 101888 from kolyshkin/update-runc-rc94"

This reverts commit b1b06fe0a4, reversing
changes made to 382a33986b.
This commit is contained in:
Jordan Liggitt
2021-05-18 09:12:04 -04:00
parent 7ccd90e7d7
commit 4b45d0d921
336 changed files with 5393 additions and 17166 deletions

View File

@@ -12,14 +12,15 @@ import (
"github.com/opencontainers/runc/libcontainer/configs"
)
func isCpuSet(r *configs.Resources) bool {
return r.CpuWeight != 0 || r.CpuQuota != 0 || r.CpuPeriod != 0
func isCpuSet(cgroup *configs.Cgroup) bool {
return cgroup.Resources.CpuWeight != 0 || cgroup.Resources.CpuQuota != 0 || cgroup.Resources.CpuPeriod != 0
}
func setCpu(dirPath string, r *configs.Resources) error {
if !isCpuSet(r) {
func setCpu(dirPath string, cgroup *configs.Cgroup) error {
if !isCpuSet(cgroup) {
return nil
}
r := cgroup.Resources
// NOTE: .CpuShares is not used here. Conversion is the caller's responsibility.
if r.CpuWeight != 0 {
@@ -56,7 +57,7 @@ func statCpu(dirPath string, stats *cgroups.Stats) error {
sc := bufio.NewScanner(f)
for sc.Scan() {
t, v, err := fscommon.ParseKeyValue(sc.Text())
t, v, err := fscommon.GetCgroupParamKeyValue(sc.Text())
if err != nil {
return err
}
@@ -69,15 +70,6 @@ func statCpu(dirPath string, stats *cgroups.Stats) error {
case "system_usec":
stats.CpuStats.CpuUsage.UsageInKernelmode = v * 1000
case "nr_periods":
stats.CpuStats.ThrottlingData.Periods = v
case "nr_throttled":
stats.CpuStats.ThrottlingData.ThrottledPeriods = v
case "throttled_usec":
stats.CpuStats.ThrottlingData.ThrottledTime = v * 1000
}
}
return nil

View File

@@ -7,22 +7,22 @@ import (
"github.com/opencontainers/runc/libcontainer/configs"
)
func isCpusetSet(r *configs.Resources) bool {
return r.CpusetCpus != "" || r.CpusetMems != ""
func isCpusetSet(cgroup *configs.Cgroup) bool {
return cgroup.Resources.CpusetCpus != "" || cgroup.Resources.CpusetMems != ""
}
func setCpuset(dirPath string, r *configs.Resources) error {
if !isCpusetSet(r) {
func setCpuset(dirPath string, cgroup *configs.Cgroup) error {
if !isCpusetSet(cgroup) {
return nil
}
if r.CpusetCpus != "" {
if err := fscommon.WriteFile(dirPath, "cpuset.cpus", r.CpusetCpus); err != nil {
if cgroup.Resources.CpusetCpus != "" {
if err := fscommon.WriteFile(dirPath, "cpuset.cpus", cgroup.Resources.CpusetCpus); err != nil {
return err
}
}
if r.CpusetMems != "" {
if err := fscommon.WriteFile(dirPath, "cpuset.mems", r.CpusetMems); err != nil {
if cgroup.Resources.CpusetMems != "" {
if err := fscommon.WriteFile(dirPath, "cpuset.mems", cgroup.Resources.CpusetMems); err != nil {
return err
}
}

View File

@@ -10,7 +10,7 @@ import (
"github.com/opencontainers/runc/libcontainer/configs"
)
func supportedControllers() (string, error) {
func supportedControllers(cgroup *configs.Cgroup) (string, error) {
return fscommon.ReadFile(UnifiedMountpoint, "/cgroup.controllers")
}
@@ -18,13 +18,13 @@ func supportedControllers() (string, error) {
// based on (1) controllers available and (2) resources that are being set.
// We don't check "pseudo" controllers such as
// "freezer" and "devices".
func needAnyControllers(r *configs.Resources) (bool, error) {
if r == nil {
func needAnyControllers(cgroup *configs.Cgroup) (bool, error) {
if cgroup == nil {
return false, nil
}
// list of all available controllers
content, err := supportedControllers()
content, err := supportedControllers(cgroup)
if err != nil {
return false, err
}
@@ -39,22 +39,22 @@ func needAnyControllers(r *configs.Resources) (bool, error) {
return ok
}
if isPidsSet(r) && have("pids") {
if isPidsSet(cgroup) && have("pids") {
return true, nil
}
if isMemorySet(r) && have("memory") {
if isMemorySet(cgroup) && have("memory") {
return true, nil
}
if isIoSet(r) && have("io") {
if isIoSet(cgroup) && have("io") {
return true, nil
}
if isCpuSet(r) && have("cpu") {
if isCpuSet(cgroup) && have("cpu") {
return true, nil
}
if isCpusetSet(r) && have("cpuset") {
if isCpusetSet(cgroup) && have("cpuset") {
return true, nil
}
if isHugeTlbSet(r) && have("hugetlb") {
if isHugeTlbSet(cgroup) && have("hugetlb") {
return true, nil
}
@@ -64,8 +64,8 @@ func needAnyControllers(r *configs.Resources) (bool, error) {
// containsDomainController returns whether the current config contains domain controller or not.
// Refer to: http://man7.org/linux/man-pages/man7/cgroups.7.html
// As at Linux 4.19, the following controllers are threaded: cpu, perf_event, and pids.
func containsDomainController(r *configs.Resources) bool {
return isMemorySet(r) || isIoSet(r) || isCpuSet(r) || isHugeTlbSet(r)
func containsDomainController(cg *configs.Cgroup) bool {
return isMemorySet(cg) || isIoSet(cg) || isCpuSet(cg) || isHugeTlbSet(cg)
}
// CreateCgroupPath creates cgroupv2 path, enabling all the supported controllers.
@@ -74,7 +74,7 @@ func CreateCgroupPath(path string, c *configs.Cgroup) (Err error) {
return fmt.Errorf("invalid cgroup path %s", path)
}
content, err := supportedControllers()
content, err := supportedControllers(c)
if err != nil {
return err
}
@@ -115,7 +115,7 @@ func CreateCgroupPath(path string, c *configs.Cgroup) (Err error) {
// the controllers requested are thread-aware we can simply put the cgroup into
// threaded mode.
case "domain invalid":
if containsDomainController(c.Resources) {
if containsDomainController(c) {
return fmt.Errorf("cannot enter cgroupv2 %q with domain controllers -- it is in an invalid state", current)
} else {
// Not entirely correct (in theory we'd always want to be a domain --
@@ -129,7 +129,7 @@ func CreateCgroupPath(path string, c *configs.Cgroup) (Err error) {
case "domain threaded":
fallthrough
case "threaded":
if containsDomainController(c.Resources) {
if containsDomainController(c) {
return fmt.Errorf("cannot enter cgroupv2 %q with domain controllers -- it is in %s mode", current, cgType)
}
}

View File

@@ -7,8 +7,6 @@ import (
"github.com/opencontainers/runc/libcontainer/cgroups/ebpf/devicefilter"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runc/libcontainer/devices"
"github.com/opencontainers/runc/libcontainer/userns"
"github.com/pkg/errors"
"golang.org/x/sys/unix"
)
@@ -28,40 +26,26 @@ func isRWM(perms devices.Permissions) bool {
return r && w && m
}
// This is similar to the logic applied in crun for handling errors from bpf(2)
// <https://github.com/containers/crun/blob/0.17/src/libcrun/cgroup.c#L2438-L2470>.
func canSkipEBPFError(r *configs.Resources) bool {
// If we're running in a user namespace we can ignore eBPF rules because we
// usually cannot use bpf(2), as well as rootless containers usually don't
// have the necessary privileges to mknod(2) device inodes or access
// host-level instances (though ideally we would be blocking device access
// for rootless containers anyway).
if userns.RunningInUserNS() {
return true
}
// We cannot ignore an eBPF load error if any rule if is a block rule or it
// doesn't permit all access modes.
//
// NOTE: This will sometimes trigger in cases where access modes are split
// between different rules but to handle this correctly would require
// using ".../libcontainer/cgroup/devices".Emulator.
for _, dev := range r.Devices {
if !dev.Allow || !isRWM(dev.Permissions) {
// the logic is from crun
// https://github.com/containers/crun/blob/0.10.2/src/libcrun/cgroup.c#L1644-L1652
func canSkipEBPFError(cgroup *configs.Cgroup) bool {
for _, dev := range cgroup.Resources.Devices {
if dev.Allow || !isRWM(dev.Permissions) {
return false
}
}
return true
}
func setDevices(dirPath string, r *configs.Resources) error {
if r.SkipDevices {
func setDevices(dirPath string, cgroup *configs.Cgroup) error {
if cgroup.SkipDevices {
return nil
}
// XXX: This is currently a white-list (but all callers pass a blacklist of
// devices). This is bad for a whole variety of reasons, but will need
// to be fixed with co-ordinated effort with downstreams.
insts, license, err := devicefilter.DeviceFilter(r.Devices)
devices := cgroup.Devices
insts, license, err := devicefilter.DeviceFilter(devices)
if err != nil {
return err
}
@@ -82,7 +66,7 @@ func setDevices(dirPath string, r *configs.Resources) error {
// programs. You could temporarily insert a deny-everything program
// but that would result in spurrious failures during updates.
if _, err := ebpf.LoadAttachCgroupDeviceFilter(insts, license, dirFD); err != nil {
if !canSkipEBPFError(r) {
if !canSkipEBPFError(cgroup) {
return err
}
}

View File

@@ -75,7 +75,7 @@ func (m *manager) Apply(pid int) error {
// - "runc create (rootless + limits + no cgrouppath + no permission) fails with informative error"
if m.rootless {
if m.config.Path == "" {
if blNeed, nErr := needAnyControllers(m.config.Resources); nErr == nil && !blNeed {
if blNeed, nErr := needAnyControllers(m.config); nErr == nil && !blNeed {
return nil
}
return errors.Wrap(err, "rootless needs no limits + no cgrouppath when no permission is granted for cgroups")
@@ -103,27 +103,43 @@ func (m *manager) GetStats() (*cgroups.Stats, error) {
)
st := cgroups.NewStats()
if err := m.getControllers(); err != nil {
return st, err
}
// pids (since kernel 4.5)
if err := statPids(m.dirPath, st); err != nil {
errs = append(errs, err)
if _, ok := m.controllers["pids"]; ok {
if err := statPids(m.dirPath, st); err != nil {
errs = append(errs, err)
}
} else {
if err := statPidsWithoutController(m.dirPath, st); err != nil {
errs = append(errs, err)
}
}
// memory (since kernel 4.5)
if err := statMemory(m.dirPath, st); err != nil && !os.IsNotExist(err) {
errs = append(errs, err)
if _, ok := m.controllers["memory"]; ok {
if err := statMemory(m.dirPath, st); err != nil {
errs = append(errs, err)
}
}
// io (since kernel 4.5)
if err := statIo(m.dirPath, st); err != nil && !os.IsNotExist(err) {
errs = append(errs, err)
if _, ok := m.controllers["io"]; ok {
if err := statIo(m.dirPath, st); err != nil {
errs = append(errs, err)
}
}
// cpu (since kernel 4.15)
// Note cpu.stat is available even if the controller is not enabled.
if err := statCpu(m.dirPath, st); err != nil && !os.IsNotExist(err) {
errs = append(errs, err)
if _, ok := m.controllers["cpu"]; ok {
if err := statCpu(m.dirPath, st); err != nil {
errs = append(errs, err)
}
}
// hugetlb (since kernel 5.6)
if err := statHugeTlb(m.dirPath, st); err != nil && !os.IsNotExist(err) {
errs = append(errs, err)
if _, ok := m.controllers["hugetlb"]; ok {
if err := statHugeTlb(m.dirPath, st); err != nil {
errs = append(errs, err)
}
}
if len(errs) > 0 && !m.rootless {
return st, errors.Errorf("error while statting cgroup v2: %+v", errs)
@@ -147,50 +163,53 @@ func (m *manager) Path(_ string) string {
return m.dirPath
}
func (m *manager) Set(r *configs.Resources) error {
func (m *manager) Set(container *configs.Config) error {
if container == nil || container.Cgroups == nil {
return nil
}
if err := m.getControllers(); err != nil {
return err
}
// pids (since kernel 4.5)
if err := setPids(m.dirPath, r); err != nil {
if err := setPids(m.dirPath, container.Cgroups); err != nil {
return err
}
// memory (since kernel 4.5)
if err := setMemory(m.dirPath, r); err != nil {
if err := setMemory(m.dirPath, container.Cgroups); err != nil {
return err
}
// io (since kernel 4.5)
if err := setIo(m.dirPath, r); err != nil {
if err := setIo(m.dirPath, container.Cgroups); err != nil {
return err
}
// cpu (since kernel 4.15)
if err := setCpu(m.dirPath, r); err != nil {
if err := setCpu(m.dirPath, container.Cgroups); err != nil {
return err
}
// devices (since kernel 4.15, pseudo-controller)
//
// When m.rootless is true, errors from the device subsystem are ignored because it is really not expected to work.
// When m.Rootless is true, errors from the device subsystem are ignored because it is really not expected to work.
// However, errors from other subsystems are not ignored.
// see @test "runc create (rootless + limits + no cgrouppath + no permission) fails with informative error"
if err := setDevices(m.dirPath, r); err != nil && !m.rootless {
if err := setDevices(m.dirPath, container.Cgroups); err != nil && !m.rootless {
return err
}
// cpuset (since kernel 5.0)
if err := setCpuset(m.dirPath, r); err != nil {
if err := setCpuset(m.dirPath, container.Cgroups); err != nil {
return err
}
// hugetlb (since kernel 5.6)
if err := setHugeTlb(m.dirPath, r); err != nil {
if err := setHugeTlb(m.dirPath, container.Cgroups); err != nil {
return err
}
// freezer (since kernel 5.2, pseudo-controller)
if err := setFreezer(m.dirPath, r.Freezer); err != nil {
if err := setFreezer(m.dirPath, container.Cgroups.Freezer); err != nil {
return err
}
if err := m.setUnified(r.Unified); err != nil {
if err := m.setUnified(container.Cgroups.Unified); err != nil {
return err
}
m.config.Resources = r
m.config = container.Cgroups
return nil
}
@@ -238,16 +257,3 @@ func (m *manager) GetFreezerState() (configs.FreezerState, error) {
func (m *manager) Exists() bool {
return cgroups.PathExists(m.dirPath)
}
func OOMKillCount(path string) (uint64, error) {
return fscommon.GetValueByKey(path, "memory.events", "oom_kill")
}
func (m *manager) OOMKillCount() (uint64, error) {
c, err := OOMKillCount(m.dirPath)
if err != nil && m.rootless && os.IsNotExist(err) {
err = nil
}
return c, err
}

View File

@@ -12,15 +12,15 @@ import (
"github.com/opencontainers/runc/libcontainer/configs"
)
func isHugeTlbSet(r *configs.Resources) bool {
return len(r.HugetlbLimit) > 0
func isHugeTlbSet(cgroup *configs.Cgroup) bool {
return len(cgroup.Resources.HugetlbLimit) > 0
}
func setHugeTlb(dirPath string, r *configs.Resources) error {
if !isHugeTlbSet(r) {
func setHugeTlb(dirPath string, cgroup *configs.Cgroup) error {
if !isHugeTlbSet(cgroup) {
return nil
}
for _, hugetlb := range r.HugetlbLimit {
for _, hugetlb := range cgroup.Resources.HugetlbLimit {
if err := fscommon.WriteFile(dirPath, "hugetlb."+hugetlb.Pagesize+".max", strconv.FormatUint(hugetlb.Limit, 10)); err != nil {
return err
}
@@ -44,10 +44,14 @@ func statHugeTlb(dirPath string, stats *cgroups.Stats) error {
hugetlbStats.Usage = value
fileName := "hugetlb." + pagesize + ".events"
value, err = fscommon.GetValueByKey(dirPath, fileName, "max")
contents, err := fscommon.ReadFile(dirPath, fileName)
if err != nil {
return errors.Wrap(err, "failed to read stats")
}
_, value, err = fscommon.GetCgroupParamKeyValue(contents)
if err != nil {
return errors.Wrap(err, "failed to parse "+fileName)
}
hugetlbStats.Failcnt = value
stats.HugetlbStats[pagesize] = hugetlbStats

View File

@@ -13,50 +13,42 @@ import (
"github.com/opencontainers/runc/libcontainer/configs"
)
func isIoSet(r *configs.Resources) bool {
return r.BlkioWeight != 0 ||
len(r.BlkioThrottleReadBpsDevice) > 0 ||
len(r.BlkioThrottleWriteBpsDevice) > 0 ||
len(r.BlkioThrottleReadIOPSDevice) > 0 ||
len(r.BlkioThrottleWriteIOPSDevice) > 0
func isIoSet(cgroup *configs.Cgroup) bool {
return cgroup.Resources.BlkioWeight != 0 ||
len(cgroup.Resources.BlkioThrottleReadBpsDevice) > 0 ||
len(cgroup.Resources.BlkioThrottleWriteBpsDevice) > 0 ||
len(cgroup.Resources.BlkioThrottleReadIOPSDevice) > 0 ||
len(cgroup.Resources.BlkioThrottleWriteIOPSDevice) > 0
}
func setIo(dirPath string, r *configs.Resources) error {
if !isIoSet(r) {
func setIo(dirPath string, cgroup *configs.Cgroup) error {
if !isIoSet(cgroup) {
return nil
}
if r.BlkioWeight != 0 {
if cgroup.Resources.BlkioWeight != 0 {
filename := "io.bfq.weight"
if err := fscommon.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
if !os.IsNotExist(err) {
return err
}
v := cgroups.ConvertBlkIOToIOWeightValue(r.BlkioWeight)
if err := fscommon.WriteFile(dirPath, "io.weight", strconv.FormatUint(v, 10)); err != nil {
return err
}
strconv.FormatUint(cgroups.ConvertBlkIOToCgroupV2Value(cgroup.Resources.BlkioWeight), 10)); err != nil {
return err
}
}
for _, td := range r.BlkioThrottleReadBpsDevice {
for _, td := range cgroup.Resources.BlkioThrottleReadBpsDevice {
if err := fscommon.WriteFile(dirPath, "io.max", td.StringName("rbps")); err != nil {
return err
}
}
for _, td := range r.BlkioThrottleWriteBpsDevice {
for _, td := range cgroup.Resources.BlkioThrottleWriteBpsDevice {
if err := fscommon.WriteFile(dirPath, "io.max", td.StringName("wbps")); err != nil {
return err
}
}
for _, td := range r.BlkioThrottleReadIOPSDevice {
for _, td := range cgroup.Resources.BlkioThrottleReadIOPSDevice {
if err := fscommon.WriteFile(dirPath, "io.max", td.StringName("riops")); err != nil {
return err
}
}
for _, td := range r.BlkioThrottleWriteIOPSDevice {
for _, td := range cgroup.Resources.BlkioThrottleWriteIOPSDevice {
if err := fscommon.WriteFile(dirPath, "io.max", td.StringName("wiops")); err != nil {
return err
}

View File

@@ -4,16 +4,13 @@ package fs2
import (
"bufio"
"math"
"os"
"strconv"
"strings"
"github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/pkg/errors"
"golang.org/x/sys/unix"
)
// numToStr converts an int64 value to a string for writing to a
@@ -33,20 +30,21 @@ func numToStr(value int64) (ret string) {
return ret
}
func isMemorySet(r *configs.Resources) bool {
return r.MemoryReservation != 0 || r.Memory != 0 || r.MemorySwap != 0
func isMemorySet(cgroup *configs.Cgroup) bool {
return cgroup.Resources.MemoryReservation != 0 ||
cgroup.Resources.Memory != 0 || cgroup.Resources.MemorySwap != 0
}
func setMemory(dirPath string, r *configs.Resources) error {
if !isMemorySet(r) {
func setMemory(dirPath string, cgroup *configs.Cgroup) error {
if !isMemorySet(cgroup) {
return nil
}
swap, err := cgroups.ConvertMemorySwapToCgroupV2Value(r.MemorySwap, r.Memory)
swap, err := cgroups.ConvertMemorySwapToCgroupV2Value(cgroup.Resources.MemorySwap, cgroup.Resources.Memory)
if err != nil {
return err
}
swapStr := numToStr(swap)
if swapStr == "" && swap == 0 && r.MemorySwap > 0 {
if swapStr == "" && swap == 0 && cgroup.Resources.MemorySwap > 0 {
// memory and memorySwap set to the same value -- disable swap
swapStr = "0"
}
@@ -57,7 +55,7 @@ func setMemory(dirPath string, r *configs.Resources) error {
}
}
if val := numToStr(r.Memory); val != "" {
if val := numToStr(cgroup.Resources.Memory); val != "" {
if err := fscommon.WriteFile(dirPath, "memory.max", val); err != nil {
return err
}
@@ -65,7 +63,7 @@ func setMemory(dirPath string, r *configs.Resources) error {
// cgroup.Resources.KernelMemory is ignored
if val := numToStr(r.MemoryReservation); val != "" {
if val := numToStr(cgroup.Resources.MemoryReservation); val != "" {
if err := fscommon.WriteFile(dirPath, "memory.low", val); err != nil {
return err
}
@@ -84,24 +82,16 @@ func statMemory(dirPath string, stats *cgroups.Stats) error {
sc := bufio.NewScanner(statsFile)
for sc.Scan() {
t, v, err := fscommon.ParseKeyValue(sc.Text())
t, v, err := fscommon.GetCgroupParamKeyValue(sc.Text())
if err != nil {
return errors.Wrapf(err, "failed to parse memory.stat (%q)", sc.Text())
}
stats.MemoryStats.Stats[t] = v
}
stats.MemoryStats.Cache = stats.MemoryStats.Stats["file"]
// Unlike cgroup v1 which has memory.use_hierarchy binary knob,
// cgroup v2 is always hierarchical.
stats.MemoryStats.UseHierarchy = true
stats.MemoryStats.Cache = stats.MemoryStats.Stats["cache"]
memoryUsage, err := getMemoryDataV2(dirPath, "")
if err != nil {
if errors.Is(err, unix.ENOENT) && dirPath == UnifiedMountpoint {
// The root cgroup does not have memory.{current,max}
// so emulate those using data from /proc/meminfo.
return statsFromMeminfo(stats)
}
return err
}
stats.MemoryStats.Usage = memoryUsage
@@ -109,15 +99,9 @@ func statMemory(dirPath string, stats *cgroups.Stats) error {
if err != nil {
return err
}
// As cgroup v1 reports SwapUsage values as mem+swap combined,
// while in cgroup v2 swap values do not include memory,
// report combined mem+swap for v1 compatibility.
swapUsage.Usage += memoryUsage.Usage
if swapUsage.Limit != math.MaxUint64 {
swapUsage.Limit += memoryUsage.Limit
}
stats.MemoryStats.SwapUsage = swapUsage
stats.MemoryStats.UseHierarchy = true
return nil
}
@@ -133,10 +117,7 @@ func getMemoryDataV2(path, name string) (cgroups.MemoryData, error) {
value, err := fscommon.GetCgroupParamUint(path, usage)
if err != nil {
if name != "" && os.IsNotExist(err) {
// Ignore EEXIST as there's no swap accounting
// if kernel CONFIG_MEMCG_SWAP is not set or
// swapaccount=0 kernel boot parameter is given.
if moduleName != "memory" && os.IsNotExist(err) {
return cgroups.MemoryData{}, nil
}
return cgroups.MemoryData{}, errors.Wrapf(err, "failed to parse %s", usage)
@@ -145,69 +126,12 @@ func getMemoryDataV2(path, name string) (cgroups.MemoryData, error) {
value, err = fscommon.GetCgroupParamUint(path, limit)
if err != nil {
if moduleName != "memory" && os.IsNotExist(err) {
return cgroups.MemoryData{}, nil
}
return cgroups.MemoryData{}, errors.Wrapf(err, "failed to parse %s", limit)
}
memoryData.Limit = value
return memoryData, nil
}
func statsFromMeminfo(stats *cgroups.Stats) error {
f, err := os.Open("/proc/meminfo")
if err != nil {
return err
}
defer f.Close()
// Fields we are interested in.
var (
swap_free uint64
swap_total uint64
main_total uint64
main_free uint64
)
mem := map[string]*uint64{
"SwapFree": &swap_free,
"SwapTotal": &swap_total,
"MemTotal": &main_total,
"MemFree": &main_free,
}
found := 0
sc := bufio.NewScanner(f)
for sc.Scan() {
parts := strings.SplitN(sc.Text(), ":", 3)
if len(parts) != 2 {
// Should not happen.
continue
}
k := parts[0]
p, ok := mem[k]
if !ok {
// Unknown field -- not interested.
continue
}
vStr := strings.TrimSpace(strings.TrimSuffix(parts[1], " kB"))
*p, err = strconv.ParseUint(vStr, 10, 64)
if err != nil {
return errors.Wrap(err, "parsing /proc/meminfo "+k)
}
found++
if found == len(mem) {
// Got everything we need -- skip the rest.
break
}
}
if sc.Err() != nil {
return sc.Err()
}
stats.MemoryStats.SwapUsage.Usage = (swap_total - swap_free) * 1024
stats.MemoryStats.SwapUsage.Limit = math.MaxUint64
stats.MemoryStats.Usage.Usage = (main_total - main_free) * 1024
stats.MemoryStats.Usage.Limit = math.MaxUint64
return nil
}

View File

@@ -3,7 +3,6 @@
package fs2
import (
"os"
"path/filepath"
"strings"
@@ -14,15 +13,15 @@ import (
"golang.org/x/sys/unix"
)
func isPidsSet(r *configs.Resources) bool {
return r.PidsLimit != 0
func isPidsSet(cgroup *configs.Cgroup) bool {
return cgroup.Resources.PidsLimit != 0
}
func setPids(dirPath string, r *configs.Resources) error {
if !isPidsSet(r) {
func setPids(dirPath string, cgroup *configs.Cgroup) error {
if !isPidsSet(cgroup) {
return nil
}
if val := numToStr(r.PidsLimit); val != "" {
if val := numToStr(cgroup.Resources.PidsLimit); val != "" {
if err := fscommon.WriteFile(dirPath, "pids.max", val); err != nil {
return err
}
@@ -31,7 +30,7 @@ func setPids(dirPath string, r *configs.Resources) error {
return nil
}
func statPidsFromCgroupProcs(dirPath string, stats *cgroups.Stats) error {
func statPidsWithoutController(dirPath string, stats *cgroups.Stats) error {
// if the controller is not enabled, let's read PIDS from cgroups.procs
// (or threads if cgroup.threads is enabled)
contents, err := fscommon.ReadFile(dirPath, "cgroup.procs")
@@ -41,8 +40,13 @@ func statPidsFromCgroupProcs(dirPath string, stats *cgroups.Stats) error {
if err != nil {
return err
}
pids := strings.Count(contents, "\n")
stats.PidsStats.Current = uint64(pids)
pids := make(map[string]string)
for _, i := range strings.Split(contents, "\n") {
if i != "" {
pids[i] = i
}
}
stats.PidsStats.Current = uint64(len(pids))
stats.PidsStats.Limit = 0
return nil
}
@@ -50,9 +54,6 @@ func statPidsFromCgroupProcs(dirPath string, stats *cgroups.Stats) error {
func statPids(dirPath string, stats *cgroups.Stats) error {
current, err := fscommon.GetCgroupParamUint(dirPath, "pids.current")
if err != nil {
if os.IsNotExist(err) {
return statPidsFromCgroupProcs(dirPath, stats)
}
return errors.Wrap(err, "failed to parse pids.current")
}