Thanks to visit codestin.com
Credit goes to github.com

Skip to content

vmm: add memory reserve option to opt out of MAP_NORESERVE - #8350

Merged
rbradford merged 2 commits into
cloud-hypervisor:mainfrom
iandk:pr/memory-reserve
Jun 10, 2026
Merged

rbradford merged 2 commits into
cloud-hypervisor:mainfrom
iandk:pr/memory-reserve

Conversation

@iandk

@iandk iandk commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a reserve=on|off option to --memory and --memory-zone (default
off). When enabled, guest RAM is mapped without MAP_NORESERVE, so the
kernel reserves the backing pages (swap, or huge pages for hugepage-backed
memory) at mmap time. An over-committed configuration then fails cleanly at
VM creation with an mmap ENOMEM instead of succeeding and later delivering a
SIGBUS to the guest.

Default off preserves today's behaviour exactly.

Motivation

Cloud Hypervisor maps guest RAM with MAP_NORESERVE, so the kernel never
reserves the backing pages up front. With hugepage-backed memory on a host whose
pool cannot satisfy every guest, the VM boots fine and then dies with SIGBUS
the moment the guest faults a page the pool can no longer back. This is the
failure mode in #5730 and #7387.

As noted on #5730, checking free hugepage headroom before boot is not a reliable
fix, because another process can consume pages between the check and the fault:

Even if CH were to check that there were enough at start, if you started
another program that also wanted free pages ... then there would still be
starvation and you would get SIGBUS during the running of your process.

reserve=on sidesteps that race: the reservation is made by the kernel
atomically with the mmap, so the pages are committed to this mapping and
cannot be stolen. Over-booking is reported as a clean ENOMEM at create time,
where the caller can handle it, rather than as a guest crash later.

Design

  • Mirrors QEMU's memory-backend reserve property, which carries the same
    name and meaning (reserve=off maps with MAP_NORESERVE). CH keeps the
    default at off to preserve existing behaviour; QEMU defaults to on.
  • The single load-bearing change is in create_ram_region:
    let mut mmap_flags = if reserve { 0 } else { libc::MAP_NORESERVE };
  • Threaded through the same mmap paths as the existing prefault option (boot,
    restore, hotplug), carried on the runtime MemoryZone.
  • Unlike prefault, it does not populate or fault the memory in, so it does not
    slow down boot; it only reserves.
  • Works at both --memory (global) and --memory-zone granularity. The
    top-level --memory reserve=on path is unchanged: the default zone is
    synthesised from MemoryConfig and inherits its reserve value.

Included

  • --memory / --memory-zone parsing and CLI help
  • MemoryConfig / MemoryZoneConfig fields (serde, default false)
  • OpenAPI schema (MemoryConfig, MemoryZoneConfig)
  • docs/memory.md (### reserve for both, mirroring ### prefault)
  • Unit tests for reserve=on parsing (global and per-zone)

Testing

  • cargo +nightly fmt --all --check: clean
  • cargo test -p vmm test_mem: passes (global and per-zone reserve=on parse)
  • Validated against the real memfd + MAP_SHARED hugepage path: with
    reserve=on an over-booking mmap returns ENOMEM; with reserve=off
    (default) the same config maps successfully and the guest takes SIGBUS on
    fault. A CH functional test over-booking a hugepage zone returns
    Mmap(OutOfMemory) at create with reserve=on, and is unchanged with
    reserve=off.

Notes

  • Hugepage reservations are pool-level; this does not add per-NUMA-node
    accounting beyond what the kernel already does for a bound mapping.
  • reserve is a --memory / --memory-zone option only; it is not a restore
    option and does not interact with --restore prefault.

@iandk
iandk marked this pull request as ready for review June 8, 2026 18:38
@iandk
iandk requested a review from a team as a code owner June 8, 2026 18:38
@iandk
iandk force-pushed the pr/memory-reserve branch 2 times, most recently from 5b5083f to 2018879 Compare June 8, 2026 19:31

@phip1611 phip1611 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This looks sensible to me and the writeup is nice - thanks! I think this could also be useful for us.

I'll wait with my approval as I'd like to hear @rbradford opinion first

Comment thread docs/memory.md

### `reserve`

Specifies if the memory for this zone should be `mmap(2)`-ed _without_ the

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Not sure if a duplicate section here make sense - perhaps we can have on generic reserve section and then link to it?

Not sure what the best thing is to do here. In case other sections are also already duplicated here, I'm fine with it

Comment thread vmm/src/memory_manager.rs
thp: bool,
) -> Result<MmapRegion<AtomicBitmap>, Error> {
let mut mmap_flags = libc::MAP_NORESERVE;
let mut mmap_flags = if reserve { 0 } else { libc::MAP_NORESERVE };

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd like to understand why CH decided to go with libc::MAP_NORESERVE in the first place. @rbradford

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It's been like that since the beginning and that came from vm-memory defaults. It does allow overcommit strategies - for huge pages it might make sense to default to on. Something to consider in the future.

@rbradford rbradford left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks!

@rbradford

Copy link
Copy Markdown
Member

Maybe we should make the huge page integration tests turn this on since that's the most likely place to use them?

@iandk
iandk force-pushed the pr/memory-reserve branch from 2018879 to dd14d37 Compare June 10, 2026 11:24
@iandk

iandk commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

Maybe we should make the huge page integration tests turn this on since that's the most likely place to use them?

Yes, I agree that's a good idea. I've updated the integration test to address this.

@rbradford

Copy link
Copy Markdown
Member

The change to the integration test should probably be a separate commit.

iandk added 2 commits June 10, 2026 12:37
Cloud Hypervisor maps guest RAM with MAP_NORESERVE, so the kernel never
reserves the backing pages at mmap time. On a host whose hugepage pool
cannot satisfy every guest, a VM is created successfully and then takes
a SIGBUS when the guest faults a page the pool can no longer back. This
is the failure mode reported in cloud-hypervisor#5730 and cloud-hypervisor#7387. As noted on cloud-hypervisor#5730,
checking free pool headroom up front is not a reliable fix: another
process can consume pages between the check and the fault.

Add a reserve=on parameter to --memory and --memory-zone (default off,
preserving the current MAP_NORESERVE behaviour). When set, the region
is mapped without MAP_NORESERVE, so the kernel reserves the backing
pages (swap, or huge pages for hugepage-backed memory) at mmap time,
atomically with the mapping. An over-committed configuration then
fails cleanly at VM creation with an mmap ENOMEM instead of crashing
the guest later. Unlike prefault it does not fault the memory in, so
it does not slow down boot.

This mirrors QEMU's memory-backend reserve property, which has the same
name and meaning (reserve=off maps with MAP_NORESERVE). reserve is
threaded through the same mmap paths as the existing prefault option,
and is exposed in the OpenAPI schema, CLI help and docs. The top-level
--memory reserve=on path is unchanged: the default zone is synthesised
from MemoryConfig and inherits its reserve value.

Assisted-by: Claude Code (Opus 4.8)
Signed-off-by: Ian Klemm <[email protected]>
Turn reserve=on for the hugepage-backed memory zone in the UFFD
snapshot/restore integration test. Hugepages are the most likely place
to want reserve (an over-committed huge page pool is exactly the case
that otherwise SIGBUSes the guest), so this is the natural test to give
the option real coverage, as suggested in review.

It exercises the reserve mmap path twice: once on the source VM boot and
once on the demand-paged restore. The existing skip guard already
requires the 256 free 2MiB pages this zone needs, and the source VM is
killed before the restore VM is started, so reserving from the pool
never has to back two VMs at once.

Assisted-by: Claude Code (Opus 4.8)
Signed-off-by: Ian Klemm <[email protected]>
@iandk
iandk force-pushed the pr/memory-reserve branch from dd14d37 to 10d190d Compare June 10, 2026 11:37
@rbradford
rbradford enabled auto-merge June 10, 2026 11:57
@rbradford
rbradford added this pull request to the merge queue Jun 10, 2026
Merged via the queue into cloud-hypervisor:main with commit e8e532f Jun 10, 2026
41 checks passed
@github-project-automation github-project-automation Bot moved this from 🆕 New to ✅ Done in Cloud Hypervisor Roadmap Jul 8, 2026
@rbradford rbradford added the new-feature New feature to include in release notes label Jul 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new-feature New feature to include in release notes

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

3 participants