Rework cpu affinity parsing
The CPU_SET_S api is pretty bad. In particular, it has a parameter for the size
of the array, but operations which take two (CPU_EQUAL_S) or even three arrays
(CPU_{AND,OR,XOR}_S) still take just one size. This means that all arrays must
be of the same size, or buffer overruns will occur. This is exactly what our
code would do, if it received an array of unexpected size over the network.
("Unexpected" here means anything different from what cpu_set_malloc() detects
as the "right" size.)
Let's rework this, and store the size in bytes of the allocated storage area.
The code will now parse any number up to 8191, independently of what the current
kernel supports. This matches the kernel maximum setting for any architecture,
to make things more portable.
Fixes #12605.
This commit is contained in:
@@ -5,150 +5,165 @@
|
||||
#include "macro.h"
|
||||
|
||||
static void test_parse_cpu_set(void) {
|
||||
cpu_set_t *c = NULL;
|
||||
CPUSet c = {};
|
||||
_cleanup_free_ char *str = NULL;
|
||||
int ncpus;
|
||||
int cpu;
|
||||
|
||||
/* Simple range (from CPUAffinity example) */
|
||||
ncpus = parse_cpu_set_and_warn("1 2", &c, NULL, "fake", 1, "CPUAffinity");
|
||||
assert_se(ncpus >= 1024);
|
||||
assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c));
|
||||
assert_se(CPU_ISSET_S(2, CPU_ALLOC_SIZE(ncpus), c));
|
||||
assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 2);
|
||||
assert_se(parse_cpu_set_full("1 2", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
|
||||
assert_se(c.set);
|
||||
assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
|
||||
assert_se(CPU_ISSET_S(1, c.allocated, c.set));
|
||||
assert_se(CPU_ISSET_S(2, c.allocated, c.set));
|
||||
assert_se(CPU_COUNT_S(c.allocated, c.set) == 2);
|
||||
|
||||
assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
|
||||
assert_se(str = cpu_set_to_string(&c));
|
||||
log_info("cpu_set_to_string: %s", str);
|
||||
str = mfree(str);
|
||||
c = cpu_set_mfree(c);
|
||||
cpu_set_reset(&c);
|
||||
|
||||
/* A more interesting range */
|
||||
ncpus = parse_cpu_set_and_warn("0 1 2 3 8 9 10 11", &c, NULL, "fake", 1, "CPUAffinity");
|
||||
assert_se(ncpus >= 1024);
|
||||
assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
|
||||
assert_se(parse_cpu_set_full("0 1 2 3 8 9 10 11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
|
||||
assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
|
||||
assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
|
||||
for (cpu = 0; cpu < 4; cpu++)
|
||||
assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
|
||||
assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
|
||||
for (cpu = 8; cpu < 12; cpu++)
|
||||
assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
|
||||
assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
|
||||
assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
|
||||
assert_se(str = cpu_set_to_string(&c));
|
||||
log_info("cpu_set_to_string: %s", str);
|
||||
str = mfree(str);
|
||||
c = cpu_set_mfree(c);
|
||||
cpu_set_reset(&c);
|
||||
|
||||
/* Quoted strings */
|
||||
ncpus = parse_cpu_set_and_warn("8 '9' 10 \"11\"", &c, NULL, "fake", 1, "CPUAffinity");
|
||||
assert_se(ncpus >= 1024);
|
||||
assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 4);
|
||||
assert_se(parse_cpu_set_full("8 '9' 10 \"11\"", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
|
||||
assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
|
||||
assert_se(CPU_COUNT_S(c.allocated, c.set) == 4);
|
||||
for (cpu = 8; cpu < 12; cpu++)
|
||||
assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
|
||||
assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
|
||||
assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
|
||||
assert_se(str = cpu_set_to_string(&c));
|
||||
log_info("cpu_set_to_string: %s", str);
|
||||
str = mfree(str);
|
||||
c = cpu_set_mfree(c);
|
||||
cpu_set_reset(&c);
|
||||
|
||||
/* Use commas as separators */
|
||||
ncpus = parse_cpu_set_and_warn("0,1,2,3 8,9,10,11", &c, NULL, "fake", 1, "CPUAffinity");
|
||||
assert_se(ncpus >= 1024);
|
||||
assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
|
||||
assert_se(parse_cpu_set_full("0,1,2,3 8,9,10,11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
|
||||
assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
|
||||
assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
|
||||
for (cpu = 0; cpu < 4; cpu++)
|
||||
assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
|
||||
assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
|
||||
for (cpu = 8; cpu < 12; cpu++)
|
||||
assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
|
||||
assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
|
||||
assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
|
||||
assert_se(str = cpu_set_to_string(&c));
|
||||
log_info("cpu_set_to_string: %s", str);
|
||||
str = mfree(str);
|
||||
c = cpu_set_mfree(c);
|
||||
cpu_set_reset(&c);
|
||||
|
||||
/* Commas with spaces (and trailing comma, space) */
|
||||
ncpus = parse_cpu_set_and_warn("0, 1, 2, 3, 4, 5, 6, 7, ", &c, NULL, "fake", 1, "CPUAffinity");
|
||||
assert_se(ncpus >= 1024);
|
||||
assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
|
||||
assert_se(parse_cpu_set_full("0, 1, 2, 3, 4, 5, 6, 7, ", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
|
||||
assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
|
||||
assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
|
||||
for (cpu = 0; cpu < 8; cpu++)
|
||||
assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
|
||||
assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
|
||||
assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
|
||||
assert_se(str = cpu_set_to_string(&c));
|
||||
log_info("cpu_set_to_string: %s", str);
|
||||
str = mfree(str);
|
||||
c = cpu_set_mfree(c);
|
||||
cpu_set_reset(&c);
|
||||
|
||||
/* Ranges */
|
||||
ncpus = parse_cpu_set_and_warn("0-3,8-11", &c, NULL, "fake", 1, "CPUAffinity");
|
||||
assert_se(ncpus >= 1024);
|
||||
assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
|
||||
assert_se(parse_cpu_set_full("0-3,8-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
|
||||
assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
|
||||
assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
|
||||
for (cpu = 0; cpu < 4; cpu++)
|
||||
assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
|
||||
assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
|
||||
for (cpu = 8; cpu < 12; cpu++)
|
||||
assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
|
||||
assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
|
||||
assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
|
||||
assert_se(str = cpu_set_to_string(&c));
|
||||
log_info("cpu_set_to_string: %s", str);
|
||||
str = mfree(str);
|
||||
c = cpu_set_mfree(c);
|
||||
cpu_set_reset(&c);
|
||||
|
||||
/* Ranges with trailing comma, space */
|
||||
ncpus = parse_cpu_set_and_warn("0-3 8-11, ", &c, NULL, "fake", 1, "CPUAffinity");
|
||||
assert_se(ncpus >= 1024);
|
||||
assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
|
||||
assert_se(parse_cpu_set_full("0-3 8-11, ", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
|
||||
assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
|
||||
assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
|
||||
for (cpu = 0; cpu < 4; cpu++)
|
||||
assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
|
||||
assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
|
||||
for (cpu = 8; cpu < 12; cpu++)
|
||||
assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
|
||||
assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
|
||||
assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
|
||||
assert_se(str = cpu_set_to_string(&c));
|
||||
log_info("cpu_set_to_string: %s", str);
|
||||
str = mfree(str);
|
||||
c = cpu_set_mfree(c);
|
||||
cpu_set_reset(&c);
|
||||
|
||||
/* Negative range (returns empty cpu_set) */
|
||||
ncpus = parse_cpu_set_and_warn("3-0", &c, NULL, "fake", 1, "CPUAffinity");
|
||||
assert_se(ncpus >= 1024);
|
||||
assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 0);
|
||||
c = cpu_set_mfree(c);
|
||||
assert_se(parse_cpu_set_full("3-0", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
|
||||
assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
|
||||
assert_se(CPU_COUNT_S(c.allocated, c.set) == 0);
|
||||
cpu_set_reset(&c);
|
||||
|
||||
/* Overlapping ranges */
|
||||
ncpus = parse_cpu_set_and_warn("0-7 4-11", &c, NULL, "fake", 1, "CPUAffinity");
|
||||
assert_se(ncpus >= 1024);
|
||||
assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 12);
|
||||
assert_se(parse_cpu_set_full("0-7 4-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
|
||||
assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
|
||||
assert_se(CPU_COUNT_S(c.allocated, c.set) == 12);
|
||||
for (cpu = 0; cpu < 12; cpu++)
|
||||
assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
|
||||
assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
|
||||
assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
|
||||
assert_se(str = cpu_set_to_string(&c));
|
||||
log_info("cpu_set_to_string: %s", str);
|
||||
str = mfree(str);
|
||||
c = cpu_set_mfree(c);
|
||||
cpu_set_reset(&c);
|
||||
|
||||
/* Mix ranges and individual CPUs */
|
||||
ncpus = parse_cpu_set_and_warn("0,1 4-11", &c, NULL, "fake", 1, "CPUAffinity");
|
||||
assert_se(ncpus >= 1024);
|
||||
assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 10);
|
||||
assert_se(CPU_ISSET_S(0, CPU_ALLOC_SIZE(ncpus), c));
|
||||
assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c));
|
||||
assert_se(parse_cpu_set_full("0,1 4-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
|
||||
assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
|
||||
assert_se(CPU_COUNT_S(c.allocated, c.set) == 10);
|
||||
assert_se(CPU_ISSET_S(0, c.allocated, c.set));
|
||||
assert_se(CPU_ISSET_S(1, c.allocated, c.set));
|
||||
for (cpu = 4; cpu < 12; cpu++)
|
||||
assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
|
||||
assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
|
||||
assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
|
||||
assert_se(str = cpu_set_to_string(&c));
|
||||
log_info("cpu_set_to_string: %s", str);
|
||||
str = mfree(str);
|
||||
c = cpu_set_mfree(c);
|
||||
cpu_set_reset(&c);
|
||||
|
||||
/* Garbage */
|
||||
ncpus = parse_cpu_set_and_warn("0 1 2 3 garbage", &c, NULL, "fake", 1, "CPUAffinity");
|
||||
assert_se(ncpus < 0);
|
||||
assert_se(!c);
|
||||
assert_se(parse_cpu_set_full("0 1 2 3 garbage", &c, true, NULL, "fake", 1, "CPUAffinity") == -EINVAL);
|
||||
assert_se(!c.set);
|
||||
assert_se(c.allocated == 0);
|
||||
|
||||
/* Range with garbage */
|
||||
ncpus = parse_cpu_set_and_warn("0-3 8-garbage", &c, NULL, "fake", 1, "CPUAffinity");
|
||||
assert_se(ncpus < 0);
|
||||
assert_se(!c);
|
||||
assert_se(parse_cpu_set_full("0-3 8-garbage", &c, true, NULL, "fake", 1, "CPUAffinity") == -EINVAL);
|
||||
assert_se(!c.set);
|
||||
assert_se(c.allocated == 0);
|
||||
|
||||
/* Empty string */
|
||||
c = NULL;
|
||||
ncpus = parse_cpu_set_and_warn("", &c, NULL, "fake", 1, "CPUAffinity");
|
||||
assert_se(ncpus == 0); /* empty string returns 0 */
|
||||
assert_se(!c);
|
||||
assert_se(parse_cpu_set_full("", &c, true, NULL, "fake", 1, "CPUAffinity") == 0);
|
||||
assert_se(!c.set); /* empty string returns NULL */
|
||||
assert_se(c.allocated == 0);
|
||||
|
||||
/* Runaway quoted string */
|
||||
ncpus = parse_cpu_set_and_warn("0 1 2 3 \"4 5 6 7 ", &c, NULL, "fake", 1, "CPUAffinity");
|
||||
assert_se(ncpus < 0);
|
||||
assert_se(!c);
|
||||
assert_se(parse_cpu_set_full("0 1 2 3 \"4 5 6 7 ", &c, true, NULL, "fake", 1, "CPUAffinity") == -EINVAL);
|
||||
assert_se(!c.set);
|
||||
assert_se(c.allocated == 0);
|
||||
|
||||
/* Maximum allocation */
|
||||
assert_se(parse_cpu_set_full("8000-8191", &c, true, NULL, "fake", 1, "CPUAffinity") == 0);
|
||||
assert_se(CPU_COUNT_S(c.allocated, c.set) == 192);
|
||||
assert_se(str = cpu_set_to_string(&c));
|
||||
log_info("cpu_set_to_string: %s", str);
|
||||
str = mfree(str);
|
||||
cpu_set_reset(&c);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
log_info("CPU_ALLOC_SIZE(1) = %zu", CPU_ALLOC_SIZE(1));
|
||||
log_info("CPU_ALLOC_SIZE(9) = %zu", CPU_ALLOC_SIZE(9));
|
||||
log_info("CPU_ALLOC_SIZE(64) = %zu", CPU_ALLOC_SIZE(64));
|
||||
log_info("CPU_ALLOC_SIZE(65) = %zu", CPU_ALLOC_SIZE(65));
|
||||
log_info("CPU_ALLOC_SIZE(1024) = %zu", CPU_ALLOC_SIZE(1024));
|
||||
log_info("CPU_ALLOC_SIZE(1025) = %zu", CPU_ALLOC_SIZE(1025));
|
||||
log_info("CPU_ALLOC_SIZE(8191) = %zu", CPU_ALLOC_SIZE(8191));
|
||||
|
||||
test_parse_cpu_set();
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
|
||||
#include <sched.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -65,6 +66,8 @@ int main(void) {
|
||||
info(uid_t);
|
||||
info(gid_t);
|
||||
|
||||
info(__cpu_mask);
|
||||
|
||||
info(enum Enum);
|
||||
info(enum BigEnum);
|
||||
info(enum BigEnum2);
|
||||
|
||||
Reference in New Issue
Block a user