From 77cae9addc0c7c9ef52513b4e46b2e6485e4e469 Mon Sep 17 00:00:00 2001 From: "Chengen, Du" Date: Mon, 26 Sep 2022 14:28:18 +0800 Subject: [PATCH 1/2] cgroups: cpuset: fix byte order while parsing cpuset range to bits Runc parses cpuset range to bits in the case of cgroup v2 + systemd as cgroup driver. The byte order representation differs from systemd expectation, which will set different cpuset range in systemd transient unit if the length of parsed byte array exceeds one. # cat config.json ... "resources": { ... "cpu": { "cpus": "10-23" } }, ... # runc --systemd-cgroup run test # cat /run/systemd/transient/runc-test.scope.d/50-AllowedCPUs.conf # This is a drop-in unit file extension, created via "systemctl set-property" # or an equivalent operation. Do not edit. [Scope] AllowedCPUs=0-7 10-15 The cpuset.cpus in cgroup will also be set to wrong value after reloading systemd manager configuration. # systemctl daemon-reload # cat /sys/fs/cgroup/system.slice/runc-test.scope/cpuset.cpus 0-7,10-15 Signed-off-by: seyeongkim Signed-off-by: Chengen, Du --- libcontainer/cgroups/systemd/cpuset.go | 5 +++++ libcontainer/cgroups/systemd/cpuset_test.go | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/libcontainer/cgroups/systemd/cpuset.go b/libcontainer/cgroups/systemd/cpuset.go index 83d10dd70..dd474cf1b 100644 --- a/libcontainer/cgroups/systemd/cpuset.go +++ b/libcontainer/cgroups/systemd/cpuset.go @@ -51,5 +51,10 @@ func RangeToBits(str string) ([]byte, error) { // do not allow empty values return nil, errors.New("empty value") } + + // fit cpuset parsing order in systemd + for l, r := 0, len(ret)-1; l < r; l, r = l+1, r-1 { + ret[l], ret[r] = ret[r], ret[l] + } return ret, nil } diff --git a/libcontainer/cgroups/systemd/cpuset_test.go b/libcontainer/cgroups/systemd/cpuset_test.go index 3030cba9e..bda31a5be 100644 --- a/libcontainer/cgroups/systemd/cpuset_test.go +++ b/libcontainer/cgroups/systemd/cpuset_test.go @@ -22,13 +22,13 @@ func TestRangeToBits(t *testing.T) { {in: "4-7", out: []byte{0xf0}}, {in: "0-7", out: []byte{0xff}}, {in: "0-15", out: []byte{0xff, 0xff}}, - {in: "16", out: []byte{1, 0, 0}}, - {in: "0-3,32-33", out: []byte{3, 0, 0, 0, 0x0f}}, + {in: "16", out: []byte{0, 0, 1}}, + {in: "0-3,32-33", out: []byte{0x0f, 0, 0, 0, 3}}, // extra spaces and tabs are ok {in: "1, 2, 1-2", out: []byte{6}}, {in: " , 1 , 3 , 5-7, ", out: []byte{0xea}}, // somewhat large values - {in: "128-130,1", out: []byte{7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}}, + {in: "128-130,1", out: []byte{2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7}}, {in: "-", isErr: true}, {in: "1-", isErr: true}, From 4a8750d93aabe2b0e76f2336c256c8aa2b47943e Mon Sep 17 00:00:00 2001 From: "Chengen, Du" Date: Mon, 3 Oct 2022 10:07:08 +0800 Subject: [PATCH 2/2] tests/int: add a "update cpuset cpus range via v2 unified map" test Add a test case for an issue fixed by the previous commit. The env should has more than 8 core CPU to meet the test requirement. Signed-off-by: Chengen, Du --- tests/integration/helpers.bash | 7 +++++++ tests/integration/update.bats | 27 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/tests/integration/helpers.bash b/tests/integration/helpers.bash index ee93c42b4..a9b70ffd8 100644 --- a/tests/integration/helpers.bash +++ b/tests/integration/helpers.bash @@ -457,6 +457,13 @@ function requires() { skip_me=1 fi ;; + more_than_8_core) + local cpus + cpus=$(grep -c '^processor' /proc/cpuinfo) + if [ "$cpus" -le 8 ]; then + skip_me=1 + fi + ;; *) fail "BUG: Invalid requires $var." ;; diff --git a/tests/integration/update.bats b/tests/integration/update.bats index 1937006fd..d24890093 100644 --- a/tests/integration/update.bats +++ b/tests/integration/update.bats @@ -557,6 +557,33 @@ EOF check_systemd_value "AllowedMemoryNodes" 1 } +@test "update cpuset cpus range via v2 unified map" { + # This test assumes systemd >= v244 + [ $EUID -ne 0 ] && requires rootless_cgroup + requires systemd cgroups_v2 more_than_8_core cgroups_cpuset + + update_config ' .linux.resources.unified |= { + "cpuset.cpus": "0-5", + }' + runc run -d --console-socket "$CONSOLE_SOCKET" test_update + [ "$status" -eq 0 ] + + # check that the initial value was properly set + check_systemd_value "AllowedCPUs" "0-5" + + runc update -r - test_update <