Skip to content

Commit 6581114

Browse files
committed
libct: make MaxCPU exclusive
MaxCPU was documented and enforced as the highest CPU/NUMA node ID that ToCPUSet accepts, i.e. an inclusive bound, while unix.NewCPUSet takes an exclusive one. As a result, tryResetCPUAffinity's NewCPUSet(MaxCPU) mask was one ID short of what ToCPUSet can parse. This is harmless in practice, as sched_setaffinity(2) truncates the mask to cpumask_size() anyway, and no kernel is configured with anywhere near 64K CPUs. Still, having a single constant mean two different things in two different files is asking for a real off-by-one later on. Make MaxCPU exclusive to match NewCPUSet, so that NewCPUSet(MaxCPU) is correct as written, and ToCPUSet's NewCPUSet(maxID+1) can never exceed it. This restores the "ret >= max" check and the "max-1" wording used before MaxCPU was introduced, and shifts the test boundary cases by one. Fixes: daf934f ("libct: use CPUSetDynamic for affinity and mempolicy masks") Fixes: c55649b ("libct: reuse configs.MaxCPU") Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
1 parent f1a7e38 commit 6581114

2 files changed

Lines changed: 11 additions & 9 deletions

File tree

libcontainer/configs/config.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -307,9 +307,10 @@ type CPUAffinity struct {
307307
Initial, Final unix.CPUSetDynamic
308308
}
309309

310-
// MaxCPU is the highest CPU/NUMA node ID that [ToCPUSet] accepts.
311-
// It is an arbitrary sanity limit, used to avoid allocating
312-
// an unreasonably large mask for a bogus input.
310+
// MaxCPU is one past the highest CPU/NUMA node ID that [ToCPUSet] accepts,
311+
// i.e. the number of CPUs/nodes a mask can represent. It is an arbitrary
312+
// sanity limit, used to avoid allocating an unreasonably large mask for a
313+
// bogus input. It is exclusive, to match [unix.NewCPUSet].
313314
const MaxCPU = 64 * 1024
314315

315316
// ToCPUSet parses a string in list format (e.g. "0-3,5,7-9")
@@ -349,8 +350,8 @@ func cpuStrToRanges(str string) (maxID int, ranges []cpuRange, _ error) {
349350
if err != nil {
350351
return 0, err
351352
}
352-
if ret > MaxCPU {
353-
return 0, fmt.Errorf("values larger than %d are not supported", MaxCPU)
353+
if ret >= MaxCPU {
354+
return 0, fmt.Errorf("values larger than %d are not supported", MaxCPU-1)
354355
}
355356
return int(ret), nil
356357
}

libcontainer/configs/tocpuset_test.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,10 @@ func TestToCPUSet(t *testing.T) {
5959
{in: "1024", out: set(1024)},
6060
{in: "8191", out: set(8191)},
6161
{in: "4096-4098", out: set(4096, 4097, 4098)},
62-
{in: "0,65536", out: set(0, 65536)},
62+
{in: "0,65534", out: set(0, 65534)},
6363
// Maximum allowed value.
64-
{in: "65536", out: set(65536)},
64+
{in: "65535", out: set(65535)},
65+
{in: "65532-65535", out: set(65532, 65533, 65534, 65535)},
6566

6667
// Error cases.
6768
{in: "-", isErr: true},
@@ -74,8 +75,8 @@ func TestToCPUSet(t *testing.T) {
7475
// Extra spaces inside a range is not OK.
7576
{in: "1 - 2", isErr: true},
7677
// Larger than the maximum supported value.
77-
{in: "65537", isErr: true},
78-
{in: "0-65537", isErr: true},
78+
{in: "65536", isErr: true},
79+
{in: "0-65536", isErr: true},
7980
}
8081

8182
for _, tc := range testCases {

0 commit comments

Comments
 (0)