From 03b512e511c587dd77047d0bf826c541672dbd60 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Fri, 8 Jan 2021 12:22:53 -0800 Subject: [PATCH] libc/cg: convert r.CPU.Cpus/Mems to systemd props Support for systemd properties AllowedCPUs and AllowedMemoryNodes was added by commit 13afa58d0e46ceb0, but only for unified resources of systemd v2 driver. This adds support for Cpu.Cpus and Cpu.Mems resources to both systemd v1 and v2 cgroup drivers. An integration test is added to check that the settings work. [v2: check for systemd version] [v3: same in the test] Signed-off-by: Kir Kolyshkin --- libcontainer/cgroups/systemd/common.go | 32 +++++++++++++++ libcontainer/cgroups/systemd/v1.go | 5 +++ libcontainer/cgroups/systemd/v2.go | 5 +++ tests/integration/update.bats | 56 ++++++++++++++++++++++++++ 4 files changed, 98 insertions(+) diff --git a/libcontainer/cgroups/systemd/common.go b/libcontainer/cgroups/systemd/common.go index 7df198caa..61f2d69f0 100644 --- a/libcontainer/cgroups/systemd/common.go +++ b/libcontainer/cgroups/systemd/common.go @@ -432,3 +432,35 @@ func addCpuQuota(conn *systemdDbus.Conn, properties *[]systemdDbus.Property, quo newProp("CPUQuotaPerSecUSec", cpuQuotaPerSecUSec)) } } + +func addCpuset(conn *systemdDbus.Conn, props *[]systemdDbus.Property, cpus, mems string) error { + if cpus == "" && mems == "" { + return nil + } + + // systemd only supports AllowedCPUs/AllowedMemoryNodes since v244 + sdVer := systemdVersion(conn) + if sdVer < 244 { + return nil + } + + if cpus != "" { + bits, err := rangeToBits(cpus) + if err != nil { + return fmt.Errorf("resources.CPU.Cpus=%q conversion error: %w", + cpus, err) + } + *props = append(*props, + newProp("AllowedCPUs", bits)) + } + if mems != "" { + bits, err := rangeToBits(mems) + if err != nil { + return fmt.Errorf("resources.CPU.Mems=%q conversion error: %w", + mems, err) + } + *props = append(*props, + newProp("AllowedMemoryNodes", bits)) + } + return nil +} diff --git a/libcontainer/cgroups/systemd/v1.go b/libcontainer/cgroups/systemd/v1.go index 2679b9993..64af1d94b 100644 --- a/libcontainer/cgroups/systemd/v1.go +++ b/libcontainer/cgroups/systemd/v1.go @@ -90,6 +90,11 @@ func genV1ResourcesProperties(c *configs.Cgroup, conn *systemdDbus.Conn) ([]syst newProp("TasksMax", uint64(r.PidsLimit))) } + err = addCpuset(conn, &properties, r.CpusetCpus, r.CpusetMems) + if err != nil { + return nil, err + } + return properties, nil } diff --git a/libcontainer/cgroups/systemd/v2.go b/libcontainer/cgroups/systemd/v2.go index 5691b43df..782e4b5b4 100644 --- a/libcontainer/cgroups/systemd/v2.go +++ b/libcontainer/cgroups/systemd/v2.go @@ -201,6 +201,11 @@ func genV2ResourcesProperties(c *configs.Cgroup, conn *systemdDbus.Conn) ([]syst newProp("TasksMax", uint64(r.PidsLimit))) } + err = addCpuset(conn, &properties, r.CpusetCpus, r.CpusetMems) + if err != nil { + return nil, err + } + // ignore r.KernelMemory // convert Resources.Unified map to systemd properties diff --git a/tests/integration/update.bats b/tests/integration/update.bats index 908ce0ccb..c03e7c6de 100644 --- a/tests/integration/update.bats +++ b/tests/integration/update.bats @@ -392,7 +392,63 @@ EOF check_systemd_value "TasksMax" 10 } +@test "update cpuset parameters via resources.CPU" { + [[ "$ROOTLESS" -ne 0 ]] && requires rootless_cgroup + requires smp + + local AllowedCPUs='AllowedCPUs' AllowedMemoryNodes='AllowedMemoryNodes' + # these properties require systemd >= v244 + if [ "$(systemd_version)" -lt 244 ]; then + # a hack to skip checks, see check_systemd_value() + AllowedCPUs='unsupported' + AllowedMemoryNodes='unsupported' + fi + + update_config ' .linux.resources.CPU |= { + "Cpus": "0", + "Mems": "0" + }' "${BUSYBOX_BUNDLE}" + runc run -d --console-socket "$CONSOLE_SOCKET" test_update + [ "$status" -eq 0 ] + + # check that initial values were properly set + check_systemd_value "$AllowedCPUs" 0 + check_systemd_value "$AllowedMemoryNodes" 0 + + runc update -r - test_update <= v244 [[ "$ROOTLESS" -ne 0 ]] && requires rootless_cgroup requires cgroups_v2 smp