Skip to content

vm: derive host CPU capacity from online cores, not process affinity - #190

Merged
CMGS merged 1 commit into
masterfrom
fix/vcpu-host-capacity
Aug 5, 2026
Merged

vm: derive host CPU capacity from online cores, not process affinity#190
CMGS merged 1 commit into
masterfrom
fix/vcpu-host-capacity

Conversation

@CMGS

@CMGS CMGS commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Fixes #189.

runtime.NumCPU() returns the size of the calling process's CPU affinity mask, not the machine's core count. A control plane pinned to a reserved core (systemd-run -p AllowedCPUs=383 cocoon vm clone ... — the shape a cgroup_cpus fence deployment invites) therefore:

  • hard-rejected every multi-vCPU create/clone/restore: requested 2 vCPUs exceeds host cores (1)
  • silently collapsed CH's hotplug ceiling to --cpus max=1 for every VM it launched

HostCPUCount() reads /sys/devices/system/cpu/online (affinity-independent, parsed with the existing cgroup.ParseCPUList) and falls back to runtime.NumCPU() where the file is unavailable (darwin). Both guest-facing sites — ValidateHostCPU and buildVMConfig — now use it. The process-concurrency sites (pool_size default, sqlite reader pool, PoolSizeOrDefault) intentionally keep runtime.NumCPU: affinity is the correct sizing for the process's own workers.

The fence width is deliberately not a ceiling: vCPU overcommit against the fence is legitimate (many VMs already sum past it), so the validation keeps its original meaning — reject configs that exceed the machine.

Hot-path cost: one small sysfs read per create/clone/restore/launch, dwarfed by the fork/exec and snapshot I/O around it; no caching, so CPU hotplug is always seen fresh.

Verification on a 384-core linux/amd64 host:

--- unpinned:
    utils_test.go:17: HostCPUCount=384 runtime.NumCPU=384
--- PASS: TestHostCPUCount (0.00s)
--- taskset -c 0:
    utils_test.go:17: HostCPUCount=384 runtime.NumCPU=1
--- PASS: TestHostCPUCount (0.00s)

The pinned row is exactly the #189 failure shape: the old code compared against 1, the new code sees the machine.

Gates: make lint (both GOOS) 0 issues, asl ./... (both GOOS) clean, go test ./... 34 packages ok.

runtime.NumCPU reports the calling process's affinity mask, so a
core-pinned control plane rejected multi-vCPU creates/clones/restores
and collapsed CH's hotplug ceiling to max=1. HostCPUCount reads
/sys/devices/system/cpu/online (NumCPU fallback where unavailable);
process-concurrency pools intentionally keep NumCPU.
@CMGS
CMGS merged commit c4c1329 into master Aug 5, 2026
4 checks passed
@CMGS
CMGS deleted the fix/vcpu-host-capacity branch August 5, 2026 17:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

vm: vCPU-count validation reads the process affinity, not the host — a core-pinned control plane cannot clone multi-vCPU VMs

1 participant