mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 14:13:58 +08:00
77cae9addc
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 <seyeong.kim@canonical.com>
Signed-off-by: Chengen, Du <chengen.du@canonical.com>
61 lines
1.4 KiB
Go
61 lines
1.4 KiB
Go
package systemd
|
|
|
|
import (
|
|
"errors"
|
|
"math/big"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// RangeToBits converts a text representation of a CPU mask (as written to
|
|
// or read from cgroups' cpuset.* files, e.g. "1,3-5") to a slice of bytes
|
|
// with the corresponding bits set (as consumed by systemd over dbus as
|
|
// AllowedCPUs/AllowedMemoryNodes unit property value).
|
|
func RangeToBits(str string) ([]byte, error) {
|
|
bits := new(big.Int)
|
|
|
|
for _, r := range strings.Split(str, ",") {
|
|
// allow extra spaces around
|
|
r = strings.TrimSpace(r)
|
|
// allow empty elements (extra commas)
|
|
if r == "" {
|
|
continue
|
|
}
|
|
ranges := strings.SplitN(r, "-", 2)
|
|
if len(ranges) > 1 {
|
|
start, err := strconv.ParseUint(ranges[0], 10, 32)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
end, err := strconv.ParseUint(ranges[1], 10, 32)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if start > end {
|
|
return nil, errors.New("invalid range: " + r)
|
|
}
|
|
for i := start; i <= end; i++ {
|
|
bits.SetBit(bits, int(i), 1)
|
|
}
|
|
} else {
|
|
val, err := strconv.ParseUint(ranges[0], 10, 32)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
bits.SetBit(bits, int(val), 1)
|
|
}
|
|
}
|
|
|
|
ret := bits.Bytes()
|
|
if len(ret) == 0 {
|
|
// 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
|
|
}
|