Skip to content

feat(proxmox): give guest disks a dedicated IO thread - #352

Merged
v0l merged 1 commit into
masterfrom
feat/iothread-virtio-scsi-single
Aug 2, 2026
Merged

feat(proxmox): give guest disks a dedicated IO thread#352
v0l merged 1 commit into
masterfrom
feat/iothread-virtio-scsi-single

Conversation

@v0l

@v0l v0l commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Problem

Every VM is created with scsihw: virtio-scsi-pci and no iothread, so all guest block IO is serialised through QEMU's main event loop — the same thread that services device emulation and networking. That caps a guest at roughly one thread's worth of storage throughput regardless of how fast the host pool actually is.

Measured on a production host (R740xd, 12x U.2 NVMe):

Layer Throughput
Raw NVMe device, 1M blocks QD1 1.7 GB/s
ZFS zvol, 4M blocks 3.0 GB/s
8 parallel zvol streams 8.2 GB/s aggregate
In-guest ~250 MiB/s

The drives are healthy (2–3% wear after 4.3 years, 100% spare, 23°C) and the pool is at ~0.4% of its IOPS capability. The bottleneck was entirely the guest disk configuration.

On the affected host: 0 of 70 VMs had iothread=1, and 68 of 71 used virtio-scsi-pci, which cannot support it.

Change

  • make_config now emits scsihw: virtio-scsi-single — the only SCSI controller type qemu-server accepts iothreads on.
  • import_disk_image adds iothread=1 to the scsi0 device string at VM creation.
  • apply_disk_limitsapply_disk_options, and it no longer returns early when a template has no throttle limits. Without that, VMs without limits would never converge onto iothread=1.

Rollout behaviour

Existing VMs pick up the new settings the next time their config is reconciled. A SCSI controller change only takes effect at VM start, so an already-running VM keeps its current behaviour until it is stopped and started — a guest-initiated reboot is not enough. No mass restart is triggered by this PR.

Mid-transition VMs are safe: qemu-server warns and ignores iothread on controllers other than virtio-scsi-single rather than erroring —

} elsif ($drive->{iothread}) {
    warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n"

So a VM whose config has iothread=1 but is still running the old controller simply ignores the flag until its next start.

Tests

  • test_make_config_uses_virtio_scsi_single — guards the controller/iothread pairing from drifting apart.
  • test_apply_disk_options_sets_iothread_without_limits — covers the removed early-return; asserts a PATCH is still issued and the bare volume ref is preserved.
  • test_apply_disk_options_preserves_ssd_params — existing regression test, extended to assert iothread=1.

cargo test -p lnvps_api_common --features proxmox → 359 passed, 0 failed. cargo clippy and cargo fmt --check clean.

API impact

None — no request or response shape changed. Documented in API_CHANGELOG.md under Unreleased.

@v0l v0l added enhancement New feature or request host:proxmox labels Aug 2, 2026
VMs were created with the `virtio-scsi-pci` controller and no iothread, so
every guest's block IO was serialised through the main QEMU event loop
alongside device emulation and networking. That caps a guest at roughly one
thread of storage throughput no matter how fast the host pool is — measured
~250 MiB/s in-guest against a pool benchmarking at 8+ GB/s aggregate.

Switch `scsihw` to `virtio-scsi-single` (the only SCSI controller type that
supports iothreads) and set `iothread=1` on scsi0, both at import time and in
the config reconcile path.

`apply_disk_limits` is renamed to `apply_disk_options` and no longer returns
early when a template carries no throttle limits, otherwise VMs without limits
would never converge onto `iothread=1`.

Existing VMs pick this up on the next config reconcile; the controller change
only takes effect at VM start, so a running VM keeps its old behaviour until
stopped and started. qemu-server warns and ignores `iothread` on other
controller types, so a VM caught mid-transition is never invalid.
@v0l
v0l force-pushed the feat/iothread-virtio-scsi-single branch from e427264 to 0cfc90c Compare August 2, 2026 18:29
@v0l
v0l enabled auto-merge (squash) August 2, 2026 18:30
@v0l
v0l disabled auto-merge August 2, 2026 18:57
@v0l
v0l merged commit 2219a60 into master Aug 2, 2026
5 of 6 checks passed
@v0l
v0l deleted the feat/iothread-virtio-scsi-single branch August 2, 2026 18:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request host:proxmox

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant