You've already forked runc
mirror of
https://github.com/opencontainers/runc.git
synced 2025-07-30 17:43:06 +03:00
1. Instead of enabling all available controllers, figure out which ones are required, and only enable those. 2. Amend all setFoo() functions to call isFooSet(). While this might seem unnecessary, it might actually help to uncover a bug. Imagine someone: - adds a cgroup.Resources.CpuFoo setting; - modifies setCpu() to apply the new setting; - but forgets to amend isCpuSet() accordingly <-- BUG In this case, a test case modifying CpuFoo will help to uncover the BUG. This is the reason why it's added. This patch *could be* amended by enabling controllers on a best-effort basis, i.e. : - do not return an error early if we can't enable some controllers; - if we fail to enable all controllers at once (usually because one of them can't be enabled), try enabling them one by one. Currently this is not implemented, and it's not clear whether this would be a good way to go or not. [v2: add/use is${Controller}Set() functions] [v3: document neededControllers()] [v4: drop "best-effort" part] Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
137 lines
3.2 KiB
Go
137 lines
3.2 KiB
Go
// +build linux
|
|
|
|
package fs2
|
|
|
|
import (
|
|
"bufio"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/opencontainers/runc/libcontainer/cgroups"
|
|
"github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
|
|
"github.com/opencontainers/runc/libcontainer/configs"
|
|
)
|
|
|
|
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, cgroup *configs.Cgroup) error {
|
|
if !isIoSet(cgroup) {
|
|
return nil
|
|
}
|
|
|
|
if cgroup.Resources.BlkioWeight != 0 {
|
|
filename := "io.bfq.weight"
|
|
if err := fscommon.WriteFile(dirPath, filename,
|
|
strconv.FormatUint(cgroups.ConvertBlkIOToCgroupV2Value(cgroup.Resources.BlkioWeight), 10)); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
for _, td := range cgroup.Resources.BlkioThrottleReadBpsDevice {
|
|
if err := fscommon.WriteFile(dirPath, "io.max", td.StringName("rbps")); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
for _, td := range cgroup.Resources.BlkioThrottleWriteBpsDevice {
|
|
if err := fscommon.WriteFile(dirPath, "io.max", td.StringName("wbps")); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
for _, td := range cgroup.Resources.BlkioThrottleReadIOPSDevice {
|
|
if err := fscommon.WriteFile(dirPath, "io.max", td.StringName("riops")); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
for _, td := range cgroup.Resources.BlkioThrottleWriteIOPSDevice {
|
|
if err := fscommon.WriteFile(dirPath, "io.max", td.StringName("wiops")); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func readCgroup2MapFile(dirPath string, name string) (map[string][]string, error) {
|
|
ret := map[string][]string{}
|
|
p := filepath.Join(dirPath, name)
|
|
f, err := os.Open(p)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer f.Close()
|
|
scanner := bufio.NewScanner(f)
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
parts := strings.Fields(line)
|
|
if len(parts) < 2 {
|
|
continue
|
|
}
|
|
ret[parts[0]] = parts[1:]
|
|
}
|
|
if err := scanner.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return ret, nil
|
|
}
|
|
|
|
func statIo(dirPath string, stats *cgroups.Stats) error {
|
|
// more details on the io.stat file format: https://www.kernel.org/doc/Documentation/cgroup-v2.txt
|
|
var ioServiceBytesRecursive []cgroups.BlkioStatEntry
|
|
values, err := readCgroup2MapFile(dirPath, "io.stat")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for k, v := range values {
|
|
d := strings.Split(k, ":")
|
|
if len(d) != 2 {
|
|
continue
|
|
}
|
|
major, err := strconv.ParseUint(d[0], 10, 0)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
minor, err := strconv.ParseUint(d[1], 10, 0)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, item := range v {
|
|
d := strings.Split(item, "=")
|
|
if len(d) != 2 {
|
|
continue
|
|
}
|
|
op := d[0]
|
|
|
|
// Accommodate the cgroup v1 naming
|
|
switch op {
|
|
case "rbytes":
|
|
op = "read"
|
|
case "wbytes":
|
|
op = "write"
|
|
}
|
|
|
|
value, err := strconv.ParseUint(d[1], 10, 0)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
entry := cgroups.BlkioStatEntry{
|
|
Op: op,
|
|
Major: major,
|
|
Minor: minor,
|
|
Value: value,
|
|
}
|
|
ioServiceBytesRecursive = append(ioServiceBytesRecursive, entry)
|
|
}
|
|
}
|
|
stats.BlkioStats = cgroups.BlkioStats{IoServiceBytesRecursive: ioServiceBytesRecursive}
|
|
return nil
|
|
}
|