Skip to content

Commit d63a212

Browse files
mmmmaedattyono
authored andcommitted
cgroups: fix incorrect cgroups cpuset via systemd
Signed-off-by: Yuta Maeda <[email protected]> Signed-off-by: Tatsuya Ono <[email protected]>
1 parent 7c29729 commit d63a212

File tree

2 files changed

+90
-7
lines changed

2 files changed

+90
-7
lines changed

pkg/cgroups/cgroups_linux_test.go

+22-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
package cgroups
44

55
import (
6+
"bytes"
67
"fmt"
8+
"math/big"
79
"os"
810
"os/exec"
911
"strconv"
@@ -87,7 +89,7 @@ func TestResources(t *testing.T) {
8789
}
8890

8991
// test CPU Quota adjustment.
90-
u, _, _, _, _ := resourcesToProps(&resources, true)
92+
u, _, b, _, _, _ := resourcesToProps(&resources, true)
9193

9294
val, ok := u["CPUQuotaPerSecUSec"]
9395
if !ok {
@@ -97,6 +99,25 @@ func TestResources(t *testing.T) {
9799
t.Fatal("CPU Quota incorrect value expected 1000000 got " + strconv.FormatUint(val, 10))
98100
}
99101

102+
bits := new(big.Int)
103+
cpuset_val := bits.SetBit(bits, 0, 1).Bytes()
104+
105+
cpus, ok := b["AllowedCPUs"]
106+
if !ok {
107+
t.Fatal("Cpuset Cpus not parsed.")
108+
}
109+
if !bytes.Equal(cpus, cpuset_val) {
110+
t.Fatal("Cpuset Cpus incorrect value expected " + string(cpuset_val) + " got " + string(cpus))
111+
}
112+
113+
mems, ok := b["AllowedMemoryNodes"]
114+
if !ok {
115+
t.Fatal("Cpuset Mems not parsed.")
116+
}
117+
if !bytes.Equal(mems, cpuset_val) {
118+
t.Fatal("Cpuset Mems incorrect value expected " + string(cpuset_val) + " got " + string(mems))
119+
}
120+
100121
err = os.Mkdir("/dev/foodevdir", os.ModePerm)
101122
if err != nil {
102123
t.Fatal(err)

pkg/cgroups/systemd_linux.go

+68-6
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@ package cgroups
44

55
import (
66
"context"
7+
"errors"
78
"fmt"
9+
"math/big"
810
"path/filepath"
11+
"slices"
12+
"strconv"
913
"strings"
1014

1115
systemdDbus "github.com/coreos/go-systemd/v22/dbus"
@@ -53,7 +57,11 @@ func systemdCreate(resources *configs.Resources, path string, c *systemdDbus.Con
5357
properties = append(properties, p)
5458
}
5559

56-
uMap, sMap, bMap, iMap, structMap := resourcesToProps(resources, v2)
60+
uMap, sMap, bMap, iMap, structMap, err := resourcesToProps(resources, v2)
61+
if err != nil {
62+
lastError = err
63+
continue
64+
}
5765
for k, v := range uMap {
5866
p := systemdDbus.Property{
5967
Name: k,
@@ -95,7 +103,7 @@ func systemdCreate(resources *configs.Resources, path string, c *systemdDbus.Con
95103
}
96104

97105
ch := make(chan string)
98-
_, err := c.StartTransientUnitContext(context.TODO(), name, "replace", properties, ch)
106+
_, err = c.StartTransientUnitContext(context.TODO(), name, "replace", properties, ch)
99107
if err != nil {
100108
lastError = err
101109
continue
@@ -142,7 +150,7 @@ func systemdDestroyConn(path string, c *systemdDbus.Conn) error {
142150
return nil
143151
}
144152

145-
func resourcesToProps(res *configs.Resources, v2 bool) (map[string]uint64, map[string]string, map[string][]byte, map[string]int64, map[string][]BlkioDev) {
153+
func resourcesToProps(res *configs.Resources, v2 bool) (map[string]uint64, map[string]string, map[string][]byte, map[string]int64, map[string][]BlkioDev, error) {
146154
bMap := make(map[string][]byte)
147155
// this array is not used but will be once more resource limits are added
148156
sMap := make(map[string]string)
@@ -179,11 +187,19 @@ func resourcesToProps(res *configs.Resources, v2 bool) (map[string]uint64, map[s
179187

180188
// CPUSet
181189
if res.CpusetCpus != "" {
182-
bits := []byte(res.CpusetCpus)
190+
bits, err := rangeToBits(res.CpusetCpus)
191+
if err != nil {
192+
return nil, nil, nil, nil, nil, fmt.Errorf("resources.CpusetCpus=%q conversion error: %w",
193+
res.CpusetCpus, err)
194+
}
183195
bMap["AllowedCPUs"] = bits
184196
}
185197
if res.CpusetMems != "" {
186-
bits := []byte(res.CpusetMems)
198+
bits, err := rangeToBits(res.CpusetMems)
199+
if err != nil {
200+
return nil, nil, nil, nil, nil, fmt.Errorf("resources.CpusetMems=%q conversion error: %w",
201+
res.CpusetMems, err)
202+
}
187203
bMap["AllowedMemoryNodes"] = bits
188204
}
189205

@@ -258,5 +274,51 @@ func resourcesToProps(res *configs.Resources, v2 bool) (map[string]uint64, map[s
258274
}
259275
}
260276

261-
return uMap, sMap, bMap, iMap, structMap
277+
return uMap, sMap, bMap, iMap, structMap, nil
278+
}
279+
280+
func rangeToBits(str string) ([]byte, error) {
281+
bits := new(big.Int)
282+
283+
for _, r := range strings.Split(str, ",") {
284+
// allow extra spaces around
285+
r = strings.TrimSpace(r)
286+
// allow empty elements (extra commas)
287+
if r == "" {
288+
continue
289+
}
290+
startr, endr, ok := strings.Cut(r, "-")
291+
if ok {
292+
start, err := strconv.ParseUint(startr, 10, 32)
293+
if err != nil {
294+
return nil, err
295+
}
296+
end, err := strconv.ParseUint(endr, 10, 32)
297+
if err != nil {
298+
return nil, err
299+
}
300+
if start > end {
301+
return nil, errors.New("invalid range: " + r)
302+
}
303+
for i := start; i <= end; i++ {
304+
bits.SetBit(bits, int(i), 1)
305+
}
306+
} else {
307+
val, err := strconv.ParseUint(startr, 10, 32)
308+
if err != nil {
309+
return nil, err
310+
}
311+
bits.SetBit(bits, int(val), 1)
312+
}
313+
}
314+
315+
ret := bits.Bytes()
316+
if len(ret) == 0 {
317+
// do not allow empty values
318+
return nil, errors.New("empty value")
319+
}
320+
321+
// fit cpuset parsing order in systemd
322+
slices.Reverse(ret)
323+
return ret, nil
262324
}

0 commit comments

Comments
 (0)