From 0eb31124e7f789b8b688434f09ae6e87003b7dc8 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Tue, 3 Nov 2020 15:15:30 -0800 Subject: [PATCH] libct/cg/sd/v2: support cpu.max unified resource Signed-off-by: Kir Kolyshkin --- libcontainer/cgroups/systemd/v2.go | 32 +++++++++++++++++++++++++++--- tests/integration/cgroups.bats | 10 +++++++++- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/libcontainer/cgroups/systemd/v2.go b/libcontainer/cgroups/systemd/v2.go index 49e491f2ebe..fd5d0d1e163 100644 --- a/libcontainer/cgroups/systemd/v2.go +++ b/libcontainer/cgroups/systemd/v2.go @@ -45,7 +45,9 @@ func NewUnifiedManager(config *configs.Cgroup, path string, rootless bool) cgrou // For the list of keys, see https://www.kernel.org/doc/Documentation/cgroup-v2.txt // // For the list of systemd unit properties, see systemd.resource-control(5). -func unifiedResToSystemdProps(res map[string]string) (props []systemdDbus.Property, _ error) { +func unifiedResToSystemdProps(conn *systemdDbus.Conn, res map[string]string) (props []systemdDbus.Property, _ error) { + var err error + for k, v := range res { if strings.Contains(k, "/") { return nil, fmt.Errorf("unified resource %q must be a file name (no slashes)", k) @@ -54,11 +56,35 @@ func unifiedResToSystemdProps(res map[string]string) (props []systemdDbus.Proper if len(sk) != 2 { return nil, fmt.Errorf("unified resource %q must be in the form CONTROLLER.PARAMETER", k) } + // Please keep cases in alphabetical order. switch k { + case "cpu.max": + // value: quota [period] + quota := int64(0) // 0 means "unlimited" if period is set + period := defCPUQuotaPeriod + sv := strings.SplitN(v, " ", 3) + if len(sv) > 2 { + return nil, fmt.Errorf("unified resource %q value invalid: %q", k, v) + } + // quota + if sv[0] != "max" { + quota, err = strconv.ParseInt(v, 10, 64) + if err != nil { + return nil, fmt.Errorf("unified resource %q value conversion error: %w", k, err) + } + } + // period + if len(sv) == 2 { + period, err = strconv.ParseUint(v, 10, 64) + if err != nil { + return nil, fmt.Errorf("unified resource %q value conversion error: %w", k, err) + } + } + addCpuQuota(conn, &props, quota, period) + case "pids.max": num := uint64(math.MaxUint64) if v != "max" { - var err error num, err = strconv.ParseUint(v, 10, 64) if err != nil { return nil, fmt.Errorf("unified resource %q value conversion error: %w", k, err) @@ -127,7 +153,7 @@ func genV2ResourcesProperties(c *configs.Cgroup, conn *systemdDbus.Conn) ([]syst // convert Resources.Unified map to systemd properties if r.Unified != nil { - unifiedProps, err := unifiedResToSystemdProps(r.Unified) + unifiedProps, err := unifiedResToSystemdProps(conn, r.Unified) if err != nil { return nil, err } diff --git a/tests/integration/cgroups.bats b/tests/integration/cgroups.bats index cc6852ef2b8..99cb7c5942b 100644 --- a/tests/integration/cgroups.bats +++ b/tests/integration/cgroups.bats @@ -218,6 +218,7 @@ function setup() { echo "$output" | grep -q '^cpu.max:10000 100000$' check_systemd_value "TasksMax" 99 + check_cpu_quota 10000 100000 "100ms" } @test "runc run (cgroup v2 resources.unified override)" { @@ -227,10 +228,15 @@ function setup() { update_config ' .linux.resources.memory |= { "limit": 33554432 } | .linux.resources.memorySwap |= { "limit": 33554432 } | .linux.resources.pids |= { "limit": 20 } + | .linux.resources.cpu |= { + "quota": 40000, + "period": 100000 + } | .linux.resources.unified |= { "memory.min": "131072", "memory.max": "10485760", - "pids.max": "42" + "pids.max": "42", + "cpu.max": "5000 50000" }' "$BUSYBOX_BUNDLE" runc run -d --console-socket "$CONSOLE_SOCKET" test_cgroups_unified @@ -247,5 +253,7 @@ function setup() { runc exec test_cgroups_unified cat /sys/fs/cgroup/pids.max [ "$status" -eq 0 ] [ "$output" = '42' ] + check_systemd_value "TasksMax" 42 + check_cpu_quota 5000 50000 "100ms" }