Brian Stinson 2593d8
From 61e5aed87f1b82a51c6ea8ccde96805cb63e5b15 Mon Sep 17 00:00:00 2001
Brian Stinson 2593d8
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Brian Stinson 2593d8
Date: Tue, 21 May 2019 08:45:19 +0200
Brian Stinson 2593d8
Subject: [PATCH] Rework cpu affinity parsing
Brian Stinson 2593d8
Brian Stinson 2593d8
The CPU_SET_S api is pretty bad. In particular, it has a parameter for the size
Brian Stinson 2593d8
of the array, but operations which take two (CPU_EQUAL_S) or even three arrays
Brian Stinson 2593d8
(CPU_{AND,OR,XOR}_S) still take just one size. This means that all arrays must
Brian Stinson 2593d8
be of the same size, or buffer overruns will occur. This is exactly what our
Brian Stinson 2593d8
code would do, if it received an array of unexpected size over the network.
Brian Stinson 2593d8
("Unexpected" here means anything different from what cpu_set_malloc() detects
Brian Stinson 2593d8
as the "right" size.)
Brian Stinson 2593d8
Brian Stinson 2593d8
Let's rework this, and store the size in bytes of the allocated storage area.
Brian Stinson 2593d8
Brian Stinson 2593d8
The code will now parse any number up to 8191, independently of what the current
Brian Stinson 2593d8
kernel supports. This matches the kernel maximum setting for any architecture,
Brian Stinson 2593d8
to make things more portable.
Brian Stinson 2593d8
Brian Stinson 2593d8
Fixes #12605.
Brian Stinson 2593d8
Brian Stinson 2593d8
(cherry picked from commit 0985c7c4e22c8dbbea4398cf3453da45ebf63800)
Brian Stinson 2593d8
Brian Stinson 2593d8
Related: #1734787
Brian Stinson 2593d8
---
Brian Stinson 2593d8
 src/basic/cpu-set-util.c     | 133 +++++++++++++++++++++-----
Brian Stinson 2593d8
 src/basic/cpu-set-util.h     |  47 ++++++---
Brian Stinson 2593d8
 src/core/dbus-execute.c      |  35 ++-----
Brian Stinson 2593d8
 src/core/execute.c           |  12 +--
Brian Stinson 2593d8
 src/core/execute.h           |   4 +-
Brian Stinson 2593d8
 src/core/load-fragment.c     |  31 +-----
Brian Stinson 2593d8
 src/core/main.c              |  14 +--
Brian Stinson 2593d8
 src/nspawn/nspawn-settings.c |  33 +------
Brian Stinson 2593d8
 src/nspawn/nspawn-settings.h |   4 +-
Brian Stinson 2593d8
 src/nspawn/nspawn.c          |  29 +++---
Brian Stinson 2593d8
 src/shared/bus-unit-util.c   |   4 +-
Brian Stinson 2593d8
 src/test/test-cpu-set-util.c | 179 +++++++++++++++++++----------------
Brian Stinson 2593d8
 src/test/test-sizeof.c       |   3 +
Brian Stinson 2593d8
 13 files changed, 286 insertions(+), 242 deletions(-)
Brian Stinson 2593d8
Brian Stinson 2593d8
diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c
Brian Stinson 2593d8
index 8f24a2601a..fe440f6381 100644
Brian Stinson 2593d8
--- a/src/basic/cpu-set-util.c
Brian Stinson 2593d8
+++ b/src/basic/cpu-set-util.c
Brian Stinson 2593d8
@@ -15,14 +15,15 @@
Brian Stinson 2593d8
 #include "macro.h"
Brian Stinson 2593d8
 #include "parse-util.h"
Brian Stinson 2593d8
 #include "string-util.h"
