Skip to content

[Backport 1.16] memory hotplug, vsock and CPU template fixes (#6076, #6100, #6120) - #6182

Merged
ilstam merged 10 commits into
firecracker-microvm:firecracker-v1.16from
ilstam:backport/v1.16-fixes
Sep 3, 2026
Merged

[Backport 1.16] memory hotplug, vsock and CPU template fixes (#6076, #6100, #6120)#6182
ilstam merged 10 commits into
firecracker-microvm:firecracker-v1.16from
ilstam:backport/v1.16-fixes

Conversation

@ilstam

@ilstam ilstam commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Changes

Backport to firecracker-v1.16 of three fixes from the UnreleasedFixed
section of main's changelog. The three series are independent of each other,
and each carries its own changelog entry into the existing ## [1.16.2]
section.

#6076
memory hotplug sizes wrapping from MiB to bytes

  • memory-hotplug: bound requested size to u32 (clean cherry-pick of
    aad75879f)
  • memory-hotplug: bound device config sizes to u32 (031a5fd6b) —
    src/vmm/src/utils/mod.rs has no tests module on this branch, since the
    align_up!/align_down! macro refactor is not backported, so the new
    conversion tests are wrapped in a new one.

#6100 — vsock
RX permanently suppressed after a bare pause/resume

  • fix(vsock): do not arm the TRANSPORT_RESET RX gate on bare resume
    (a34d51c93) — additionally bumps SNAPSHOT_VERSION, see below.
  • test(vsock): cover host-initiated connections after bare resume
    (2c4604808, clean)

#6120 — guest
CPUID must be installed before reading CPUID-gated MSRs

  • vmm: x86: cpu_config: split CPU template application stages (d46a5a210,
    clean)
  • vmm: x86: vcpu: split boot configuration stages (b85185750, clean)
  • vmm: x86: fix CPUID-dependent MSR read ordering (4681a67f7, clean)
  • vmm: x86: remove obsolete CPU configuration path (d9edec6f4) —
    EntryPoint has no setup_header field on this branch, since bzImage boot
    support is not backported, so that field is dropped from the updated tests.
  • tests: x86: verify CPUID-gated MSR passthrough (4aa9bb83c) — the test
    takes the guest_kernel_default fixture, since pin_guest_kernel() and
    GUEST_KERNEL_DEFAULT only exist on main.
  • test: x86: update T2CL MSR baselines (9c493b4da) — dropped the two
    *_6.18host_6.18guest.csv updates, since 6.18 guest kernels are not
    supported on this branch.

Every adaptation is also noted in the commit message of the commit it applies
to.

Reason

Three bug fixes that are already on main and apply to a supported release
branch:

  • #6076
    the MiB sizes accepted by PUT /hotplug/memory and PATCH /hotplug/memory
    were usize and shifted left by 20 to get a byte count, discarding the bits
    shifted out. A large enough size therefore wrapped: 2^44 MiB was accepted
    as a 0-byte region instead of being rejected.
  • #6100 — a
    bare pause/resume (PATCH /vm with Paused then Resumed, no snapshot
    involved) armed the TRANSPORT_RESET RX gate even though no reset event had
    been sent. The guest could never acknowledge it, so every new host-initiated
    vsock connection made after the resume hung forever. TX kept working, which
    makes the failure look RX-specific.
  • #6120
    since Linux 6.13, KVM returns zero when userspace reads a CPUID-gated MSR
    before guest CPUID advertises it. On 6.18 hosts Firecracker read the CPU
    template MSRs before installing guest CPUID, so passthrough bits preserved
    that zero: T2CL guests did not observe eIBRS and selected retpoline.

One consequence to be aware of when taking this into a patch release:
#6100 adds a
field to the persisted vsock device state, and the bitcode encoding used for
the microVM state does not allow backwards compatible changes. The same commit
therefore bumps SNAPSHOT_VERSION to 11.0.0, so snapshots do not interoperate
between 1.16.2 and 1.16.0/1.16.1. This is recorded in the changelog's Changed
section.

Testing

  • tools/devtool checkbuild --all passes (x86_64 and aarch64).
  • tools/devtool checkstyle passes.
  • cargo test -p vmm: the new test_persist_pending_event_ack and the
    snapshot:: and utils:: tests pass. The failures that remain
    (devices::virtio::mem::device, the two vsock::unix::muxer metrics tests,
    arch::x86_64::vcpu::tests::test_set_tsc and the persist:: tests failing on
    KVM SetUserMemoryRegion) reproduce identically on pristine
    firecracker-v1.16, so they are pre-existing and unrelated.
  • git range-diff against the original main commits shows no code drift
    beyond the adaptations documented above.
  • Integration tests were not run locally; they ran on the original PRs against
    main.

License Acceptance

By submitting this pull request, I confirm that my contribution is made under
the terms of the Apache 2.0 license. For more information on following Developer
Certificate of Origin and signing off your commits, please check
CONTRIBUTING.md.

PR Checklist

  • I have read and understand CONTRIBUTING.md.
  • I have run tools/devtool checkbuild --all to verify that the PR passes
    build checks on all supported architectures.
  • I have run tools/devtool checkstyle to verify that the PR passes the
    automated style checks.
  • I have described what is done in these changes, why they are needed, and
    how they are solving the problem in a clear and encompassing way.
  • I have updated any relevant documentation (both in code and in the docs)
    in the PR.
  • I have mentioned all user-facing changes in CHANGELOG.md.
  • If a specific issue led to this PR, this PR closes the issue.
  • When making API changes, I have followed the
    Runbook for Firecracker API changes.
  • I have tested all new and changed functionalities in unit tests and/or
    integration tests.
  • I have linked an issue to every new TODO.

  • This functionality cannot be added in rust-vmm.

@ilstam ilstam added the Status: Awaiting review Indicates that a pull request is ready to be reviewed label Sep 2, 2026
@codecov

codecov Bot commented Sep 2, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.50350% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.07%. Comparing base (eec3484) to head (d890461).

Files with missing lines Patch % Lines
src/vmm/src/devices/virtio/vsock/device.rs 66.66% 2 Missing ⚠️
src/vmm/src/arch/x86_64/mod.rs 97.29% 1 Missing ⚠️
src/vmm/src/builder.rs 87.50% 1 Missing ⚠️
src/vmm/src/lib.rs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@                  Coverage Diff                  @@
##           firecracker-v1.16    #6182      +/-   ##
=====================================================
+ Coverage              83.04%   83.07%   +0.03%     
=====================================================
  Files                    277      277              
  Lines                  30196    30228      +32     
=====================================================
+ Hits                   25075    25111      +36     
+ Misses                  5121     5117       -4     
Flag Coverage Δ
5.10-m5n.metal 83.31% <96.50%> (+0.02%) ⬆️
5.10-m6a.metal 82.66% <96.50%> (+0.02%) ⬆️
5.10-m6g.metal 79.93% <91.11%> (+0.02%) ⬆️
5.10-m6i.metal 83.32% <96.50%> (+0.04%) ⬆️
5.10-m7a.metal-48xl 82.65% <96.50%> (+0.03%) ⬆️
5.10-m7g.metal 79.93% <91.11%> (+0.02%) ⬆️
5.10-m7i.metal-24xl 83.29% <96.50%> (+0.03%) ⬆️
5.10-m7i.metal-48xl 83.29% <96.50%> (+0.03%) ⬆️
5.10-m8g.metal-24xl 79.93% <91.11%> (+0.02%) ⬆️
5.10-m8g.metal-48xl 79.93% <91.11%> (+0.02%) ⬆️
5.10-m8i.metal-48xl 83.29% <96.50%> (+0.03%) ⬆️
5.10-m8i.metal-96xl 83.29% <96.50%> (+0.02%) ⬆️
6.1-m5n.metal 83.35% <96.50%> (+0.04%) ⬆️
6.1-m6a.metal 82.69% <96.50%> (+0.03%) ⬆️
6.1-m6g.metal 79.93% <91.11%> (+0.02%) ⬆️
6.1-m6i.metal 83.34% <96.50%> (+0.03%) ⬆️
6.1-m7a.metal-48xl 82.68% <96.50%> (+0.03%) ⬆️
6.1-m7g.metal 79.93% <91.11%> (+0.02%) ⬆️
6.1-m7i.metal-24xl 83.35% <96.50%> (+0.03%) ⬆️
6.1-m7i.metal-48xl 83.35% <96.50%> (+0.02%) ⬆️
6.1-m8g.metal-24xl 79.93% <91.11%> (+0.02%) ⬆️
6.1-m8g.metal-48xl 79.93% <91.11%> (+0.02%) ⬆️
6.1-m8i.metal-48xl 83.36% <96.50%> (+0.03%) ⬆️
6.1-m8i.metal-96xl 83.36% <96.50%> (+0.03%) ⬆️
6.18-m5n.metal 83.35% <96.50%> (+0.04%) ⬆️
6.18-m6a.metal 82.69% <96.50%> (+0.03%) ⬆️
6.18-m6g.metal 80.02% <91.11%> (+0.02%) ⬆️
6.18-m6i.metal 83.34% <96.50%> (+0.03%) ⬆️
6.18-m7a.metal-48xl 82.68% <96.50%> (+0.03%) ⬆️
6.18-m7g.metal 80.02% <91.11%> (+0.02%) ⬆️
6.18-m7i.metal-24xl 83.36% <96.50%> (+0.03%) ⬆️
6.18-m7i.metal-48xl 83.36% <96.50%> (+0.03%) ⬆️
6.18-m8g.metal-24xl 80.02% <91.11%> (+0.02%) ⬆️
6.18-m8g.metal-48xl 80.02% <91.11%> (+0.02%) ⬆️
6.18-m8i.metal-48xl 83.35% <96.50%> (+0.02%) ⬆️
6.18-m8i.metal-96xl 83.36% <96.50%> (+0.03%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

zulinx86
zulinx86 previously approved these changes Sep 3, 2026

@zulinx86 zulinx86 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

approved the CPU template handling fix on 6.18. please obtain an approval from the person who can review the remaining part.

Manciukic
Manciukic previously approved these changes Sep 3, 2026
JackThomson2 and others added 10 commits September 3, 2026 12:02
Memory hotplug resize requests used usize, allowing a MiB value to
overflow when converted to bytes.

Use u32 for requested_size_mib throughout the API, VMM, and virtio-mem
update path. The resulting maximum of just under 4 PiB always fits in a
u64 byte count, so explicit conversion validation is unnecessary.

Document the API range and test the accepted and rejected boundaries.

[cherry picked from commit aad7587]
Signed-off-by: Jack Thomson <jackabt@amazon.com>
The previous commit bounded requested_size_mib, but the sizes accepted
by PUT /hotplug/memory were still usize. mib_to_bytes shifts left by 20
and discards the bits shifted out, so a large enough total_size_mib
wrapped to a smaller byte count: 2^44 MiB became a 0-byte region.

Use u32 for total_size_mib, block_size_mib and slot_size_mib,
matching requested_size_mib and the balloon's amount_mib. Since
u32::MAX MiB is just under 4 PiB, every accepted value fits a u64 byte
count, so the wrap becomes unrepresentable at deserialization rather
than something to check for later.

Route the conversions through u32_mib_to_bytes and bytes_to_u32_mib,
which widen before shifting, so the MiB conversion is no longer
open-coded.

Document the ranges in the API spec and record the behaviour change in
the changelog.

[cherry picked from commit 031a5fd]
Signed-off-by: Jack Thomson <jackabt@amazon.com>
The resume kick unconditionally armed `pending_event_ack`, the gate
that suppresses RX delivery until the guest acknowledges a
TRANSPORT_RESET event. On a bare pause/resume no such event was ever
published, so the guest could never acknowledge it, the gate never
cleared, and every new host-initiated connection made after the resume
hung forever. TX kept working, which made the failure look RX-specific.

Persist `pending_event_ack` in the vsock frontend snapshot state and
make the resume kick respect the restored value instead of arming it:
the event queue is only re-signaled when a reset ack is actually
outstanding, and a bare resume leaves RX untouched.

[Ilias: This changes the layout of VsockFrontendState, which is a
snapshot format change on an already released format. SNAPSHOT_VERSION
is therefore bumped to 11.0.0 here as well. Snapshots created by 1.16.2
can not be loaded by 1.16.0 or 1.16.1, and snapshots created by those
versions can not be loaded by 1.16.2.]

[cherry picked from commit a34d51c]
Signed-off-by: Dov Alperin <git@dov.dev>
Add an integration test that pauses and resumes a microVM without
snapshotting and checks that fresh host-initiated (RX direction)
connections still work afterwards, alongside guest-initiated ones.

[Conflicts: context only, on main the following test is pinned with
@pin_guest_kernel(ACPI_GUEST_KERNELS), which does not exist on this
branch.]

[cherry picked from commit 2c46048]
Signed-off-by: Dov Alperin <git@dov.dev>
Split CPU template application into independent CPUID and MSR
transformations while keeping CpuConfiguration::apply_template() as a
compatibility wrapper.

This is a preparatory refactor for a follow-up fix. The fix needs to
apply CPUID and MSR template modifiers at different points during vCPU
configuration. Exposing the transformations independently lets the
follow-up commit correct the ordering without duplicating template
logic.

Add focused tests for both transformations, including exact output
values and unsupported-register errors.

No functional change is intended.

[cherry picked from commit d46a5a2]
Signed-off-by: Takahiro Itazuri <itazur@amazon.com>
Extract CPUID setup, MSR setup, and the remaining Linux boot state from
KvmVcpu::configure(), and keep configure() as a compatibility wrapper.

This is a preparatory refactor for a follow-up fix. The fix needs to
install CPUID on every vCPU before reading CPUID-dependent MSRs, such as
IA32_ARCH_CAPABILITIES, from vCPU 0. Exposing the operations
independently lets the follow-up commit correct the ordering.

Return the installed KVM CPUID from configure_cpuid() so MSR snapshot
bookkeeping continues to use the exact per-vCPU CPUID and preserves the
existing MSR save-list order.

No functional change is intended.

[cherry picked from commit b851857]
Signed-off-by: Takahiro Itazuri <itazur@amazon.com>
KVM's feature MSR series [1] made userspace accesses to
CPUID-dependent MSRs subject to architectural existence checks.
Userspace must install guest CPUID with KVM_SET_CPUID{,2} before
reading such MSRs with KVM_GET_MSRS. If guest CPUID does not advertise
a feature, KVM returns zero when userspace reads the corresponding MSR
that KVM advertised as supported.

The KVM maintainer deferred documenting this behavior until KVM's
internal MSR handling is fully converted to KVM_MSR_RET_UNSUPPORTED [3].
The documentation update has not landed as of Linux 6.18.

This behavior landed in Linux 6.13 through commit [2], and is therefore
present in Firecracker's supported 6.18 host kernel. Firecracker read
CPU template MSRs from vCPU 0 before installing guest CPUID. On T2CL,
KVM_GET_MSRS consequently returned zero for IA32_ARCH_CAPABILITIES. The
template's passthrough mask preserved the zero IBRS_ALL bit, and the
later KVM_SET_MSRS overwrote KVM's post-CPUID value. The guest did not
observe eIBRS support and selected retpoline.

Correct CPU configuration ordering as follows:

1. Apply CPUID modifiers.
2. Install each vCPU's normalized CPUID with KVM_SET_CPUID2.
3. Retrieve CPUID-dependent MSRs from vCPU 0 with KVM_GET_MSRS.
4. Apply MSR modifiers.
5. Add Linux boot MSRs and update CPUID-derived MSR snapshot
   bookkeeping.
6. Install each vCPU's MSRs with KVM_SET_MSRS.

[1]: https://lore.kernel.org/all/20240802185511.305849-1-seanjc@google.com/
[2]: torvalds/linux@a5d5638
[3]: https://lore.kernel.org/kvm/Zivh0IaAmHsEOLFc@google.com/

[cherry picked from commit 4681a67]
Signed-off-by: Takahiro Itazuri <itazur@amazon.com>
Remove the CpuConfiguration and KvmVcpu compatibility wrappers left
after wiring staged CPUID and MSR configuration into the x86 cold boot
path.

Update x86 tests to exercise the staged operations directly.
CpuConfiguration remains available for CPU configuration dumps, and
VcpuConfig remains available for aarch64 boot configuration.

[cherry picked from commit d9edec6]
Signed-off-by: Takahiro Itazuri <itazur@amazon.com>
Add an integration test that verifies CPU templates preserve passthrough
bits from a CPUID-gated MSR.

Compare a live IA32_ARCH_CAPABILITIES value from a no-template guest
against a custom template that flips bit 0 and passes all other bits
through. On Linux 6.13 and later, KVM returns zero when userspace reads
IA32_ARCH_CAPABILITIES before guest CPUID advertises it [1]. The test
therefore covers the requirement that Firecracker install guest CPUID
before reading the base MSR values used for template application.

[1]: torvalds/linux@a5d5638

[The test fixture consolidation is not backported, so pin_guest_kernel()
and GUEST_KERNEL_DEFAULT do not exist here and the test takes the
guest_kernel_default fixture instead. Also,
framework.utils_cpu_templates only provides get_cpu_template_name on
this branch.]

[cherry picked from commit 4aa9bb8]
Signed-off-by: Takahiro Itazuri <itazur@amazon.com>
Refresh the T2CL baselines for Cascade Lake and Ice Lake after
Firecracker sets each vCPU's CPUID before retrieving MSRs to be modified
by CPU templates.

The corrected output exposes IA32_SPEC_CTRL and IA32_TSX_CTRL and
records the post-CPUID IA32_ARCH_CAPABILITIES values instead of zero
across guest kernels 5.10, 6.1, and 6.18.

For each CPU model, all three MSR results match the corresponding Linux
6.1 host baselines. This confirms that the ordering fix restores the
established T2CL behavior on Linux 6.18 hosts.

[Dropped the two *_6.18host_6.18guest.csv baseline updates, since 6.18
guest kernels are not supported on this branch.]

[cherry picked from commit 9c493b4]
Signed-off-by: Takahiro Itazuri <itazur@amazon.com>
@ilstam
ilstam dismissed stale reviews from Manciukic and zulinx86 via d890461 September 3, 2026 11:09
@ilstam
ilstam force-pushed the backport/v1.16-fixes branch from fbe30bc to d890461 Compare September 3, 2026 11:09
@ilstam
ilstam enabled auto-merge (rebase) September 3, 2026 11:43
@ilstam
ilstam merged commit 12006e8 into firecracker-microvm:firecracker-v1.16 Sep 3, 2026
7 checks passed
@ilstam
ilstam deleted the backport/v1.16-fixes branch September 3, 2026 12:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Status: Awaiting review Indicates that a pull request is ready to be reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants