count_cpu_cores__() allocates the CPU affinity mask based on the number of online CPUs returned by sysconf(_SC_NPROCESSORS_ONLN). On Linux, sched_getaffinity() returns EINVAL if the supplied mask is smaller than the kernel affinity mask.
This can happen when the possible CPU range exceeds the online CPU count, for example on systems or VMs configured for CPU hotplug. In that case OVS falls back to the online CPU count and may ignore the process affinity mask when sizing handler threads. Retry sched_getaffinity() with larger dynamically allocated CPU masks on EINVAL, while preserving the existing fallback behavior for other failures. This follows the sched_getaffinity(2) guidance for large CPU affinity masks: probe with dynamically allocated masks of increasing size until the call no longer fails with EINVAL. Testing: - Ran make check TESTSUITEFLAGS=-j4: 2751 tests passed, 6 skipped. - Built an Open vSwitch RPM with this patch. - Installed the RPM on a Rocky Linux 9.7 VM running Linux 6.6.119, with CPUs 0-159 possible, CPUs 0-19 online, and ovs-vswitchd limited to CPUs 6-9; verified that per-cpu handler threads dropped from 20 to 5 after restart, following the process affinity mask. Assisted-by: GPT-5, Codex Signed-off-by: zwtop <[email protected]> --- lib/ovs-thread.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/lib/ovs-thread.c b/lib/ovs-thread.c index 243791de8..141721e8b 100644 --- a/lib/ovs-thread.c +++ b/lib/ovs-thread.c @@ -647,15 +647,35 @@ count_cpu_cores__(void) #endif #ifdef __linux__ if (n_cores > 0) { - cpu_set_t *set = CPU_ALLOC(n_cores); - - if (set) { - size_t size = CPU_ALLOC_SIZE(n_cores); + enum { CPU_ALLOC_INITIAL = 1024 }; + enum { CPU_ALLOC_MAX = 1024 << 8 }; + size_t n_alloc = MAX((size_t) n_cores, (size_t) CPU_ALLOC_INITIAL); + size_t max_n_alloc = MAX(n_alloc, (size_t) CPU_ALLOC_MAX); + + /* sched_getaffinity() returns EINVAL when 'size' is smaller than the + * kernel affinity mask. This can happen when the possible CPU range + * exceeds the online CPU count. */ + for (;;) { + cpu_set_t *set = CPU_ALLOC(n_alloc); + size_t size = CPU_ALLOC_SIZE(n_alloc); + + if (!set) { + break; + } + CPU_ZERO_S(size, set); if (!sched_getaffinity(0, size, set)) { n_cores = CPU_COUNT_S(size, set); + CPU_FREE(set); + break; } + + int error = errno; CPU_FREE(set); + if (error != EINVAL || n_alloc >= max_n_alloc) { + break; + } + n_alloc = MIN(n_alloc << 2, max_n_alloc); } } #endif -- 2.47.3 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
