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