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 configured CPU
count reported by sysconf(_SC_NPROCESSORS_CONF), 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.

Use _SC_NPROCESSORS_CONF as the initial Linux allocation size and retry
sched_getaffinity() with larger dynamically allocated CPU masks on EINVAL,
while preserving 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:
- Tested on a QEMU/KVM Rocky Linux 9.7 VM running Linux 6.6.119,
  with CPUs 0-159 possible, CPUs 0-19 online, and the tested process
  limited to CPUs 6-9; verified that sched_getaffinity() failed with
  CPU_ALLOC(20/64/128) and succeeded with CPU_ALLOC(160), returning
  4 CPUs.

Assisted-by: GPT-5, Codex
Signed-off-by: Wang Zhan <[email protected]>
---
v2:
- Use _SC_NPROCESSORS_CONF as the initial Linux allocation size.
- Keep the EINVAL retry loop for CPU hotplug environments where configured
  CPUs are still smaller than the kernel affinity mask.
- Remove one-shot enums, extra casts, MIN(), and use '* 2' growth.
- Use full name in Signed-off-by.

 lib/ovs-thread.c | 25 +++++++++++++++++++++----
 1 file changed, 21 insertions(+), 4 deletions(-)

diff --git a/lib/ovs-thread.c b/lib/ovs-thread.c
index 243791de8..095843d8d 100644
--- a/lib/ovs-thread.c
+++ b/lib/ovs-thread.c
@@ -647,14 +647,31 @@ 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);
+        long int n_conf = sysconf(_SC_NPROCESSORS_CONF);
+        size_t n_alloc = MAX(n_cores, n_conf);
+        size_t max_n_alloc = MAX(n_alloc, 1 << 18);
+        int error = EINVAL;
+
+        /* sched_getaffinity() returns EINVAL when 'size' is smaller than the
+         * kernel affinity mask.  This can happen when the possible CPU range
+         * exceeds the CPU count reported by sysconf(). */
+        while (error == EINVAL && n_alloc <= max_n_alloc) {
+            size_t size = CPU_ALLOC_SIZE(n_alloc);
+            cpu_set_t *set = CPU_ALLOC(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;
             }
+
+            error = errno;
+            n_alloc *= 2;
             CPU_FREE(set);
         }
     }
-- 
2.47.3
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to