Brian Stinson 2593d8
+#include "util.h"
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-char* cpu_set_to_string(const cpu_set_t *set, size_t setsize) {
Brian Stinson 2593d8
+char* cpu_set_to_string(const CPUSet *a) {
Brian Stinson 2593d8
         _cleanup_free_ char *str = NULL;
Brian Stinson 2593d8
         size_t allocated = 0, len = 0;
Brian Stinson 2593d8
         int i, r;
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-        for (i = 0; (size_t) i < setsize * 8; i++) {
Brian Stinson 2593d8
-                if (!CPU_ISSET_S(i, setsize, set))
Brian Stinson 2593d8
+        for (i = 0; (size_t) i < a->allocated * 8; i++) {
Brian Stinson 2593d8
+                if (!CPU_ISSET_S(i, a->allocated, a->set))
Brian Stinson 2593d8
                         continue;
Brian Stinson 2593d8
 
Brian Stinson 2593d8
                 if (!GREEDY_REALLOC(str, allocated, len + 1 + DECIMAL_STR_MAX(int)))
Brian Stinson 2593d8
@@ -65,24 +66,74 @@ cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
Brian Stinson 2593d8
         }
Brian Stinson 2593d8
 }
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-int parse_cpu_set_internal(
Brian Stinson 2593d8
+static int cpu_set_realloc(CPUSet *cpu_set, unsigned ncpus) {
Brian Stinson 2593d8
+        size_t need;
Brian Stinson 2593d8
+
Brian Stinson 2593d8
+        assert(cpu_set);
Brian Stinson 2593d8
+
Brian Stinson 2593d8
+        need = CPU_ALLOC_SIZE(ncpus);
Brian Stinson 2593d8
+        if (need > cpu_set->allocated) {
Brian Stinson 2593d8
+                cpu_set_t *t;
Brian Stinson 2593d8
+
Brian Stinson 2593d8
+                t = realloc(cpu_set->set, need);
Brian Stinson 2593d8
+                if (!t)
Brian Stinson 2593d8
+                        return -ENOMEM;
Brian Stinson 2593d8
+
Brian Stinson 2593d8
+                memzero((uint8_t*) t + cpu_set->allocated, need - cpu_set->allocated);
Brian Stinson 2593d8
+
Brian Stinson 2593d8
+                cpu_set->set = t;
Brian Stinson 2593d8
+                cpu_set->allocated = need;
Brian Stinson 2593d8
+        }
Brian Stinson 2593d8
+
Brian Stinson 2593d8
+        return 0;
Brian Stinson 2593d8
+}
Brian Stinson 2593d8
+
Brian Stinson 2593d8
+static int cpu_set_add(CPUSet *cpu_set, unsigned cpu) {
Brian Stinson 2593d8
+        int r;
Brian Stinson 2593d8
+
Brian Stinson 2593d8
+        if (cpu >= 8192)
Brian Stinson 2593d8
+                /* As of kernel 5.1, CONFIG_NR_CPUS can be set to 8192 on PowerPC */
Brian Stinson 2593d8
+                return -ERANGE;
Brian Stinson 2593d8
+
Brian Stinson 2593d8
+        r = cpu_set_realloc(cpu_set, cpu + 1);
Brian Stinson 2593d8
+        if (r < 0)
Brian Stinson 2593d8
+                return r;
Brian Stinson 2593d8
+
Brian Stinson 2593d8
+        CPU_SET_S(cpu, cpu_set->allocated, cpu_set->set);
Brian Stinson 2593d8
+        return 0;
Brian Stinson 2593d8
+}
Brian Stinson 2593d8
+
Brian Stinson 2593d8
+int cpu_set_add_all(CPUSet *a, const CPUSet *b) {
Brian Stinson 2593d8
+        int r;
Brian Stinson 2593d8
+
Brian Stinson 2593d8
+        /* Do this backwards, so if we fail, we fail before changing anything. */
Brian Stinson 2593d8
+        for (unsigned cpu_p1 = b->allocated * 8; cpu_p1 > 0; cpu_p1--)
Brian Stinson 2593d8
+                if (CPU_ISSET_S(cpu_p1 - 1, b->allocated, b->set)) {
Brian Stinson 2593d8
+                        r = cpu_set_add(a, cpu_p1 - 1);
Brian Stinson 2593d8
+                        if (r < 0)
Brian Stinson 2593d8
+                                return r;
Brian Stinson 2593d8
+                }
Brian Stinson 2593d8
+
Brian Stinson 2593d8
+        return 0;
Brian Stinson 2593d8
+}
Brian Stinson 2593d8
+
Brian Stinson 2593d8
+int parse_cpu_set_full(
Brian Stinson 2593d8
                 const char *rvalue,
Brian Stinson 2593d8
-                cpu_set_t **cpu_set,
Brian Stinson 2593d8
+                CPUSet *cpu_set,
Brian Stinson 2593d8
                 bool warn,
Brian Stinson 2593d8
                 const char *unit,
Brian Stinson 2593d8
                 const char *filename,
Brian Stinson 2593d8
                 unsigned line,
Brian Stinson 2593d8
                 const char *lvalue) {
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-        _cleanup_cpu_free_ cpu_set_t *c = NULL;
Brian Stinson 2593d8
+        _cleanup_(cpu_set_reset) CPUSet c = {};
Brian Stinson 2593d8
         const char *p = rvalue;
Brian Stinson 2593d8
-        unsigned ncpus = 0;
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-        assert(rvalue);
Brian Stinson 2593d8
+        assert(p);
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         for (;;) {
Brian Stinson 2593d8
                 _cleanup_free_ char *word = NULL;
Brian Stinson 2593d8
-                unsigned cpu, cpu_lower, cpu_upper;
Brian Stinson 2593d8
+                unsigned cpu_lower, cpu_upper;
Brian Stinson 2593d8
                 int r;
Brian Stinson 2593d8
 
Brian Stinson 2593d8
                 r = extract_first_word(&p, &word, WHITESPACE ",", EXTRACT_QUOTES);
Brian Stinson 2593d8
@@ -93,31 +144,63 @@ int parse_cpu_set_internal(
Brian Stinson 2593d8
                 if (r == 0)
Brian Stinson 2593d8
                         break;
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-                if (!c) {
Brian Stinson 2593d8
-                        c = cpu_set_malloc(&ncpus);
Brian Stinson 2593d8
-                        if (!c)
Brian Stinson 2593d8
-                                return warn ? log_oom() : -ENOMEM;
Brian Stinson 2593d8
-                }
Brian Stinson 2593d8
-
Brian Stinson 2593d8
                 r = parse_range(word, &cpu_lower, &cpu_upper);
Brian Stinson 2593d8
                 if (r < 0)
Brian Stinson 2593d8
                         return warn ? log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU affinity '%s'", word) : r;
Brian Stinson 2593d8
-                if (cpu_lower >= ncpus || cpu_upper >= ncpus)
Brian Stinson 2593d8
-                        return warn ? log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU out of range '%s' ncpus is %u", word, ncpus) : -EINVAL;
Brian Stinson 2593d8
 
Brian Stinson 2593d8
                 if (cpu_lower > cpu_upper) {
Brian Stinson 2593d8
                         if (warn)
Brian Stinson 2593d8
-                                log_syntax(unit, LOG_WARNING, filename, line, 0, "Range '%s' is invalid, %u > %u, ignoring", word, cpu_lower, cpu_upper);
Brian Stinson 2593d8
-                        continue;
Brian Stinson 2593d8
+                                log_syntax(unit, LOG_WARNING, filename, line, 0, "Range '%s' is invalid, %u > %u, ignoring.",
Brian Stinson 2593d8
+                                           word, cpu_lower, cpu_upper);
Brian Stinson 2593d8
+
Brian Stinson 2593d8
+                        /* Make sure something is allocated, to distinguish this from the empty case */
Brian Stinson 2593d8
+                        r = cpu_set_realloc(&c, 1);
Brian Stinson 2593d8
+                        if (r < 0)
Brian Stinson 2593d8
+                                return r;
Brian Stinson 2593d8
                 }
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-                for (cpu = cpu_lower; cpu <= cpu_upper; cpu++)
Brian Stinson 2593d8
-                        CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c);
Brian Stinson 2593d8
+                for (unsigned cpu_p1 = MIN(cpu_upper, UINT_MAX-1) + 1; cpu_p1 > cpu_lower; cpu_p1--) {
Brian Stinson 2593d8
+                        r = cpu_set_add(&c, cpu_p1 - 1);
Brian Stinson 2593d8
+                        if (r < 0)
Brian Stinson 2593d8
+                                return warn ? log_syntax(unit, LOG_ERR, filename, line, r,
Brian Stinson 2593d8
+                                                         "Cannot add CPU %u to set: %m", cpu_p1 - 1) : r;
Brian Stinson 2593d8
+                }
Brian Stinson 2593d8
         }
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-        /* On success, sets *cpu_set and returns ncpus for the system. */
Brian Stinson 2593d8
-        if (c)
Brian Stinson 2593d8
-                *cpu_set = TAKE_PTR(c);
Brian Stinson 2593d8
+        /* On success, transfer ownership to the output variable */
Brian Stinson 2593d8
+        *cpu_set = c;
Brian Stinson 2593d8
+        c = (CPUSet) {};
Brian Stinson 2593d8
+
Brian Stinson 2593d8
+        return 0;
Brian Stinson 2593d8
+}
Brian Stinson 2593d8
+
Brian Stinson 2593d8
+int parse_cpu_set_extend(
Brian Stinson 2593d8
+                const char *rvalue,
Brian Stinson 2593d8
+                CPUSet *old,
Brian Stinson 2593d8
+                bool warn,
Brian Stinson 2593d8
+                const char *unit,
Brian Stinson 2593d8
+                const char *filename,
Brian Stinson 2593d8
+                unsigned line,
Brian Stinson 2593d8
+                const char *lvalue) {
Brian Stinson 2593d8
+
Brian Stinson 2593d8
+        _cleanup_(cpu_set_reset) CPUSet cpuset = {};
Brian Stinson 2593d8
+        int r;
Brian Stinson 2593d8
+
Brian Stinson 2593d8
+        r = parse_cpu_set_full(rvalue, &cpuset, true, unit, filename, line, lvalue);
Brian Stinson 2593d8
+        if (r < 0)
Brian Stinson 2593d8
+                return r;
Brian Stinson 2593d8
+
Brian Stinson 2593d8
+        if (!cpuset.set) {
Brian Stinson 2593d8
+                /* An empty assignment resets the CPU list */
Brian Stinson 2593d8
+                cpu_set_reset(old);
Brian Stinson 2593d8
+                return 0;
Brian Stinson 2593d8
+        }
Brian Stinson 2593d8
+
Brian Stinson 2593d8
+        if (!old->set) {
Brian Stinson 2593d8
+                *old = cpuset;
Brian Stinson 2593d8
+                cpuset = (CPUSet) {};
Brian Stinson 2593d8
+                return 0;
Brian Stinson 2593d8
+        }
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-        return (int) ncpus;
Brian Stinson 2593d8
+        return cpu_set_add_all(old, &cpuset);
Brian Stinson 2593d8
 }
Brian Stinson 2593d8
diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h
Brian Stinson 2593d8
index 20612a8876..eb31b362fe 100644
Brian Stinson 2593d8
--- a/src/basic/cpu-set-util.h
Brian Stinson 2593d8
+++ b/src/basic/cpu-set-util.h
Brian Stinson 2593d8
@@ -12,23 +12,40 @@
Brian Stinson 2593d8
 DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE);
Brian Stinson 2593d8
 #define _cleanup_cpu_free_ _cleanup_(CPU_FREEp)
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-static inline cpu_set_t* cpu_set_mfree(cpu_set_t *p) {
Brian Stinson 2593d8
-        if (p)
Brian Stinson 2593d8
-                CPU_FREE(p);
Brian Stinson 2593d8
-        return NULL;
Brian Stinson 2593d8
-}
Brian Stinson 2593d8
-
Brian Stinson 2593d8
 cpu_set_t* cpu_set_malloc(unsigned *ncpus);
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-char* cpu_set_to_string(const cpu_set_t *set, size_t setsize);
Brian Stinson 2593d8
-int parse_cpu_set_internal(const char *rvalue, cpu_set_t **cpu_set, bool warn, const char *unit, const char *filename, unsigned line, const char *lvalue);
Brian Stinson 2593d8
-
Brian Stinson 2593d8
-static inline int parse_cpu_set_and_warn(const char *rvalue, cpu_set_t **cpu_set, const char *unit, const char *filename, unsigned line, const char *lvalue) {
Brian Stinson 2593d8
-        assert(lvalue);
Brian Stinson 2593d8
-
Brian Stinson 2593d8
-        return parse_cpu_set_internal(rvalue, cpu_set, true, unit, filename, line, lvalue);
Brian Stinson 2593d8
+/* This wraps the libc interface with a variable to keep the allocated size. */
Brian Stinson 2593d8
+typedef struct CPUSet {
Brian Stinson 2593d8
+        cpu_set_t *set;
Brian Stinson 2593d8
+        size_t allocated; /* in bytes */
Brian Stinson 2593d8
+} CPUSet;
Brian Stinson 2593d8
+
Brian Stinson 2593d8
+static inline void cpu_set_reset(CPUSet *a) {
Brian Stinson 2593d8
+        assert((a->allocated > 0) == !!a->set);
Brian Stinson 2593d8
+        if (a->set)
Brian Stinson 2593d8
+                CPU_FREE(a->set);
Brian Stinson 2593d8
+        *a = (CPUSet) {};
Brian Stinson 2593d8
 }
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-static inline int parse_cpu_set(const char *rvalue, cpu_set_t **cpu_set){
Brian Stinson 2593d8
-        return parse_cpu_set_internal(rvalue, cpu_set, false, NULL, NULL, 0, NULL);
Brian Stinson 2593d8
+int cpu_set_add_all(CPUSet *a, const CPUSet *b);
Brian Stinson 2593d8
+
Brian Stinson 2593d8
+char* cpu_set_to_string(const CPUSet *a);
Brian Stinson 2593d8
+int parse_cpu_set_full(
Brian Stinson 2593d8
+                const char *rvalue,
Brian Stinson 2593d8
+                CPUSet *cpu_set,
Brian Stinson 2593d8
+                bool warn,
Brian Stinson 2593d8
+                const char *unit,
Brian Stinson 2593d8
+                const char *filename, unsigned line,
Brian Stinson 2593d8
+                const char *lvalue);
Brian Stinson 2593d8
+int parse_cpu_set_extend(
Brian Stinson 2593d8
+                const char *rvalue,
Brian Stinson 2593d8
+                CPUSet *old,
Brian Stinson 2593d8
+                bool warn,
Brian Stinson 2593d8
+                const char *unit,
Brian Stinson 2593d8
+                const char *filename,
Brian Stinson 2593d8
+                unsigned line,
Brian Stinson 2593d8
+                const char *lvalue);
Brian Stinson 2593d8
+
Brian Stinson 2593d8
+static inline int parse_cpu_set(const char *rvalue, CPUSet *cpu_set){
Brian Stinson 2593d8
+        return parse_cpu_set_full(rvalue, cpu_set, false, NULL, NULL, 0, NULL);
Brian Stinson 2593d8
 }
Brian Stinson 2593d8
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
Brian Stinson 2593d8
index d9f4445745..08946627e3 100644
Brian Stinson 2593d8
--- a/src/core/dbus-execute.c
Brian Stinson 2593d8
+++ b/src/core/dbus-execute.c
Brian Stinson 2593d8
@@ -220,7 +220,7 @@ static int property_get_cpu_affinity(
Brian Stinson 2593d8
         assert(reply);
Brian Stinson 2593d8
         assert(c);
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-        return sd_bus_message_append_array(reply, 'y', c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus));
Brian Stinson 2593d8
+        return sd_bus_message_append_array(reply, 'y', c->cpu_set.set, c->cpu_set.allocated);
Brian Stinson 2593d8
 }
Brian Stinson 2593d8
 
Brian Stinson 2593d8
 static int property_get_timer_slack_nsec(
Brian Stinson 2593d8
@@ -1560,37 +1560,22 @@ int bus_exec_context_set_transient_property(
Brian Stinson 2593d8
 
Brian Stinson 2593d8
                 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
Brian Stinson 2593d8
                         if (n == 0) {
Brian Stinson 2593d8
-                                c->cpuset = cpu_set_mfree(c->cpuset);
Brian Stinson 2593d8
-                                c->cpuset_ncpus = 0;
Brian Stinson 2593d8
+                                cpu_set_reset(&c->cpu_set);
Brian Stinson 2593d8
                                 unit_write_settingf(u, flags, name, "%s=", name);
Brian Stinson 2593d8
                         } else {
Brian Stinson 2593d8
                                 _cleanup_free_ char *str = NULL;
Brian Stinson 2593d8
-                                size_t ncpus;
Brian Stinson 2593d8
+                                const CPUSet set = {(cpu_set_t*) a, n};
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-                                str = cpu_set_to_string(a, n);
Brian Stinson 2593d8
+                                str = cpu_set_to_string(&set);
Brian Stinson 2593d8
                                 if (!str)
Brian Stinson 2593d8
                                         return -ENOMEM;
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-                                ncpus = CPU_SIZE_TO_NUM(n);
Brian Stinson 2593d8
-
Brian Stinson 2593d8
-                                if (!c->cpuset || c->cpuset_ncpus < ncpus) {
Brian Stinson 2593d8
-                                        cpu_set_t *cpuset;
Brian Stinson 2593d8
-
Brian Stinson 2593d8
-                                        cpuset = CPU_ALLOC(ncpus);
Brian Stinson 2593d8
-                                        if (!cpuset)
Brian Stinson 2593d8
-                                                return -ENOMEM;
Brian Stinson 2593d8
-
Brian Stinson 2593d8
-                                        CPU_ZERO_S(n, cpuset);
Brian Stinson 2593d8
-                                        if (c->cpuset) {
Brian Stinson 2593d8
-                                                CPU_OR_S(CPU_ALLOC_SIZE(c->cpuset_ncpus), cpuset, c->cpuset, (cpu_set_t*) a);
Brian Stinson 2593d8
-                                                CPU_FREE(c->cpuset);
Brian Stinson 2593d8
-                                        } else
Brian Stinson 2593d8
-                                                CPU_OR_S(n, cpuset, cpuset, (cpu_set_t*) a);
Brian Stinson 2593d8
-
Brian Stinson 2593d8
-                                        c->cpuset = cpuset;
Brian Stinson 2593d8
-                                        c->cpuset_ncpus = ncpus;
Brian Stinson 2593d8
-                                } else
Brian Stinson 2593d8
-                                        CPU_OR_S(n, c->cpuset, c->cpuset, (cpu_set_t*) a);
Brian Stinson 2593d8
+                                /* We forego any optimizations here, and always create the structure using
Brian Stinson 2593d8
+                                 * cpu_set_add_all(), because we don't want to care if the existing size we
Brian Stinson 2593d8
+                                 * got over dbus is appropriate. */
Brian Stinson 2593d8
+                                r = cpu_set_add_all(&c->cpu_set, &set);
Brian Stinson 2593d8
+                                if (r < 0)
Brian Stinson 2593d8
+                                        return r;
Brian Stinson 2593d8
 
Brian Stinson 2593d8
                                 unit_write_settingf(u, flags, name, "%s=%s", name, str);
Brian Stinson 2593d8
                         }
Brian Stinson 2593d8
diff --git a/src/core/execute.c b/src/core/execute.c
Brian Stinson 2593d8
index c42300a41e..22e5825905 100644
Brian Stinson 2593d8
--- a/src/core/execute.c
Brian Stinson 2593d8
+++ b/src/core/execute.c
Brian Stinson 2593d8
@@ -2991,8 +2991,8 @@ static int exec_child(
Brian Stinson 2593d8
                 }
Brian Stinson 2593d8
         }
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-        if (context->cpuset)
Brian Stinson 2593d8
-                if (sched_setaffinity(0, CPU_ALLOC_SIZE(context->cpuset_ncpus), context->cpuset) < 0) {
Brian Stinson 2593d8
+        if (context->cpu_set.set)
Brian Stinson 2593d8
+                if (sched_setaffinity(0, context->cpu_set.allocated, context->cpu_set.set) < 0) {
Brian Stinson 2593d8
                         *exit_status = EXIT_CPUAFFINITY;
Brian Stinson 2593d8
                         return log_unit_error_errno(unit, errno, "Failed to set up CPU affinity: %m");
Brian Stinson 2593d8
                 }
Brian Stinson 2593d8
@@ -3694,7 +3694,7 @@ void exec_context_done(ExecContext *c) {
Brian Stinson 2593d8
         c->temporary_filesystems = NULL;
Brian Stinson 2593d8
         c->n_temporary_filesystems = 0;
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-        c->cpuset = cpu_set_mfree(c->cpuset);
Brian Stinson 2593d8
+        cpu_set_reset(&c->cpu_set);
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         c->utmp_id = mfree(c->utmp_id);
Brian Stinson 2593d8
         c->selinux_context = mfree(c->selinux_context);
Brian Stinson 2593d8
@@ -4097,10 +4097,10 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
Brian Stinson 2593d8
                         prefix, yes_no(c->cpu_sched_reset_on_fork));
Brian Stinson 2593d8
         }
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-        if (c->cpuset) {
Brian Stinson 2593d8
+        if (c->cpu_set.set) {
Brian Stinson 2593d8
                 fprintf(f, "%sCPUAffinity:", prefix);
Brian Stinson 2593d8
-                for (i = 0; i < c->cpuset_ncpus; i++)
Brian Stinson 2593d8
-                        if (CPU_ISSET_S(i, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset))
Brian Stinson 2593d8
+                for (i = 0; i < c->cpu_set.allocated * 8; i++)
Brian Stinson 2593d8
+                        if (CPU_ISSET_S(i, c->cpu_set.allocated, c->cpu_set.set))
Brian Stinson 2593d8
                                 fprintf(f, " %u", i);
Brian Stinson 2593d8
                 fputs("\n", f);
Brian Stinson 2593d8
         }
Brian Stinson 2593d8
diff --git a/src/core/execute.h b/src/core/execute.h
Brian Stinson 2593d8
index 8c91636adc..e1e7a494cd 100644
Brian Stinson 2593d8
--- a/src/core/execute.h
Brian Stinson 2593d8
+++ b/src/core/execute.h
Brian Stinson 2593d8
@@ -14,6 +14,7 @@ typedef struct Manager Manager;
Brian Stinson 2593d8
 #include <sys/capability.h>
Brian Stinson 2593d8
 
Brian Stinson 2593d8
 #include "cgroup-util.h"
Brian Stinson 2593d8
+#include "cpu-set-util.h"
Brian Stinson 2593d8
 #include "fdset.h"
Brian Stinson 2593d8
 #include "list.h"
Brian Stinson 2593d8
 #include "missing.h"
Brian Stinson 2593d8
@@ -148,8 +149,7 @@ struct ExecContext {
Brian Stinson 2593d8
         int cpu_sched_policy;
Brian Stinson 2593d8
         int cpu_sched_priority;
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-        cpu_set_t *cpuset;
Brian Stinson 2593d8
-        unsigned cpuset_ncpus;
Brian Stinson 2593d8
+        CPUSet cpu_set;
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         ExecInput std_input;
Brian Stinson 2593d8
         ExecOutput std_output;
Brian Stinson 2593d8
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
Brian Stinson 2593d8
index d9a5094aa0..34ae834188 100644
Brian Stinson 2593d8
--- a/src/core/load-fragment.c
Brian Stinson 2593d8
+++ b/src/core/load-fragment.c
Brian Stinson 2593d8
@@ -1211,42 +1211,13 @@ int config_parse_exec_cpu_affinity(const char *unit,
Brian Stinson 2593d8
                                    void *userdata) {
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         ExecContext *c = data;
Brian Stinson 2593d8
-        _cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
Brian Stinson 2593d8
-        int ncpus;
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         assert(filename);
Brian Stinson 2593d8
         assert(lvalue);
Brian Stinson 2593d8
         assert(rvalue);
Brian Stinson 2593d8
         assert(data);
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-        ncpus = parse_cpu_set_and_warn(rvalue, &cpuset, unit, filename, line, lvalue);
Brian Stinson 2593d8
-        if (ncpus < 0)
Brian Stinson 2593d8
-                return ncpus;
Brian Stinson 2593d8
-
Brian Stinson 2593d8
-        if (ncpus == 0) {
Brian Stinson 2593d8
-                /* An empty assignment resets the CPU list */
Brian Stinson 2593d8
-                c->cpuset = cpu_set_mfree(c->cpuset);
Brian Stinson 2593d8
-                c->cpuset_ncpus = 0;
Brian Stinson 2593d8
-                return 0;
Brian Stinson 2593d8
-        }
Brian Stinson 2593d8
-
Brian Stinson 2593d8
-        if (!c->cpuset) {
Brian Stinson 2593d8
-                c->cpuset = TAKE_PTR(cpuset);
Brian Stinson 2593d8
-                c->cpuset_ncpus = (unsigned) ncpus;
Brian Stinson 2593d8
-                return 0;
Brian Stinson 2593d8
-        }
Brian Stinson 2593d8
-
Brian Stinson 2593d8
-        if (c->cpuset_ncpus < (unsigned) ncpus) {
Brian Stinson 2593d8
-                CPU_OR_S(CPU_ALLOC_SIZE(c->cpuset_ncpus), cpuset, c->cpuset, cpuset);
Brian Stinson 2593d8
-                CPU_FREE(c->cpuset);
Brian Stinson 2593d8
-                c->cpuset = TAKE_PTR(cpuset);
Brian Stinson 2593d8
-                c->cpuset_ncpus = (unsigned) ncpus;
Brian Stinson 2593d8
-                return 0;
Brian Stinson 2593d8
-        }
Brian Stinson 2593d8
-
Brian Stinson 2593d8
-        CPU_OR_S(CPU_ALLOC_SIZE((unsigned) ncpus), c->cpuset, c->cpuset, cpuset);
Brian Stinson 2593d8
-
Brian Stinson 2593d8
-        return 0;
Brian Stinson 2593d8
+        return parse_cpu_set_extend(rvalue, &c->cpu_set, true, unit, filename, line, lvalue);
Brian Stinson 2593d8
 }
Brian Stinson 2593d8
 
Brian Stinson 2593d8
 int config_parse_capability_set(
Brian Stinson 2593d8
diff --git a/src/core/main.c b/src/core/main.c
Brian Stinson 2593d8
index af7b26d6f1..e62b2756ee 100644
Brian Stinson 2593d8
--- a/src/core/main.c
Brian Stinson 2593d8
+++ b/src/core/main.c
Brian Stinson 2593d8
@@ -537,16 +537,18 @@ static int config_parse_cpu_affinity2(
Brian Stinson 2593d8
                 void *data,
Brian Stinson 2593d8
                 void *userdata) {
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-        _cleanup_cpu_free_ cpu_set_t *c = NULL;
Brian Stinson 2593d8
-        int ncpus;
Brian Stinson 2593d8
+        _cleanup_(cpu_set_reset) CPUSet c = {};
Brian Stinson 2593d8
+        int r;
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-        ncpus = parse_cpu_set_and_warn(rvalue, &c, unit, filename, line, lvalue);
Brian Stinson 2593d8
-        if (ncpus < 0)
Brian Stinson 2593d8
-                return ncpus;
Brian Stinson 2593d8
+        r = parse_cpu_set_full(rvalue, &c, true, unit, filename, line, lvalue);
Brian Stinson 2593d8
+        if (r < 0)
Brian Stinson 2593d8
+                return r;
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-        if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0)
Brian Stinson 2593d8
+        if (sched_setaffinity(0, c.allocated, c.set) < 0)
Brian Stinson 2593d8
                 log_warning_errno(errno, "Failed to set CPU affinity: %m");
Brian Stinson 2593d8
 
Brian Stinson 2593d8
+        // FIXME: parsing and execution should be seperated.
Brian Stinson 2593d8
+
Brian Stinson 2593d8
         return 0;
Brian Stinson 2593d8
 }
Brian Stinson 2593d8
 
Brian Stinson 2593d8
diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c
Brian Stinson 2593d8
index 62a3486952..21c24a1111 100644
Brian Stinson 2593d8
--- a/src/nspawn/nspawn-settings.c
Brian Stinson 2593d8
+++ b/src/nspawn/nspawn-settings.c
Brian Stinson 2593d8
@@ -85,7 +85,7 @@ Settings* settings_free(Settings *s) {
Brian Stinson 2593d8
         strv_free(s->syscall_blacklist);
Brian Stinson 2593d8
         rlimit_free_all(s->rlimit);
Brian Stinson 2593d8
         free(s->hostname);
Brian Stinson 2593d8
-        s->cpuset = cpu_set_mfree(s->cpuset);
Brian Stinson 2593d8
+        cpu_set_reset(&s->cpu_set);
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         strv_free(s->network_interfaces);
Brian Stinson 2593d8
         strv_free(s->network_macvlan);
Brian Stinson 2593d8
@@ -687,41 +687,12 @@ int config_parse_cpu_affinity(
Brian Stinson 2593d8
                 void *data,
Brian Stinson 2593d8
                 void *userdata) {
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-        _cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
Brian Stinson 2593d8
         Settings *settings = data;
Brian Stinson 2593d8
-        int ncpus;
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         assert(rvalue);
Brian Stinson 2593d8
         assert(settings);
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-        ncpus = parse_cpu_set_and_warn(rvalue, &cpuset, unit, filename, line, lvalue);
Brian Stinson 2593d8
-        if (ncpus < 0)
Brian Stinson 2593d8
-                return ncpus;
Brian Stinson 2593d8
-
Brian Stinson 2593d8
-        if (ncpus == 0) {
Brian Stinson 2593d8
-                /* An empty assignment resets the CPU list */
Brian Stinson 2593d8
-                settings->cpuset = cpu_set_mfree(settings->cpuset);
Brian Stinson 2593d8
-                settings->cpuset_ncpus = 0;
Brian Stinson 2593d8
-                return 0;
Brian Stinson 2593d8
-        }
Brian Stinson 2593d8
-
Brian Stinson 2593d8
-        if (!settings->cpuset) {
Brian Stinson 2593d8
-                settings->cpuset = TAKE_PTR(cpuset);
Brian Stinson 2593d8
-                settings->cpuset_ncpus = (unsigned) ncpus;
Brian Stinson 2593d8
-                return 0;
Brian Stinson 2593d8
-        }
Brian Stinson 2593d8
-
Brian Stinson 2593d8
-        if (settings->cpuset_ncpus < (unsigned) ncpus) {
Brian Stinson 2593d8
-                CPU_OR_S(CPU_ALLOC_SIZE(settings->cpuset_ncpus), cpuset, settings->cpuset, cpuset);
Brian Stinson 2593d8
-                CPU_FREE(settings->cpuset);
Brian Stinson 2593d8
-                settings->cpuset = TAKE_PTR(cpuset);
Brian Stinson 2593d8
-                settings->cpuset_ncpus = (unsigned) ncpus;
Brian Stinson 2593d8
-                return 0;
Brian Stinson 2593d8
-        }
Brian Stinson 2593d8
-
Brian Stinson 2593d8
-        CPU_OR_S(CPU_ALLOC_SIZE((unsigned) ncpus), settings->cpuset, settings->cpuset, cpuset);
Brian Stinson 2593d8
-
Brian Stinson 2593d8
-        return 0;
Brian Stinson 2593d8
+        return parse_cpu_set_extend(rvalue, &settings->cpu_set, true, unit, filename, line, lvalue);
Brian Stinson 2593d8
 }
Brian Stinson 2593d8
 
Brian Stinson 2593d8
 DEFINE_CONFIG_PARSE_ENUM(config_parse_resolv_conf, resolv_conf_mode, ResolvConfMode, "Failed to parse resolv.conf mode");
Brian Stinson 2593d8
diff --git a/src/nspawn/nspawn-settings.h b/src/nspawn/nspawn-settings.h
Brian Stinson 2593d8
index d522f3cb36..da863ef11c 100644
Brian Stinson 2593d8
--- a/src/nspawn/nspawn-settings.h
Brian Stinson 2593d8
+++ b/src/nspawn/nspawn-settings.h
Brian Stinson 2593d8
@@ -7,6 +7,7 @@
Brian Stinson 2593d8
 #include "sd-id128.h"
Brian Stinson 2593d8
 
Brian Stinson 2593d8
 #include "conf-parser.h"
Brian Stinson 2593d8
+#include "cpu-set-util.h"
Brian Stinson 2593d8
 #include "macro.h"
Brian Stinson 2593d8
 #include "nspawn-expose-ports.h"
Brian Stinson 2593d8
 #include "nspawn-mount.h"
Brian Stinson 2593d8
@@ -123,8 +124,7 @@ typedef struct Settings {
Brian Stinson 2593d8
         int no_new_privileges;
Brian Stinson 2593d8
         int oom_score_adjust;
Brian Stinson 2593d8
         bool oom_score_adjust_set;
Brian Stinson 2593d8
-        cpu_set_t *cpuset;
Brian Stinson 2593d8
-        unsigned cpuset_ncpus;
Brian Stinson 2593d8
+        CPUSet cpu_set;
Brian Stinson 2593d8
         ResolvConfMode resolv_conf;
Brian Stinson 2593d8
         LinkJournal link_journal;
Brian Stinson 2593d8
         bool link_journal_try;
Brian Stinson 2593d8
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
Brian Stinson 2593d8
index b40411dcd0..08255b5724 100644
Brian Stinson 2593d8
--- a/src/nspawn/nspawn.c
Brian Stinson 2593d8
+++ b/src/nspawn/nspawn.c
Brian Stinson 2593d8
@@ -199,8 +199,7 @@ static struct rlimit *arg_rlimit[_RLIMIT_MAX] = {};
Brian Stinson 2593d8
 static bool arg_no_new_privileges = false;
Brian Stinson 2593d8
 static int arg_oom_score_adjust = 0;
Brian Stinson 2593d8
 static bool arg_oom_score_adjust_set = false;
Brian Stinson 2593d8
-static cpu_set_t *arg_cpuset = NULL;
Brian Stinson 2593d8
-static unsigned arg_cpuset_ncpus = 0;
Brian Stinson 2593d8
+static CPUSet arg_cpu_set = {};
Brian Stinson 2593d8
 static ResolvConfMode arg_resolv_conf = RESOLV_CONF_AUTO;
Brian Stinson 2593d8
 static TimezoneMode arg_timezone = TIMEZONE_AUTO;
Brian Stinson 2593d8
 
Brian Stinson 2593d8
@@ -1186,17 +1185,14 @@ static int parse_argv(int argc, char *argv[]) {
Brian Stinson 2593d8
                         break;
Brian Stinson 2593d8
 
Brian Stinson 2593d8
                 case ARG_CPU_AFFINITY: {
Brian Stinson 2593d8
-                        _cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
Brian Stinson 2593d8
+                        CPUSet cpuset;
Brian Stinson 2593d8
 
Brian Stinson 2593d8
                         r = parse_cpu_set(optarg, &cpuset);
Brian Stinson 2593d8
                         if (r < 0)
Brian Stinson 2593d8
-                                return log_error_errno(r, "Failed to parse CPU affinity mask: %s", optarg);
Brian Stinson 2593d8
+                                return log_error_errno(r, "Failed to parse CPU affinity mask %s: %m", optarg);
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-                        if (arg_cpuset)
Brian Stinson 2593d8
-                                CPU_FREE(arg_cpuset);
Brian Stinson 2593d8
-
Brian Stinson 2593d8
-                        arg_cpuset = TAKE_PTR(cpuset);
Brian Stinson 2593d8
-                        arg_cpuset_ncpus = r;
Brian Stinson 2593d8
+                        cpu_set_reset(&arg_cpu_set);
Brian Stinson 2593d8
+                        arg_cpu_set = cpuset;
Brian Stinson 2593d8
                         arg_settings_mask |= SETTING_CPU_AFFINITY;
Brian Stinson 2593d8
                         break;
Brian Stinson 2593d8
                 }
Brian Stinson 2593d8
@@ -2631,8 +2627,8 @@ static int inner_child(
Brian Stinson 2593d8
                         return log_error_errno(r, "Failed to adjust OOM score: %m");
Brian Stinson 2593d8
         }
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-        if (arg_cpuset)
Brian Stinson 2593d8
-                if (sched_setaffinity(0, CPU_ALLOC_SIZE(arg_cpuset_ncpus), arg_cpuset) < 0)
Brian Stinson 2593d8
+        if (arg_cpu_set.set)
Brian Stinson 2593d8
+                if (sched_setaffinity(0, arg_cpu_set.allocated, arg_cpu_set.set) < 0)
Brian Stinson 2593d8
                         return log_error_errno(errno, "Failed to set CPU affinity: %m");
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         r = drop_capabilities();
Brian Stinson 2593d8
@@ -3494,15 +3490,14 @@ static int merge_settings(Settings *settings, const char *path) {
Brian Stinson 2593d8
         }
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         if ((arg_settings_mask & SETTING_CPU_AFFINITY) == 0 &&
Brian Stinson 2593d8
-            settings->cpuset) {
Brian Stinson 2593d8
+            settings->cpu_set.set) {
Brian Stinson 2593d8
 
Brian Stinson 2593d8
                 if (!arg_settings_trusted)
Brian Stinson 2593d8
                         log_warning("Ignoring CPUAffinity= setting, file '%s' is not trusted.", path);
Brian Stinson 2593d8
                 else {
Brian Stinson 2593d8
-                        if (arg_cpuset)
Brian Stinson 2593d8
-                                CPU_FREE(arg_cpuset);
Brian Stinson 2593d8
-                        arg_cpuset = TAKE_PTR(settings->cpuset);
Brian Stinson 2593d8
-                        arg_cpuset_ncpus = settings->cpuset_ncpus;
Brian Stinson 2593d8
+                        cpu_set_reset(&arg_cpu_set);
Brian Stinson 2593d8
+                        arg_cpu_set = settings->cpu_set;
Brian Stinson 2593d8
+                        settings->cpu_set = (CPUSet) {};
Brian Stinson 2593d8
                 }
Brian Stinson 2593d8
         }
Brian Stinson 2593d8
 
Brian Stinson 2593d8
@@ -4600,7 +4595,7 @@ finish:
Brian Stinson 2593d8
         rlimit_free_all(arg_rlimit);
Brian Stinson 2593d8
         strv_free(arg_syscall_whitelist);
Brian Stinson 2593d8
         strv_free(arg_syscall_blacklist);
Brian Stinson 2593d8
-        arg_cpuset = cpu_set_mfree(arg_cpuset);
Brian Stinson 2593d8
+        cpu_set_reset(&arg_cpu_set);
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         return r < 0 ? EXIT_FAILURE : ret;
Brian Stinson 2593d8
 }
Brian Stinson 2593d8
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
Brian Stinson 2593d8
index 271cc054da..75b4aace84 100644
Brian Stinson 2593d8
--- a/src/shared/bus-unit-util.c
Brian Stinson 2593d8
+++ b/src/shared/bus-unit-util.c
Brian Stinson 2593d8
@@ -932,13 +932,13 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
Brian Stinson 2593d8
         }
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         if (streq(field, "CPUAffinity")) {
Brian Stinson 2593d8
-                _cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
Brian Stinson 2593d8
+                _cleanup_(cpu_set_reset) CPUSet cpuset = {};
Brian Stinson 2593d8
 
Brian Stinson 2593d8
                 r = parse_cpu_set(eq, &cpuset);
Brian Stinson 2593d8
                 if (r < 0)
Brian Stinson 2593d8
                         return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
Brian Stinson 2593d8
 
Brian Stinson 2593d8
-                return bus_append_byte_array(m, field, cpuset, CPU_ALLOC_SIZE(r));
Brian Stinson 2593d8
+                return bus_append_byte_array(m, field, cpuset.set, cpuset.allocated);
Brian Stinson 2593d8
         }
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         if (STR_IN_SET(field, "RestrictAddressFamilies", "SystemCallFilter")) {
Brian Stinson 2593d8
diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c
Brian Stinson 2593d8
index ff5edb2a69..b9ec29af66 100644
Brian Stinson 2593d8
--- a/src/test/test-cpu-set-util.c
Brian Stinson 2593d8
+++ b/src/test/test-cpu-set-util.c
Brian Stinson 2593d8
@@ -1,154 +1,171 @@
Brian Stinson 2593d8
 /* SPDX-License-Identifier: LGPL-2.1+ */
Brian Stinson 2593d8
 
Brian Stinson 2593d8
+#include <errno.h>
Brian Stinson 2593d8
+
Brian Stinson 2593d8
 #include "alloc-util.h"
Brian Stinson 2593d8
 #include "cpu-set-util.h"
Brian Stinson 2593d8
 #include "macro.h"
Brian Stinson 2593d8
 
Brian Stinson 2593d8
 static void test_parse_cpu_set(void) {
Brian Stinson 2593d8
-        cpu_set_t *c = NULL;
Brian Stinson 2593d8
+        CPUSet c = {};
Brian Stinson 2593d8
         _cleanup_free_ char *str = NULL;
Brian Stinson 2593d8
-        int ncpus;
Brian Stinson 2593d8
         int cpu;
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         /* Simple range (from CPUAffinity example) */
Brian Stinson 2593d8
-        ncpus = parse_cpu_set_and_warn("1 2", &c, NULL, "fake", 1, "CPUAffinity");
Brian Stinson 2593d8
-        assert_se(ncpus >= 1024);
Brian Stinson 2593d8
-        assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c));
Brian Stinson 2593d8
-        assert_se(CPU_ISSET_S(2, CPU_ALLOC_SIZE(ncpus), c));
Brian Stinson 2593d8
-        assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 2);
Brian Stinson 2593d8
-
Brian Stinson 2593d8
-        assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
Brian Stinson 2593d8
+        assert_se(parse_cpu_set_full("1 2", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
Brian Stinson 2593d8
+        assert_se(c.set);
Brian Stinson 2593d8
+        assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
Brian Stinson 2593d8
+        assert_se(CPU_ISSET_S(1, c.allocated, c.set));
Brian Stinson 2593d8
+        assert_se(CPU_ISSET_S(2, c.allocated, c.set));
Brian Stinson 2593d8
+        assert_se(CPU_COUNT_S(c.allocated, c.set) == 2);
Brian Stinson 2593d8
+
Brian Stinson 2593d8
+        assert_se(str = cpu_set_to_string(&c);;
Brian Stinson 2593d8
         log_info("cpu_set_to_string: %s", str);
Brian Stinson 2593d8
         str = mfree(str);
Brian Stinson 2593d8
-        c = cpu_set_mfree(c);
Brian Stinson 2593d8
+        cpu_set_reset(&c);
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         /* A more interesting range */
Brian Stinson 2593d8
-        ncpus = parse_cpu_set_and_warn("0 1 2 3 8 9 10 11", &c, NULL, "fake", 1, "CPUAffinity");
Brian Stinson 2593d8
-        assert_se(ncpus >= 1024);
Brian Stinson 2593d8
-        assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
Brian Stinson 2593d8
+        assert_se(parse_cpu_set_full("0 1 2 3 8 9 10 11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
Brian Stinson 2593d8
+        assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
Brian Stinson 2593d8
+        assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
Brian Stinson 2593d8
         for (cpu = 0; cpu < 4; cpu++)
Brian Stinson 2593d8
-                assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
Brian Stinson 2593d8
+                assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
Brian Stinson 2593d8
         for (cpu = 8; cpu < 12; cpu++)
Brian Stinson 2593d8
-                assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
Brian Stinson 2593d8
-        assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
Brian Stinson 2593d8
+                assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
Brian Stinson 2593d8
+        assert_se(str = cpu_set_to_string(&c);;
Brian Stinson 2593d8
         log_info("cpu_set_to_string: %s", str);
Brian Stinson 2593d8
         str = mfree(str);
Brian Stinson 2593d8
-        c = cpu_set_mfree(c);
Brian Stinson 2593d8
+        cpu_set_reset(&c);
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         /* Quoted strings */
Brian Stinson 2593d8
-        ncpus = parse_cpu_set_and_warn("8 '9' 10 \"11\"", &c, NULL, "fake", 1, "CPUAffinity");
Brian Stinson 2593d8
-        assert_se(ncpus >= 1024);
Brian Stinson 2593d8
-        assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 4);
Brian Stinson 2593d8
+        assert_se(parse_cpu_set_full("8 '9' 10 \"11\"", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
Brian Stinson 2593d8
+        assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
Brian Stinson 2593d8
+        assert_se(CPU_COUNT_S(c.allocated, c.set) == 4);
Brian Stinson 2593d8
         for (cpu = 8; cpu < 12; cpu++)
Brian Stinson 2593d8
-                assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
Brian Stinson 2593d8
-        assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
Brian Stinson 2593d8
+                assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
Brian Stinson 2593d8
+        assert_se(str = cpu_set_to_string(&c);;
Brian Stinson 2593d8
         log_info("cpu_set_to_string: %s", str);
Brian Stinson 2593d8
         str = mfree(str);
Brian Stinson 2593d8
-        c = cpu_set_mfree(c);
Brian Stinson 2593d8
+        cpu_set_reset(&c);
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         /* Use commas as separators */
Brian Stinson 2593d8
-        ncpus = parse_cpu_set_and_warn("0,1,2,3 8,9,10,11", &c, NULL, "fake", 1, "CPUAffinity");
Brian Stinson 2593d8
-        assert_se(ncpus >= 1024);
Brian Stinson 2593d8
-        assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
Brian Stinson 2593d8
+        assert_se(parse_cpu_set_full("0,1,2,3 8,9,10,11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
Brian Stinson 2593d8
+        assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
Brian Stinson 2593d8
+        assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
Brian Stinson 2593d8
         for (cpu = 0; cpu < 4; cpu++)
Brian Stinson 2593d8
-                assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
Brian Stinson 2593d8
+                assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
Brian Stinson 2593d8
         for (cpu = 8; cpu < 12; cpu++)
Brian Stinson 2593d8
-                assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
Brian Stinson 2593d8
-        assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
Brian Stinson 2593d8
+                assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
Brian Stinson 2593d8
+        assert_se(str = cpu_set_to_string(&c);;
Brian Stinson 2593d8
         log_info("cpu_set_to_string: %s", str);
Brian Stinson 2593d8
         str = mfree(str);
Brian Stinson 2593d8
-        c = cpu_set_mfree(c);
Brian Stinson 2593d8
+        cpu_set_reset(&c);
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         /* Commas with spaces (and trailing comma, space) */
Brian Stinson 2593d8
-        ncpus = parse_cpu_set_and_warn("0, 1, 2, 3, 4, 5, 6, 7, ", &c, NULL, "fake", 1, "CPUAffinity");
Brian Stinson 2593d8
-        assert_se(ncpus >= 1024);
Brian Stinson 2593d8
-        assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
Brian Stinson 2593d8
+        assert_se(parse_cpu_set_full("0, 1, 2, 3, 4, 5, 6, 7, ", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
Brian Stinson 2593d8
+        assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
Brian Stinson 2593d8
+        assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
Brian Stinson 2593d8
         for (cpu = 0; cpu < 8; cpu++)
Brian Stinson 2593d8
-                assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
Brian Stinson 2593d8
-        assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
Brian Stinson 2593d8
+                assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
Brian Stinson 2593d8
+        assert_se(str = cpu_set_to_string(&c);;
Brian Stinson 2593d8
         log_info("cpu_set_to_string: %s", str);
Brian Stinson 2593d8
         str = mfree(str);
Brian Stinson 2593d8
-        c = cpu_set_mfree(c);
Brian Stinson 2593d8
+        cpu_set_reset(&c);
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         /* Ranges */
Brian Stinson 2593d8
-        ncpus = parse_cpu_set_and_warn("0-3,8-11", &c, NULL, "fake", 1, "CPUAffinity");
Brian Stinson 2593d8
-        assert_se(ncpus >= 1024);
Brian Stinson 2593d8
-        assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
Brian Stinson 2593d8
+        assert_se(parse_cpu_set_full("0-3,8-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
Brian Stinson 2593d8
+        assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
Brian Stinson 2593d8
+        assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
Brian Stinson 2593d8
         for (cpu = 0; cpu < 4; cpu++)
Brian Stinson 2593d8
-                assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
Brian Stinson 2593d8
+                assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
Brian Stinson 2593d8
         for (cpu = 8; cpu < 12; cpu++)
Brian Stinson 2593d8
-                assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
Brian Stinson 2593d8
-        assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
Brian Stinson 2593d8
+                assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
Brian Stinson 2593d8
+        assert_se(str = cpu_set_to_string(&c);;
Brian Stinson 2593d8
         log_info("cpu_set_to_string: %s", str);
Brian Stinson 2593d8
         str = mfree(str);
Brian Stinson 2593d8
-        c = cpu_set_mfree(c);
Brian Stinson 2593d8
+        cpu_set_reset(&c);
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         /* Ranges with trailing comma, space */
Brian Stinson 2593d8
-        ncpus = parse_cpu_set_and_warn("0-3  8-11, ", &c, NULL, "fake", 1, "CPUAffinity");
Brian Stinson 2593d8
-        assert_se(ncpus >= 1024);
Brian Stinson 2593d8
-        assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
Brian Stinson 2593d8
+        assert_se(parse_cpu_set_full("0-3  8-11, ", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
Brian Stinson 2593d8
+        assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
Brian Stinson 2593d8
+        assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
Brian Stinson 2593d8
         for (cpu = 0; cpu < 4; cpu++)
Brian Stinson 2593d8
-                assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
Brian Stinson 2593d8
+                assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
Brian Stinson 2593d8
         for (cpu = 8; cpu < 12; cpu++)
Brian Stinson 2593d8
-                assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
Brian Stinson 2593d8
-        assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
Brian Stinson 2593d8
+                assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
Brian Stinson 2593d8
+        assert_se(str = cpu_set_to_string(&c);;
Brian Stinson 2593d8
         log_info("cpu_set_to_string: %s", str);
Brian Stinson 2593d8
         str = mfree(str);
Brian Stinson 2593d8
-        c = cpu_set_mfree(c);
Brian Stinson 2593d8
+        cpu_set_reset(&c);
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         /* Negative range (returns empty cpu_set) */
Brian Stinson 2593d8
-        ncpus = parse_cpu_set_and_warn("3-0", &c, NULL, "fake", 1, "CPUAffinity");
Brian Stinson 2593d8
-        assert_se(ncpus >= 1024);
Brian Stinson 2593d8
-        assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 0);
Brian Stinson 2593d8
-        c = cpu_set_mfree(c);
Brian Stinson 2593d8
+        assert_se(parse_cpu_set_full("3-0", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
Brian Stinson 2593d8
+        assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
Brian Stinson 2593d8
+        assert_se(CPU_COUNT_S(c.allocated, c.set) == 0);
Brian Stinson 2593d8
+        cpu_set_reset(&c);
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         /* Overlapping ranges */
Brian Stinson 2593d8
-        ncpus = parse_cpu_set_and_warn("0-7 4-11", &c, NULL, "fake", 1, "CPUAffinity");
Brian Stinson 2593d8
-        assert_se(ncpus >= 1024);
Brian Stinson 2593d8
-        assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 12);
Brian Stinson 2593d8
+        assert_se(parse_cpu_set_full("0-7 4-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
Brian Stinson 2593d8
+        assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
Brian Stinson 2593d8
+        assert_se(CPU_COUNT_S(c.allocated, c.set) == 12);
Brian Stinson 2593d8
         for (cpu = 0; cpu < 12; cpu++)
Brian Stinson 2593d8
-                assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
Brian Stinson 2593d8
-        assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
Brian Stinson 2593d8
+                assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
Brian Stinson 2593d8
+        assert_se(str = cpu_set_to_string(&c);;
Brian Stinson 2593d8
         log_info("cpu_set_to_string: %s", str);
Brian Stinson 2593d8
         str = mfree(str);
Brian Stinson 2593d8
-        c = cpu_set_mfree(c);
Brian Stinson 2593d8
+        cpu_set_reset(&c);
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         /* Mix ranges and individual CPUs */
Brian Stinson 2593d8
-        ncpus = parse_cpu_set_and_warn("0,1 4-11", &c, NULL, "fake", 1, "CPUAffinity");
Brian Stinson 2593d8
-        assert_se(ncpus >= 1024);
Brian Stinson 2593d8
-        assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 10);
Brian Stinson 2593d8
-        assert_se(CPU_ISSET_S(0, CPU_ALLOC_SIZE(ncpus), c));
Brian Stinson 2593d8
-        assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c));
Brian Stinson 2593d8
+        assert_se(parse_cpu_set_full("0,1 4-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
Brian Stinson 2593d8
+        assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
Brian Stinson 2593d8
+        assert_se(CPU_COUNT_S(c.allocated, c.set) == 10);
Brian Stinson 2593d8
+        assert_se(CPU_ISSET_S(0, c.allocated, c.set));
Brian Stinson 2593d8
+        assert_se(CPU_ISSET_S(1, c.allocated, c.set));
Brian Stinson 2593d8
         for (cpu = 4; cpu < 12; cpu++)
Brian Stinson 2593d8
-                assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
Brian Stinson 2593d8
-        assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
Brian Stinson 2593d8
+                assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
Brian Stinson 2593d8
+        assert_se(str = cpu_set_to_string(&c);;
Brian Stinson 2593d8
         log_info("cpu_set_to_string: %s", str);
Brian Stinson 2593d8
         str = mfree(str);
Brian Stinson 2593d8
-        c = cpu_set_mfree(c);
Brian Stinson 2593d8
+        cpu_set_reset(&c);
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         /* Garbage */
Brian Stinson 2593d8
-        ncpus = parse_cpu_set_and_warn("0 1 2 3 garbage", &c, NULL, "fake", 1, "CPUAffinity");
Brian Stinson 2593d8
-        assert_se(ncpus < 0);
Brian Stinson 2593d8
-        assert_se(!c);
Brian Stinson 2593d8
+        assert_se(parse_cpu_set_full("0 1 2 3 garbage", &c, true, NULL, "fake", 1, "CPUAffinity") == -EINVAL);
Brian Stinson 2593d8
+        assert_se(!c.set);
Brian Stinson 2593d8
+        assert_se(c.allocated == 0);
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         /* Range with garbage */
Brian Stinson 2593d8
-        ncpus = parse_cpu_set_and_warn("0-3 8-garbage", &c, NULL, "fake", 1, "CPUAffinity");
Brian Stinson 2593d8
-        assert_se(ncpus < 0);
Brian Stinson 2593d8
-        assert_se(!c);
Brian Stinson 2593d8
+        assert_se(parse_cpu_set_full("0-3 8-garbage", &c, true, NULL, "fake", 1, "CPUAffinity") == -EINVAL);
Brian Stinson 2593d8
+        assert_se(!c.set);
Brian Stinson 2593d8
+        assert_se(c.allocated == 0);
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         /* Empty string */
Brian Stinson 2593d8
-        c = NULL;
Brian Stinson 2593d8
-        ncpus = parse_cpu_set_and_warn("", &c, NULL, "fake", 1, "CPUAffinity");
Brian Stinson 2593d8
-        assert_se(ncpus == 0);  /* empty string returns 0 */
Brian Stinson 2593d8
-        assert_se(!c);
Brian Stinson 2593d8
+        assert_se(parse_cpu_set_full("", &c, true, NULL, "fake", 1, "CPUAffinity") == 0);
Brian Stinson 2593d8
+        assert_se(!c.set);                /* empty string returns NULL */
Brian Stinson 2593d8
+        assert_se(c.allocated == 0);
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         /* Runaway quoted string */
Brian Stinson 2593d8
-        ncpus = parse_cpu_set_and_warn("0 1 2 3 \"4 5 6 7 ", &c, NULL, "fake", 1, "CPUAffinity");
Brian Stinson 2593d8
-        assert_se(ncpus < 0);
Brian Stinson 2593d8
-        assert_se(!c);
Brian Stinson 2593d8
+        assert_se(parse_cpu_set_full("0 1 2 3 \"4 5 6 7 ", &c, true, NULL, "fake", 1, "CPUAffinity") == -EINVAL);
Brian Stinson 2593d8
+        assert_se(!c.set);
Brian Stinson 2593d8
+        assert_se(c.allocated == 0);
Brian Stinson 2593d8
+
Brian Stinson 2593d8
+        /* Maximum allocation */
Brian Stinson 2593d8
+        assert_se(parse_cpu_set_full("8000-8191", &c, true, NULL, "fake", 1, "CPUAffinity") == 0);
Brian Stinson 2593d8
+        assert_se(CPU_COUNT_S(c.allocated, c.set) == 192);
Brian Stinson 2593d8
+        assert_se(str = cpu_set_to_string(&c);;
Brian Stinson 2593d8
+        log_info("cpu_set_to_string: %s", str);
Brian Stinson 2593d8
+        str = mfree(str);
Brian Stinson 2593d8
+        cpu_set_reset(&c);
Brian Stinson 2593d8
 }
Brian Stinson 2593d8
 
Brian Stinson 2593d8
 int main(int argc, char *argv[]) {
Brian Stinson 2593d8
+        log_info("CPU_ALLOC_SIZE(1) = %zu", CPU_ALLOC_SIZE(1));
Brian Stinson 2593d8
+        log_info("CPU_ALLOC_SIZE(9) = %zu", CPU_ALLOC_SIZE(9));
Brian Stinson 2593d8
+        log_info("CPU_ALLOC_SIZE(64) = %zu", CPU_ALLOC_SIZE(64));
Brian Stinson 2593d8
+        log_info("CPU_ALLOC_SIZE(65) = %zu", CPU_ALLOC_SIZE(65));
Brian Stinson 2593d8
+        log_info("CPU_ALLOC_SIZE(1024) = %zu", CPU_ALLOC_SIZE(1024));
Brian Stinson 2593d8
+        log_info("CPU_ALLOC_SIZE(1025) = %zu", CPU_ALLOC_SIZE(1025));
Brian Stinson 2593d8
+        log_info("CPU_ALLOC_SIZE(8191) = %zu", CPU_ALLOC_SIZE(8191));
Brian Stinson 2593d8
+
Brian Stinson 2593d8
         test_parse_cpu_set();
Brian Stinson 2593d8
 
Brian Stinson 2593d8
         return 0;
Brian Stinson 2593d8
diff --git a/src/test/test-sizeof.c b/src/test/test-sizeof.c
Brian Stinson 2593d8
index 7a1e496ed2..396e68f35f 100644
Brian Stinson 2593d8
--- a/src/test/test-sizeof.c
Brian Stinson 2593d8
+++ b/src/test/test-sizeof.c
Brian Stinson 2593d8
@@ -1,5 +1,6 @@
Brian Stinson 2593d8
 /* SPDX-License-Identifier: LGPL-2.1+ */
Brian Stinson 2593d8
 
Brian Stinson 2593d8
+#include <sched.h>
Brian Stinson 2593d8
 #include <stdio.h>
Brian Stinson 2593d8
 #include <string.h>
Brian Stinson 2593d8
 
Brian Stinson 2593d8
@@ -64,6 +65,8 @@ int main(void) {
Brian Stinson 2593d8
         info(uid_t);
Brian Stinson 2593d8
         info(gid_t);
Brian Stinson 2593d8
 
Brian Stinson 2593d8
+        info(__cpu_mask);
Brian Stinson 2593d8
+
Brian Stinson 2593d8
         info(enum Enum);
Brian Stinson 2593d8
         info(enum BigEnum);
Brian Stinson 2593d8
         info(enum BigEnum2);