Compare commits

...

162 Commits
v49.0 ... v50.0

Author SHA1 Message Date
Bo Chen
9a24680abd build: Release v50.0
Signed-off-by: Bo Chen <bchen@crusoe.ai>
2025-12-19 00:08:01 +00:00
Thomas Prescher
736813f90c tests: add live disk resize test
This test verifies that we can grow and shrink
disk images during runtime.

On-behalf-of: SAP thomas.prescher@sap.com
Signed-off-by: Thomas Prescher <thomas.prescher@cyberus-technology.de>
2025-12-17 13:54:52 +00:00
Thomas Prescher
b15459106c docs: update vm.resize-disk
On-behalf-of: SAP thomas.prescher@sap.com
Signed-off-by: Thomas Prescher <thomas.prescher@cyberus-technology.de>
2025-12-17 13:54:52 +00:00
Thomas Prescher
5fb078305a ch-remote: support live disk resizing
Support disk resizing via ch-remote and REST api.

On-behalf-of: SAP thomas.prescher@sap.com
Signed-off-by: Thomas Prescher <thomas.prescher@cyberus-technology.de>
2025-12-17 13:54:52 +00:00
Thomas Prescher
aac240d076 block: raw_async: implement disk resizing
Support for resize events for raw_async disks.

On-behalf-of: SAP thomas.prescher@sap.com
Signed-off-by: Thomas Prescher <thomas.prescher@cyberus-technology.de>
2025-12-17 13:54:52 +00:00
Thomas Prescher
37d71fa038 vmm: disk resize infrastructure
Add basic infrastructure so resize events are
propagated to the underlying disk implementation.

On-behalf-of: SAP thomas.prescher@sap.com
Signed-off-by: Thomas Prescher <thomas.prescher@cyberus-technology.de>
2025-12-17 13:54:52 +00:00
Thomas Prescher
8e52bf251b block: virtio-devices: make disk_nsectors a shared atomic
This change is a prerequisite for live disk resizing. Before this
commit, the epoll-handler threads just got a copy of the sector
size which we cannot update during runtime.

On-behalf-of: SAP thomas.prescher@sap.com
Signed-off-by: Thomas Prescher <thomas.prescher@cyberus-technology.de>
2025-12-17 13:54:52 +00:00
Anatol Belski
d75bd1675c performance-metrics: Add QCOW2 backing file performance test
Add sequential and random read performance tests for QCOW2 overlays
with QCOW2 backing files.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2025-12-16 21:49:54 +00:00
Anatol Belski
d696cea024 performance-metrics: Refactor fio_control to BlockControl
Introduce a new BlockControl struct to encapsulate fio operation
parameters. This replaces the tuple-based fio_control with a more
extensible structure that includes:
- fio_ops: The FIO operation type
- bandwidth: Whether to measure bandwidth or IOPS
- test_file: The file path to test against

This refactoring enables reusing performance_block_io with different
test files.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2025-12-16 21:49:54 +00:00
Philipp Schuster
7288031c0e misc: slightly improve feature list readability
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-12-14 17:05:49 +00:00
Philipp Schuster
82e8002fa0 misc: clippy: remove some overrides
Closes #4986 [0].

[0]: https://github.com/cloud-hypervisor/cloud-hypervisor/issues/4986

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-12-14 17:05:49 +00:00
Pascal Scholz
a8d1411307 vmm: Write directly to member when creating new devices
Virtio PCI devices are created in a set of nested functions. In each
of this functions a vector is created to add created devices to, only
to be appended to the vector of the higher nesting level. Those nested
vectors are unnecessary as we can directly write to the member of
`DeviceManager`.

Signed-off-by: Pascal Scholz <pascal.scholz@cyberus-technology.de>
On-behalf-of: SAP pascal.scholz@sap.com
2025-12-14 17:04:23 +00:00
Philipp Schuster
9569809d4c block: fix bug with wrong lock granularity for image container formats
The lock must always correspond to the physical size of the file,
everything else doesn't make sense.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-12-14 17:02:36 +00:00
Philipp Schuster
603b5e862c block: add DiskFile::physical_size()
This is a pre-requisite for the bug fix in the following commit.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-12-14 17:02:36 +00:00
Philipp Schuster
53092359b4 block: rename DiskFile::size() -> DiskFile::logical_size()
This better reflects the actual usage.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-12-14 17:02:36 +00:00
dependabot[bot]
0ddb032cab build: Bump actions/upload-artifact from 5 to 6
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-13 00:22:02 +00:00
Oliver Anderson
bcc6ac68e9 seccomp: Add KVM_GET_XSAVE2 for amx state
Signed-off-by: Oliver Anderson <oliver.anderson@cyberus-technology.de>
Signed-off-by: Songqian Li <sionli@tencent.com>
2025-12-11 17:14:13 +00:00
Songqian Li
4b4954ff86 hypervisor: AMX state snapshot and restore support
The TILE data state of AMX may require 8KB+ space, calling the legacy
KVM_GET_XSAVE will encounter an error since KVM_GET_XSAVE only can get
4KB space. This patch adds KVM_GET_XSAVE2 support to allow snapping more
data.

Fixes: #7533

Signed-off-by: Songqian Li <sionli@tencent.com>
2025-12-11 17:14:13 +00:00
Anatol Belski
5c5f33050c block: qcow: Refactor pointer table writes to use iterators
Refactor write_pointer_table to accept iterators instead of requiring
materialized vectors, eliminating temporary allocations in L1 table
sync operations.

Changes:
- Modified write_pointer_table() to take Iterator<Item = &T> and
  dereference internally before passing owned values to the callback
- Added write_pointer_table_direct() convenience wrapper for cases
  without value transformation
- Updated sync_caches() to use l1_table.iter() directly instead of
  .get_values().iter().copied()
- Implemented Deref<Target = [T]> for VecCache to enable direct .iter()

Performance impact:
- Eliminates L1 table allocation during sync (~2KB per 100GB disk)
- L2 and refcount table writes already used slices, no change there
- Zero performance overhead: iterator dereferencing is equivalent to
  .copied() and optimizes identically

The L1 sync previously collected entries into a Vec to apply the
OFLAG_COPIED flag. The new iterator+callback pattern computes this
on-the-fly, avoiding the allocation entirely.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2025-12-10 23:35:46 +00:00
Anatol Belski
be5b14ef3a block: qcow: Implement Deref for VecCache
Add Deref<Target = [T]> implementation for VecCache<T> to allow direct
slice operations without explicitly calling get_values(). This enables
cleaner code patterns like cache.iter() instead
of cache.get_values().iter().

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2025-12-10 23:35:46 +00:00
Anatol Belski
9dc923f379 seccomp: Allow fcntl in virtio-block thread
Add fcntl to virtio_block_thread_rules to allow try_clone() on file
descriptors. The try_clone() method uses fcntl(fd, F_DUPFD_CLOEXEC)
to duplicate file descriptors, which is needed for efficient QCOW2
L1 table sync that avoids temporary allocations.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2025-12-10 23:35:46 +00:00
Sebastien Boeuf
f57b9b2359 tests: Re-enable test_vdpa_net
Creating a vdpa_net with an associated MAC address and setting the right
amount of queues in order to fix the integration test related to
vdpa_net.

Fixes: #5756

Signed-off-by: Sebastien Boeuf <seb@rivosinc.com>
2025-12-10 11:43:45 +00:00
Philipp Schuster
6bda6541be vmm: cleanup &Mutex parameters
In [0] we refactored some Arc<Mutex<T>> parameters to &Mutex<T>> to
satisfy clippy's needless_pass_by_value lint. Nevertheless, this is also
not so idiomatic, so as a follow-up, we put the responsibility to lock
objects to the caller side (only where this is not strictly needed by
the callee).

While on it, I also tried to pass vm_config directly into
pre_create_console_devices() which would clean up some code, but then
we have interleaving mutable and immutable borrows of the Vmm, which
are denied by the borrow checker.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-12-10 11:06:29 +00:00
Stefan Nürnberger
4592f37bcf tests: integration: expect some ksm merged pages
Our CI test execution system finds some mergeable pages in the system
directly on boot since a recent update. Remove the broken assumption in
the test_memory_mergeable integration test and only check if the guest
VMs influence the shared pages count.

Signed-off-by: Stefan Nürnberger <stefan.nuernberger@cyberus-technology.de>
2025-12-09 23:29:07 +00:00
Connor Brewster
41a8dcd9ba block: allow VIRTIO_BLK_T_GET_ID for read-only devices
https://github.com/cloud-hypervisor/cloud-hypervisor/pull/7294 adjusted
the checks for read-only requests made to virtio-blk devices and started
rejecting VIRTIO_BLK_T_GET_ID requests. These requests do not perform
any writes and are needed in order to access device serials from within
the guest.

Signed-off-by: Connor Brewster <cbrewster@hey.com>
2025-12-09 16:22:46 +00:00
Oliver Anderson
8de24b5f08 vmm: Fix clippy lints
This PR fixes some clippy lints in the vmm crate.

Signed-off-by: Oliver Anderson <oliver.anderson@cyberus-technology.de>
On-behalf-of: SAP oliver.anderson@sap.com
2025-12-09 16:14:44 +00:00
Philipp Schuster
0be7d1bd82 ci: replace cargo rustc -> cargo build to support virtual manifests
`cargo rustc` is incompatible with virtual manifests, so the CI needs to
 use cargo build instead. However, passing `RUSTFLAGS="-D warnings"` via
 the environment would propagate to all dependencies, and some of them
 currently fail to build under ``-D warnings` due to issues like [0]:

```
error: creating a mutable reference to mutable static
  --> src/temp.rs:97:5
   |
97 |     DIRS.pop()
   |     ^^^^^^^^^^ mutable reference to mutable static
```

To resolve this, apply ``-D warnings` only to the `cargo clippy`
commands (which apply to our workspace only) and avoid enforcing it for
the entire cargo build.

[0]: https://github.com/cloud-hypervisor/cloud-hypervisor/actions/runs/19962283528/job/57245376263?pr=7525

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-12-09 16:13:10 +00:00
Philipp Schuster
3191ff26e1 docs: adjust contributing.md: remove need for --all (--workspace)
It is no longer needed to add `--all` (which is an alias for
`--workspace`). The documentation says "Commands run in the workspace
root will run against all workspace members by default" [0].

We however still need `--tests` as this activates the building of
tests in `<crate>/tests` directories.

[0] https://doc.rust-lang.org/cargo/reference/workspaces.html#virtual-workspace

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-12-09 16:13:10 +00:00
Philipp Schuster
9979e562b2 docs: adjust contributing.md: fix missing --all
Unrelated but necessary to also always format code for all
architectures and all features.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-12-09 16:13:10 +00:00
Philipp Schuster
70146ee7af test_infra: Adapt to workspace + make code more robust
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-12-09 16:13:10 +00:00
Philipp Schuster
3d049765bd build: decouple Cargo.toml: split crate and workspace definitions
TL;DR: cargo clippy|check|... now runs on whole workspace by default.

## Steps

- add new workspace member `cloud-hypervisor`
- move `./src` to new workspace member
- move `./tests` to new workspace member
- move relevant parts from Cargo.toml to new workspace member
- kept necessary parts in main Cargo.toml, such as profile
  configurations

## About

The main Cargo.toml historically mixes workspace and crate definitions
for cloud-hypervisor and ch-remote. This makes it hard to read and
requires `--workspace` to run cargo clippy or cargo test on all
workspace members, which is counter-intuitive.

This patch separates the workspace from the crate definition in the main
Cargo.toml file. After this, cargo clippy, cargo test, etc., work on the
whole workspace naturally, giving a smoother developer experience. The
Cargo.toml without a package definition is also called a virtual
workspace or virtual manifest by Cargo [0].

Backporting is not a concern: CHV no longer backports, but the affected
files are rarely modified anyway.

[0] https://doc.rust-lang.org/cargo/reference/workspaces.html#virtual-workspace

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-12-09 16:13:10 +00:00
Philipp Schuster
f104bcdb6b build: remove useless build scripts (copy & paste artifact)
This will also prevent some useless rebuilds. Using `--verbose` we can
observe that the build.rs causes frequent useless rebuilds - having
less is a good thing. They come from the dependency of `build.rs` to
the local git repository.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-12-09 16:13:10 +00:00
Philipp Schuster
265d21b0c4 misc: improve test idempotence (unrelated improvement)
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-12-09 16:13:10 +00:00
Anatol Belski
562af123d5 block: qcow: Add missing flush in write_refcount_block
The BufWriter must be flushed explicitly to handle errors
properly. Without explicit flush, errors during the implicit
drop flush are ignored.

This is the same issue fixed for write_pointer_table
in commit 85556951a.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2025-12-09 14:51:54 +00:00
dependabot[bot]
f0dfa2a5ef build: Bump the non-rust-vmm group across 2 directories with 16 updates
Bumps the non-rust-vmm group with 12 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [serde_with](https://github.com/jonasbb/serde_with) | `3.16.0` | `3.16.1` |
| [flume](https://github.com/zesterer/flume) | `0.11.1` | `0.12.0` |
| [libc](https://github.com/rust-lang/libc) | `0.2.177` | `0.2.178` |
| [log](https://github.com/rust-lang/log) | `0.4.28` | `0.4.29` |
| [uuid](https://github.com/uuid-rs/uuid) | `1.18.1` | `1.19.0` |
| [zerocopy](https://github.com/google/zerocopy) | `0.8.30` | `0.8.31` |
| [cc](https://github.com/rust-lang/cc-rs) | `1.2.47` | `1.2.49` |
| [endi](https://github.com/zeenix/endi) | `1.1.0` | `1.1.1` |
| [simd-adler32](https://github.com/mcountryman/simd-adler32) | `0.3.7` | `0.3.8` |
| [toml_edit](https://github.com/toml-rs/toml) | `0.23.7` | `0.23.9` |
| [tracing](https://github.com/tokio-rs/tracing) | `0.1.41` | `0.1.43` |
| [winnow](https://github.com/winnow-rs/winnow) | `0.7.13` | `0.7.14` |

Bumps the non-rust-vmm group with 10 updates in the /fuzz directory:

| Package | From | To |
| --- | --- | --- |
| [serde_with](https://github.com/jonasbb/serde_with) | `3.16.0` | `3.16.1` |
| [flume](https://github.com/zesterer/flume) | `0.11.1` | `0.12.0` |
| [libc](https://github.com/rust-lang/libc) | `0.2.177` | `0.2.178` |
| [log](https://github.com/rust-lang/log) | `0.4.28` | `0.4.29` |
| [uuid](https://github.com/uuid-rs/uuid) | `1.18.1` | `1.19.0` |
| [zerocopy](https://github.com/google/zerocopy) | `0.8.30` | `0.8.31` |
| [cc](https://github.com/rust-lang/cc-rs) | `1.2.47` | `1.2.49` |
| [simd-adler32](https://github.com/mcountryman/simd-adler32) | `0.3.7` | `0.3.8` |
| [toml_edit](https://github.com/toml-rs/toml) | `0.23.7` | `0.23.9` |
| [winnow](https://github.com/winnow-rs/winnow) | `0.7.13` | `0.7.14` |



Updates `serde_with` from 3.16.0 to 3.16.1
- [Release notes](https://github.com/jonasbb/serde_with/releases)
- [Commits](https://github.com/jonasbb/serde_with/compare/v3.16.0...v3.16.1)

Updates `flume` from 0.11.1 to 0.12.0
- [Changelog](https://github.com/zesterer/flume/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zesterer/flume/commits)

Updates `libc` from 0.2.177 to 0.2.178
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.178/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.177...0.2.178)

Updates `log` from 0.4.28 to 0.4.29
- [Release notes](https://github.com/rust-lang/log/releases)
- [Changelog](https://github.com/rust-lang/log/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/log/compare/0.4.28...0.4.29)

Updates `uuid` from 1.18.1 to 1.19.0
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/v1.18.1...v1.19.0)

Updates `zerocopy` from 0.8.30 to 0.8.31
- [Release notes](https://github.com/google/zerocopy/releases)
- [Changelog](https://github.com/google/zerocopy/blob/main/CHANGELOG.md)
- [Commits](https://github.com/google/zerocopy/compare/v0.8.30...v0.8.31)

Updates `cc` from 1.2.47 to 1.2.49
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.47...cc-v1.2.49)

Updates `endi` from 1.1.0 to 1.1.1
- [Release notes](https://github.com/zeenix/endi/releases)
- [Commits](https://github.com/zeenix/endi/compare/1.1.0...1.1.1)

Updates `serde_with_macros` from 3.16.0 to 3.16.1
- [Release notes](https://github.com/jonasbb/serde_with/releases)
- [Commits](https://github.com/jonasbb/serde_with/compare/v3.16.0...v3.16.1)

Updates `simd-adler32` from 0.3.7 to 0.3.8
- [Changelog](https://github.com/mcountryman/simd-adler32/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mcountryman/simd-adler32/commits)

Updates `toml_edit` from 0.23.7 to 0.23.9
- [Commits](https://github.com/toml-rs/toml/compare/v0.23.7...v0.23.9)

Updates `tracing` from 0.1.41 to 0.1.43
- [Release notes](https://github.com/tokio-rs/tracing/releases)
- [Commits](https://github.com/tokio-rs/tracing/compare/tracing-0.1.41...tracing-0.1.43)

Updates `tracing-attributes` from 0.1.30 to 0.1.31
- [Release notes](https://github.com/tokio-rs/tracing/releases)
- [Commits](https://github.com/tokio-rs/tracing/compare/tracing-attributes-0.1.30...tracing-attributes-0.1.31)

Updates `tracing-core` from 0.1.34 to 0.1.35
- [Release notes](https://github.com/tokio-rs/tracing/releases)
- [Commits](https://github.com/tokio-rs/tracing/compare/tracing-core-0.1.34...tracing-core-0.1.35)

Updates `winnow` from 0.7.13 to 0.7.14
- [Changelog](https://github.com/winnow-rs/winnow/blob/main/CHANGELOG.md)
- [Commits](https://github.com/winnow-rs/winnow/compare/v0.7.13...v0.7.14)

Updates `zerocopy-derive` from 0.8.30 to 0.8.31
- [Release notes](https://github.com/google/zerocopy/releases)
- [Changelog](https://github.com/google/zerocopy/blob/main/CHANGELOG.md)
- [Commits](https://github.com/google/zerocopy/compare/v0.8.30...v0.8.31)

Updates `serde_with` from 3.16.0 to 3.16.1
- [Release notes](https://github.com/jonasbb/serde_with/releases)
- [Commits](https://github.com/jonasbb/serde_with/compare/v3.16.0...v3.16.1)

Updates `flume` from 0.11.1 to 0.12.0
- [Changelog](https://github.com/zesterer/flume/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zesterer/flume/commits)

Updates `libc` from 0.2.177 to 0.2.178
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.178/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.177...0.2.178)

Updates `log` from 0.4.28 to 0.4.29
- [Release notes](https://github.com/rust-lang/log/releases)
- [Changelog](https://github.com/rust-lang/log/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/log/compare/0.4.28...0.4.29)

Updates `uuid` from 1.18.1 to 1.19.0
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/v1.18.1...v1.19.0)

Updates `zerocopy` from 0.8.30 to 0.8.31
- [Release notes](https://github.com/google/zerocopy/releases)
- [Changelog](https://github.com/google/zerocopy/blob/main/CHANGELOG.md)
- [Commits](https://github.com/google/zerocopy/compare/v0.8.30...v0.8.31)

Updates `cc` from 1.2.47 to 1.2.49
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.47...cc-v1.2.49)

Updates `serde_with_macros` from 3.16.0 to 3.16.1
- [Release notes](https://github.com/jonasbb/serde_with/releases)
- [Commits](https://github.com/jonasbb/serde_with/compare/v3.16.0...v3.16.1)

Updates `simd-adler32` from 0.3.7 to 0.3.8
- [Changelog](https://github.com/mcountryman/simd-adler32/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mcountryman/simd-adler32/commits)

Updates `toml_edit` from 0.23.7 to 0.23.9
- [Commits](https://github.com/toml-rs/toml/compare/v0.23.7...v0.23.9)

Updates `winnow` from 0.7.13 to 0.7.14
- [Changelog](https://github.com/winnow-rs/winnow/blob/main/CHANGELOG.md)
- [Commits](https://github.com/winnow-rs/winnow/compare/v0.7.13...v0.7.14)

Updates `zerocopy-derive` from 0.8.30 to 0.8.31
- [Release notes](https://github.com/google/zerocopy/releases)
- [Changelog](https://github.com/google/zerocopy/blob/main/CHANGELOG.md)
- [Commits](https://github.com/google/zerocopy/compare/v0.8.30...v0.8.31)

---
updated-dependencies:
- dependency-name: serde_with
  dependency-version: 3.16.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: flume
  dependency-version: 0.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-rust-vmm
- dependency-name: libc
  dependency-version: 0.2.178
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: log
  dependency-version: 0.4.29
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: uuid
  dependency-version: 1.19.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-rust-vmm
- dependency-name: zerocopy
  dependency-version: 0.8.31
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: cc
  dependency-version: 1.2.49
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: endi
  dependency-version: 1.1.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: serde_with_macros
  dependency-version: 3.16.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: simd-adler32
  dependency-version: 0.3.8
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: toml_edit
  dependency-version: 0.23.9
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: tracing
  dependency-version: 0.1.43
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: tracing-attributes
  dependency-version: 0.1.31
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: tracing-core
  dependency-version: 0.1.35
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: winnow
  dependency-version: 0.7.14
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: zerocopy-derive
  dependency-version: 0.8.31
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: serde_with
  dependency-version: 3.16.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: flume
  dependency-version: 0.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-rust-vmm
- dependency-name: libc
  dependency-version: 0.2.178
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: log
  dependency-version: 0.4.29
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: uuid
  dependency-version: 1.19.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-rust-vmm
- dependency-name: zerocopy
  dependency-version: 0.8.31
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: cc
  dependency-version: 1.2.49
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: serde_with_macros
  dependency-version: 3.16.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: simd-adler32
  dependency-version: 0.3.8
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: toml_edit
  dependency-version: 0.23.9
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: winnow
  dependency-version: 0.7.14
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: zerocopy-derive
  dependency-version: 0.8.31
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-09 00:29:41 +00:00
Muminul Islam
7c8372452b tests: disable live-upgrade tests for MSHV
These tests are expected to fail.

See: #7542

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2025-12-07 01:29:56 +00:00
Muminul Islam
f795081bf9 hypervisor: mshv: retrieve MSRs list correctly
The MSR enumeration logic in MSHV does not accurately
account for the capabilities of the underlying
hardware and hypervisor. Previously, integration tests
passed because only the default MSRs—universally supported
across platforms—were involved. However, recent feature
additions in MSHV have introduced MSRs that are not
supported on Intel hardware, causing failures.

This patch retrieves the MSRs from the VM specific
API call that filters out the unsupported MSRs.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2025-12-07 01:29:56 +00:00
Anatol Belski
c940f6642f block: qcow: Refactor refcount update into helper method
Add set_cluster_refcount_track_freed() helper to consolidate the
common pattern of setting a cluster refcount and tracking freed
refblocks. This reduces code duplication and improves readability.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2025-12-06 17:10:48 +00:00
Anatol Belski
f56adb8a5a tests: Fix path handling for qemu-img check
The image passed for the guest construction is copied. Previously,
check-img has been checking the unchanged image from the workspace dir,
which is supposed to be error free.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2025-12-05 15:38:55 +00:00
Anatol Belski
e6dd429a64 tests: qcow: Add testing for uncompressed backing file
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2025-12-05 15:38:55 +00:00
Anatol Belski
248e786363 tests: qcow: Adjust namings for zstd compresed backing file
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2025-12-05 15:38:55 +00:00
Anatol Belski
f1ffd795e0 block: qcow: tests: Update combo_write_read for cluster leak fixes
Freed clusters correctly have refcount=0. Remove the assertion that
expected no clusters with zero refcount, as it was validating the
buggy behavior.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2025-12-05 15:38:55 +00:00
Anatol Belski
efad6578d1 block: qcow: Fix refcount leak when converting compressed clusters
When converting a compressed cluster to standard during write
operations, the old compressed cluster's refcount was never
decremented, causing leak warnings by `qemu-img check ..`

`Leaked cluster X refcount=N reference=M`

Additionally, compressed data can span multiple physical clusters,
not just one. The compressed cluster address and size are encoded
in the L2 entry, and the data may cross cluster boundaries.

The proper handling is implemented as follows:
- Extract compressed cluster address and size before overwriting
  L2 entry
- Identify all clusters occupied by the compressed data
- Decrement refcount for each cluster in the range

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2025-12-05 15:38:55 +00:00
Anatol Belski
9e2e85a48f block: qcow: Fix refcount leak when refcount blocks are replaced
When a refcount block is evicted from cache and replaced with a new
one, the old refcount block cluster was added to unref_clusters but
its refcount was never decremented to 0 on disk. This left the cluster
with refcount=1 while no metadata referenced it, causing errors in
qemu-img check

`Leaked cluster X refcount=1 reference=0`

This fix recursively calls set_cluster_refcount(freed_cluster, 0) to
properly decrement the freed refcount block's refcount on disk. The
recursion handles cascading replacements where freeing one refcount
block may trigger the replacement of another.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2025-12-05 15:38:55 +00:00
Philipp Schuster
f7edfefe42 ci: dco: rename misleading job title
"Signed-off-by" is the only variant that is accepted. So we
should remove the inconsistency to prevent:

- user forgets this at all
- CI complains
- user adds "Signed-Off-By"
- CI still complains because of the wrong format

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-12-05 12:54:25 +00:00
Sebastien Boeuf
801059c2d5 scripts: Update custom image to Ubuntu Noble Numbat
Updating the helper script to create a VFIO custom image from Ubuntu
22.04 to Ubuntu 24.04.

Signed-off-by: Sebastien Boeuf <seb@rivosinc.com>
2025-12-04 15:25:13 +00:00
Oliver Anderson
5ec1e66e22 vmm: Refactor amx tile state component enabling logic
We enable AMX tile state components via the hypervisor (as introduced
in the previous commit) instead of doing this inline in the body of
`CpuManager::new`.

Signed-off-by: Oliver Anderson <oliver.anderson@cyberus-technology.de>
On-behalf-of: SAP oliver.anderson@sap.com
2025-12-04 14:04:11 +00:00
Oliver Anderson
01383538f3 hypervisor: Introduce an enable AMX tile state components method
Currently when the user configures AMX the corresponding state
components get dynamically enabled directly inside the function body of
vmm::cpu::CpuManager::new.

With our ongoing work on CPU templates/profiles, there will (likely) be
one more binary crate for producing CPU profiles that also needs to do
this (without creating a CpuManager) and it may also be the case that
we will need to call this function prior to `CpuManager::new` during
live migrations.

We thus add a method for enabling the AMX tile state components on the
hypervisor trait that may be called wherever necessary. We argue that
this is beneficial for code clarity independently of the upcoming CPU
templates/profiles PR that we are working on.

The astute reader will notice that the logic introduced here is not 100%
the same as what is done inside the vmm::cpu::Cpumanager::new method. We
claim that our approach is more in-line with the official documentation.

Signed-off-by: Oliver Anderson <oliver.anderson@cyberus-technology.de>
On-behalf-of: SAP oliver.anderson@sap.com
2025-12-04 14:04:11 +00:00
Muminul Islam
5fb50edb55 docs: update guide for nested CPU feature
This patch updates the documentation to reflect the newly added
nested CPU feature option in the CLI.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2025-12-03 09:56:58 +00:00
Muminul Islam
658a7f9175 arch: vmm: disable nested virtualization if needed
User can now disable nested virtualization for Intel and AMD
if configured by the CLI.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2025-12-03 09:56:58 +00:00
Muminul Islam
d8360ddc8e hypervisor: vmm: passing nested argument from VMM to hypervisor
This patch connects the VMM and hypervisor to fully enable nested
support for MSHV.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2025-12-03 09:56:58 +00:00
Muminul Islam
f10d0bb33d vmm: add nested option to CPU config
Add an option in the CLI to enable nested support.
Adding an option --cpu nested=on|off to the CPU
argument to enable nested support for Microsoft
Hypervisor. By default it is enabled for both KVM
and MSHV.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2025-12-03 09:56:58 +00:00
Muminul Islam
0d5c914bdd build: use latest 0.6.5 mshv crates
Use mshv-{ioctls, bindings) with the latest versions
that have the nested MSHV support.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2025-12-03 09:56:58 +00:00
Muminul Islam
deaf660a52 vmm: simplify VM creation API
Create HypervisorVmConfig early and pass the
struct to VM creation API in the vmm crate. Getting
rid of multiple conditional parameter.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2025-12-03 09:56:58 +00:00
Anatol Belski
6897c2a462 block: qcow: Set OFLAG_COPIED bit in L1 entries for spec compliance
The OFLAG_COPIED bit (bit 63) indicates a cluster's refcount is exactly
1 and doesn't need copy-on-write. This bit must be set in L1 entries
when their referenced L2 clusters have refcount=1.

Previously, L1 entries were always written as raw addresses without the
OFLAG_COPIED bit, violating the QCOW2 specification and causing qemu-img
check to report errors like

`ERROR OFLAG_COPIED L2 cluster: l1_index=X .... refcount=1`

The implementation queries each L2 cluster's refcount in sync_caches()
and sets OFLAG_COPIED appropriately when writing the L1 table. This
ensures QCOW2 images are specification compliant and maintain correct
COW semantics to avoid data corruption.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2025-12-01 16:45:55 +00:00
Wei Liu
85556951a6 block: qcow2: Flush the buffer explicitly when writing pointer table
Previously the code relies on the implicit flush when BufWriter is
dropped. That's not safe.

Per BufWriter's document:

```
It is critical to call flush before BufWriter<W> is dropped. Though
dropping will attempt to flush the contents of the buffer, any errors
that happen in the process of dropping will be ignored. Calling flush
ensures that the buffer is empty and thus dropping will not even attempt
file operations.
```

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-11-30 18:39:49 +00:00
Rob Bradford
4abebc9e56 hypervisor: Don't create temporary vector for boot MSRs
The MSRs are constant at boot time so rather than creating a vector in
the boot_msr_entries() method instead reaturn a reference to static MSR
array data.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-11-29 13:07:16 +00:00
Philipp Schuster
a91235dab1 vm-migration: better describe migration protocol
Reflect the latest migration protocol as mermaid diagrams in the
(code) documentation.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-28 08:41:47 +00:00
Julian Stecklina
dbb148b216 vmm: refactor live migration receive into state machine
Previously, state that we accumulated during the migration process in
the receiver was kept in `mut Option` variables or HashMaps. The
problem is that it is unclear in the code when these variables can be
safely used. It's also difficult to add new state, such as the state
we need to handle the upcoming feature for performing the migration
using multiple connections.

To solve this, I've refactored the code to use the state machine
pattern. Each state carries the data it needs to. Any state that
didn't arrive yet (memory_files, memory_manager) cannot be accessed
until we are in the proper state.

Some benefits that fall out of this:

- We now respond to all requests, even invalid ones, at least with an
  error message.
- Any error handling a request will result in an error message being
  sent.
- There is only a single place where responses are sent and thus it's
  very hard to mess this up in the code.
- The main protocol state machine fits on a screen.

I would argue that especially the error cases are now much more
consistent. There is still a lot to be done. There is still state
transfer via self.vm and similar. In an ideal world, this would also
be carried by the state machine. I also want to see better handling of
payloads, which are still handled all over the place, but this change
is already too big. :)

Co-authored-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP julian.stecklina@sap.com
On-behalf-of: SAP philipp.schuster@sap.com
Signed-off-by: Julian Stecklina <julian.stecklina@cyberus-technology.de>
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
2025-11-28 08:41:47 +00:00
Julian Stecklina
1861bc49e7 vmm: simplify receiving memory fds
... and nuke some Option<> while I was there. Given that HashMap has a
usable default and we end up passing an empty HashMap anyway, just get
rid of the Option.

On-behalf-of: SAP julian.stecklina@sap.com
Signed-off-by: Julian Stecklina <julian.stecklina@cyberus-technology.de>
2025-11-28 08:41:47 +00:00
Julian Stecklina
3d43245608 vmm: allow comparing commands and extracting response length
This will be useful later when we rebuild the live migration code as a
state machine.

On-behalf-of: SAP julian.stecklina@sap.com
Signed-off-by: Julian Stecklina <julian.stecklina@cyberus-technology.de>
2025-11-28 08:41:47 +00:00
Muminul Islam
b163fea66a hypervisor: update cache when a shared page is revoked
During the lifecycle of a confidential VM, the guest may revoke
previously shared pages via an attribute-intercept VM exit.
When this happens, the host-side cache must be updated so that any
subsequent access by the VMM triggers a fresh request for the guest
to re-share the page.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2025-11-28 04:42:20 +00:00
Philipp Schuster
afcb2b285f tpm: remove mixture of str and Path
`impl AsRef<Path>` is the most idiomatic way to consume paths
in Rust. I removed the mixture.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-27 17:11:14 +00:00
Philipp Schuster
c53781bf5f misc: clippy: add needless_pass_by_value
This is a follow-up of [0].

# Advantages

- This saves dozens of unneeded clone()s across the whole code base
- Makes it much easier to reason about how parameters are used
  (often we passed owned Arc/Rc versions without actually needing
  ownership)

# Exceptions

For certain code paths, the alternatives would require awkward or overly
complex code, and in some cases the functions are the logical owners of
the values they take. In those cases, I've added
#[allow(clippy::needless_pass_by_value)].

This does not mean that one should not improve this in the future.

[0] 6a86c157af

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-27 17:11:14 +00:00
Praveen K Paladugu
ed4af3a005 vmm: fix the initial flush while using PTY
Fix the condition to correctly identify a new PTY connection.

Fixes: 287887c99 (vmm: fix console IO safety)
Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com>
2025-11-27 08:28:44 +00:00
Praveen K Paladugu
ac5fc69b2e vmm: Fix fd leak in socket connection handling
Previously, `into_raw_fd()` transferred fd ownership to epoll while
keeping separate clones in `reader` and `writer`, causing leaks when
the stream was closed. Now, `reader` owns the fd and epoll borrows it.
When the FD is closed in the kernel, reader will be reset to None.

Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com>
2025-11-27 08:28:44 +00:00
Oliver Anderson
0d884d3f50 arch: Mask (out) extended AMX features
The Intel Granite Rapids processors include more AMX related features
that are advertised in leaf 0x7 subleaf 0x1. If the VM is not
configured to support AMX (the default) then these feature bits need
to be masked out.

Furthermore Tile information and TMUL information
in leaves 0x1d and 0x1e respectively are also purely related to AMX
and should also be zeroed whenever AMX support is disabled.

Signed-off-by: Oliver Anderson <oliver.anderson@cyberus-technology.de>
On-behalf-of: SAP <oliver.anderson@sap.com>
2025-11-27 08:27:43 +00:00
dependabot[bot]
8e5dd296de build: Bump crate-ci/typos from 1.39.2 to 1.40.0
Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.39.2 to 1.40.0.
- [Release notes](https://github.com/crate-ci/typos/releases)
- [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crate-ci/typos/compare/v1.39.2...v1.40.0)

---
updated-dependencies:
- dependency-name: crate-ci/typos
  dependency-version: 1.40.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-27 00:07:30 +00:00
Wei Liu
2f8edc182e performance-metrics: Respect queue size in block tests
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-11-26 17:43:12 +00:00
Songqian Li
41382879d3 seccomp: add arch_prctl syscall for amx
When enabling amx feature, we should call arch_prctl to request
permission to use tile data for guest. The permission should be
requested before the first vcpu is created, so we need to call
arch_prctl in vmm thread. This patch adds the arch_prctl syscall for
vmm_thread_rules.

Fixes: #7516

Signed-off-by: Songqian Li <sionli@tencent.com>
2025-11-26 13:53:02 +00:00
Chengyu Fu
e7cda177cc hypervisor: kvm: Remove unnecessary .to_vec() in set_state
.. to avoid copy elements.

Signed-off-by: Chengyu Fu <chengyu.fu@linux.alibaba.com>
2025-11-26 09:13:10 +00:00
Rob Bradford
e3fb425615 event_monitor: Send events to info! level logging
The resulting output looks like:

Event: source = virtio-device event = activated id = _disk0

See: #7484

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-11-25 22:06:40 +00:00
Philipp Schuster
6a86c157af misc: clippy: add needless_pass_by_value (partially)
This helps to uncover expensive and needless clones in the code base.
For example, I prevented extensive clones in the snapshot path where
(nested) BTreeMap's have been cloned over and over again. Further,
the lint helps devs to much better reason about the ownership of
parameters.

All of these changes have been done manually with the necessary
caution. A few structs that are cheap to clone are now `copy` so that
this lint won't trigger for them.

I didn't enable the lint so far as it is a massive rabbit hole and
needs much more fixes. Nevertheless, it is very useful.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-25 16:05:46 +00:00
Philipp Schuster
0a07c96d17 misc: clippy: add if_not_else
This removes cognitive load when reading if statements.
All changes were applied by clippy via `--fix`.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-25 16:05:46 +00:00
Philipp Schuster
a0b72dce22 misc: clippy: add redundant_else
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-25 16:05:46 +00:00
Philipp Schuster
d2b19bb969 misc: clippy: add map_unwrap_or
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-25 16:05:46 +00:00
Wei Liu
dda89d7027 tests: Check disk consistency after use
We've encountered issues that Cloud Hypervisor corrupts disk images
after use. Those issues may not be immediately obvious until the
corrupted images are used again.

Run consistency checks over the disk images in the test cases to catch
issues as early as possible.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-11-25 15:59:39 +00:00
Wei Liu
a1a018bd83 tests: Do not return a failure when no tests are run
It is a common use case to run a subset of tests locally to verify
certain functionalities.

The default behaviour for nextest is to error out if no tests are run.
That causes the test scripts to return a non-zero value (failure). Pass
`--no-tests=pass` to nextest to match what `cargo test` does if no tests
are run.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-11-25 15:59:39 +00:00
Julian Stecklina
8c50450002 vmm: don't needlessly clone strings
On-behalf-of: SAP julian.stecklina@sap.com
Signed-off-by: Julian Stecklina <julian.stecklina@cyberus-technology.de>
2025-11-25 15:58:31 +00:00
Philipp Schuster
7443a9f69e misc: fix typo and wording
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-25 15:58:31 +00:00
Philipp Schuster
28b54df01d vmm: cleanup: replace map_err misuse with inspect_err
This is continuing the work from [0]. Some places in CHV
"misuse" Result::map_err for side-effects. inspect_err is
a better suited alternative for exactly that use-case.

Unfortunately, there is no clippy lint for this yet.

[0] f02745a7ed

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-25 15:58:31 +00:00
dependabot[bot]
4e93f85ab1 build: Bump the non-rust-vmm group across 2 directories with 38 updates
Bumps the non-rust-vmm group with 28 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [zbus](https://github.com/z-galaxy/zbus) | `5.11.0` | `5.12.0` |
| [serde_with](https://github.com/jonasbb/serde_with) | `3.15.0` | `3.16.0` |
| [bitflags](https://github.com/bitflags/bitflags) | `2.9.4` | `2.10.0` |
| [cfg-if](https://github.com/rust-lang/cfg-if) | `1.0.3` | `1.0.4` |
| [clap](https://github.com/clap-rs/clap) | `4.5.49` | `4.5.53` |
| [zerocopy](https://github.com/google/zerocopy) | `0.8.27` | `0.8.30` |
| [io-uring](https://github.com/tokio-rs/io-uring) | `0.7.10` | `0.7.11` |
| [num_enum](https://github.com/illicitonion/num_enum) | `0.7.4` | `0.7.5` |
| [getrandom](https://github.com/rust-random/getrandom) | `0.3.3` | `0.3.4` |
| [landlock](https://github.com/landlock-lsm/rust-landlock) | `0.4.3` | `0.4.4` |
| [aho-corasick](https://github.com/BurntSushi/aho-corasick) | `1.1.3` | `1.1.4` |
| [anstyle-query](https://github.com/rust-cli/anstyle) | `1.1.4` | `1.1.5` |
| [anstyle-wincon](https://github.com/rust-cli/anstyle) | `3.0.10` | `3.0.11` |
| [cc](https://github.com/rust-lang/cc-rs) | `1.2.41` | `1.2.47` |
| [hashbrown](https://github.com/rust-lang/hashbrown) | `0.16.0` | `0.16.1` |
| [indexmap](https://github.com/indexmap-rs/indexmap) | `2.11.4` | `2.12.1` |
| [is_terminal_polyfill](https://github.com/polyfill-rs/is_terminal_polyfill) | `1.70.1` | `1.70.2` |
| [jiff](https://github.com/BurntSushi/jiff) | `0.2.15` | `0.2.16` |
| [libz-sys](https://github.com/rust-lang/libz-sys) | `1.1.22` | `1.1.23` |
| [once_cell_polyfill](https://github.com/polyfill-rs/once_cell_polyfill) | `1.70.1` | `1.70.2` |
| [openssl-src](https://github.com/alexcrichton/openssl-src-rs) | `300.5.3+3.5.4` | `300.5.4+3.5.4` |
| [openssl-sys](https://github.com/rust-openssl/rust-openssl) | `0.9.109` | `0.9.111` |
| [proc-macro2](https://github.com/dtolnay/proc-macro2) | `1.0.101` | `1.0.103` |
| [quote](https://github.com/dtolnay/quote) | `1.0.41` | `1.0.42` |
| [signal-hook-registry](https://github.com/vorner/signal-hook) | `1.4.6` | `1.4.7` |
| [syn](https://github.com/dtolnay/syn) | `2.0.106` | `2.0.111` |
| [unicode-ident](https://github.com/dtolnay/unicode-ident) | `1.0.19` | `1.0.22` |
| [zvariant](https://github.com/dbus2/zbus) | `5.7.0` | `5.8.0` |

Bumps the non-rust-vmm group with 20 updates in the /fuzz directory:

| Package | From | To |
| --- | --- | --- |
| [serde_with](https://github.com/jonasbb/serde_with) | `3.15.0` | `3.16.0` |
| [bitflags](https://github.com/bitflags/bitflags) | `2.9.4` | `2.10.0` |
| [cfg-if](https://github.com/rust-lang/cfg-if) | `1.0.3` | `1.0.4` |
| [clap](https://github.com/clap-rs/clap) | `4.5.49` | `4.5.53` |
| [zerocopy](https://github.com/google/zerocopy) | `0.8.27` | `0.8.30` |
| [num_enum](https://github.com/illicitonion/num_enum) | `0.7.4` | `0.7.5` |
| [landlock](https://github.com/landlock-lsm/rust-landlock) | `0.4.3` | `0.4.4` |
| [anstyle-query](https://github.com/rust-cli/anstyle) | `1.1.4` | `1.1.5` |
| [anstyle-wincon](https://github.com/rust-cli/anstyle) | `3.0.10` | `3.0.11` |
| [cc](https://github.com/rust-lang/cc-rs) | `1.2.41` | `1.2.47` |
| [hashbrown](https://github.com/rust-lang/hashbrown) | `0.16.0` | `0.16.1` |
| [indexmap](https://github.com/indexmap-rs/indexmap) | `2.11.4` | `2.12.1` |
| [is_terminal_polyfill](https://github.com/polyfill-rs/is_terminal_polyfill) | `1.70.1` | `1.70.2` |
| [once_cell_polyfill](https://github.com/polyfill-rs/once_cell_polyfill) | `1.70.1` | `1.70.2` |
| [proc-macro2](https://github.com/dtolnay/proc-macro2) | `1.0.101` | `1.0.103` |
| [quote](https://github.com/dtolnay/quote) | `1.0.41` | `1.0.42` |
| [signal-hook-registry](https://github.com/vorner/signal-hook) | `1.4.6` | `1.4.7` |
| [syn](https://github.com/dtolnay/syn) | `2.0.106` | `2.0.111` |
| [unicode-ident](https://github.com/dtolnay/unicode-ident) | `1.0.19` | `1.0.22` |
| [windows-sys](https://github.com/microsoft/windows-rs) | `0.60.2` | `0.61.2` |



Updates `zbus` from 5.11.0 to 5.12.0
- [Release notes](https://github.com/z-galaxy/zbus/releases)
- [Commits](https://github.com/z-galaxy/zbus/compare/zbus-5.11.0...zbus-5.12.0)

Updates `serde_with` from 3.15.0 to 3.16.0
- [Release notes](https://github.com/jonasbb/serde_with/releases)
- [Commits](https://github.com/jonasbb/serde_with/compare/v3.15.0...v3.16.0)

Updates `bitflags` from 2.9.4 to 2.10.0
- [Release notes](https://github.com/bitflags/bitflags/releases)
- [Changelog](https://github.com/bitflags/bitflags/blob/main/CHANGELOG.md)
- [Commits](https://github.com/bitflags/bitflags/compare/2.9.4...2.10.0)

Updates `cfg-if` from 1.0.3 to 1.0.4
- [Release notes](https://github.com/rust-lang/cfg-if/releases)
- [Changelog](https://github.com/rust-lang/cfg-if/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cfg-if/compare/v1.0.3...v1.0.4)

Updates `clap` from 4.5.49 to 4.5.53
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.49...clap_complete-v4.5.53)

Updates `zerocopy` from 0.8.27 to 0.8.30
- [Release notes](https://github.com/google/zerocopy/releases)
- [Changelog](https://github.com/google/zerocopy/blob/main/CHANGELOG.md)
- [Commits](https://github.com/google/zerocopy/compare/v0.8.27...v0.8.30)

Updates `io-uring` from 0.7.10 to 0.7.11
- [Commits](https://github.com/tokio-rs/io-uring/commits/v0.7.11)

Updates `num_enum` from 0.7.4 to 0.7.5
- [Commits](https://github.com/illicitonion/num_enum/compare/0.7.4...0.7.5)

Updates `getrandom` from 0.3.3 to 0.3.4
- [Release notes](https://github.com/rust-random/getrandom/releases)
- [Changelog](https://github.com/rust-random/getrandom/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-random/getrandom/compare/v0.3.3...v0.3.4)

Updates `landlock` from 0.4.3 to 0.4.4
- [Release notes](https://github.com/landlock-lsm/rust-landlock/releases)
- [Changelog](https://github.com/landlock-lsm/rust-landlock/blob/main/CHANGELOG.md)
- [Commits](https://github.com/landlock-lsm/rust-landlock/compare/v0.4.3...v0.4.4)

Updates `aho-corasick` from 1.1.3 to 1.1.4
- [Commits](https://github.com/BurntSushi/aho-corasick/compare/1.1.3...1.1.4)

Updates `anstyle-query` from 1.1.4 to 1.1.5
- [Commits](https://github.com/rust-cli/anstyle/compare/anstyle-query-v1.1.4...anstyle-query-v1.1.5)

Updates `anstyle-wincon` from 3.0.10 to 3.0.11
- [Commits](https://github.com/rust-cli/anstyle/compare/anstyle-wincon-v3.0.10...anstyle-wincon-v3.0.11)

Updates `cc` from 1.2.41 to 1.2.47
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.41...cc-v1.2.47)

Updates `clap_builder` from 4.5.49 to 4.5.53
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v4.5.49...v4.5.53)

Updates `find-msvc-tools` from 0.1.4 to 0.1.5
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/find-msvc-tools-v0.1.4...find-msvc-tools-v0.1.5)

Updates `hashbrown` from 0.16.0 to 0.16.1
- [Release notes](https://github.com/rust-lang/hashbrown/releases)
- [Changelog](https://github.com/rust-lang/hashbrown/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/hashbrown/compare/v0.16.0...v0.16.1)

Updates `indexmap` from 2.11.4 to 2.12.1
- [Changelog](https://github.com/indexmap-rs/indexmap/blob/main/RELEASES.md)
- [Commits](https://github.com/indexmap-rs/indexmap/compare/2.11.4...2.12.1)

Updates `is_terminal_polyfill` from 1.70.1 to 1.70.2
- [Changelog](https://github.com/polyfill-rs/is_terminal_polyfill/blob/main-v1.70/CHANGELOG.md)
- [Commits](https://github.com/polyfill-rs/is_terminal_polyfill/compare/v1.70.1...v1.70.2)

Updates `jiff` from 0.2.15 to 0.2.16
- [Release notes](https://github.com/BurntSushi/jiff/releases)
- [Changelog](https://github.com/BurntSushi/jiff/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/jiff/compare/jiff-static-0.2.15...jiff-static-0.2.16)

Updates `jiff-static` from 0.2.15 to 0.2.16
- [Release notes](https://github.com/BurntSushi/jiff/releases)
- [Changelog](https://github.com/BurntSushi/jiff/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/jiff/compare/jiff-static-0.2.15...jiff-static-0.2.16)

Updates `libz-sys` from 1.1.22 to 1.1.23
- [Release notes](https://github.com/rust-lang/libz-sys/releases)
- [Commits](https://github.com/rust-lang/libz-sys/compare/1.1.22...1.1.23)

Updates `num_enum_derive` from 0.7.4 to 0.7.5
- [Commits](https://github.com/illicitonion/num_enum/compare/0.7.4...0.7.5)

Updates `once_cell_polyfill` from 1.70.1 to 1.70.2
- [Changelog](https://github.com/polyfill-rs/once_cell_polyfill/blob/v1.70.2/CHANGELOG.md)
- [Commits](https://github.com/polyfill-rs/once_cell_polyfill/compare/v1.70.1...v1.70.2)

Updates `openssl-src` from 300.5.3+3.5.4 to 300.5.4+3.5.4
- [Release notes](https://github.com/alexcrichton/openssl-src-rs/releases)
- [Commits](https://github.com/alexcrichton/openssl-src-rs/commits)

Updates `openssl-sys` from 0.9.109 to 0.9.111
- [Release notes](https://github.com/rust-openssl/rust-openssl/releases)
- [Commits](https://github.com/rust-openssl/rust-openssl/compare/openssl-sys-v0.9.109...openssl-sys-v0.9.111)

Updates `proc-macro2` from 1.0.101 to 1.0.103
- [Release notes](https://github.com/dtolnay/proc-macro2/releases)
- [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.101...1.0.103)

Updates `quote` from 1.0.41 to 1.0.42
- [Release notes](https://github.com/dtolnay/quote/releases)
- [Commits](https://github.com/dtolnay/quote/compare/1.0.41...1.0.42)

Updates `serde_with_macros` from 3.15.0 to 3.16.0
- [Release notes](https://github.com/jonasbb/serde_with/releases)
- [Commits](https://github.com/jonasbb/serde_with/compare/v3.15.0...v3.16.0)

Updates `signal-hook-registry` from 1.4.6 to 1.4.7
- [Changelog](https://github.com/vorner/signal-hook/blob/master/CHANGELOG.md)
- [Commits](https://github.com/vorner/signal-hook/compare/registry-v1.4.6...registry-v1.4.7)

Updates `syn` from 2.0.106 to 2.0.111
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.106...2.0.111)

Updates `unicode-ident` from 1.0.19 to 1.0.22
- [Release notes](https://github.com/dtolnay/unicode-ident/releases)
- [Commits](https://github.com/dtolnay/unicode-ident/compare/1.0.19...1.0.22)

Updates `zbus_macros` from 5.11.0 to 5.12.0
- [Release notes](https://github.com/z-galaxy/zbus/releases)
- [Commits](https://github.com/z-galaxy/zbus/compare/zbus-5.11.0...zbus-5.12.0)

Updates `zerocopy-derive` from 0.8.27 to 0.8.30
- [Release notes](https://github.com/google/zerocopy/releases)
- [Changelog](https://github.com/google/zerocopy/blob/main/CHANGELOG.md)
- [Commits](https://github.com/google/zerocopy/compare/v0.8.27...v0.8.30)

Updates `zvariant` from 5.7.0 to 5.8.0
- [Release notes](https://github.com/dbus2/zbus/releases)
- [Commits](https://github.com/dbus2/zbus/compare/zvariant-5.7.0...zvariant-5.8.0)

Updates `zvariant_derive` from 5.7.0 to 5.8.0
- [Release notes](https://github.com/dbus2/zbus/releases)
- [Commits](https://github.com/dbus2/zbus/compare/zbus-5.7.0...zbus-5.8.0)

Updates `serde_with` from 3.15.0 to 3.16.0
- [Release notes](https://github.com/jonasbb/serde_with/releases)
- [Commits](https://github.com/jonasbb/serde_with/compare/v3.15.0...v3.16.0)

Updates `bitflags` from 2.9.4 to 2.10.0
- [Release notes](https://github.com/bitflags/bitflags/releases)
- [Changelog](https://github.com/bitflags/bitflags/blob/main/CHANGELOG.md)
- [Commits](https://github.com/bitflags/bitflags/compare/2.9.4...2.10.0)

Updates `cfg-if` from 1.0.3 to 1.0.4
- [Release notes](https://github.com/rust-lang/cfg-if/releases)
- [Changelog](https://github.com/rust-lang/cfg-if/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cfg-if/compare/v1.0.3...v1.0.4)

Updates `clap` from 4.5.49 to 4.5.53
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.49...clap_complete-v4.5.53)

Updates `zerocopy` from 0.8.27 to 0.8.30
- [Release notes](https://github.com/google/zerocopy/releases)
- [Changelog](https://github.com/google/zerocopy/blob/main/CHANGELOG.md)
- [Commits](https://github.com/google/zerocopy/compare/v0.8.27...v0.8.30)

Updates `bitfield-struct` from 0.11.0 to 0.12.1
- [Release notes](https://github.com/wrenger/bitfield-struct-rs/releases)
- [Commits](https://github.com/wrenger/bitfield-struct-rs/compare/0.11.0...0.12.1)

Updates `num_enum` from 0.7.4 to 0.7.5
- [Commits](https://github.com/illicitonion/num_enum/compare/0.7.4...0.7.5)

Updates `landlock` from 0.4.3 to 0.4.4
- [Release notes](https://github.com/landlock-lsm/rust-landlock/releases)
- [Changelog](https://github.com/landlock-lsm/rust-landlock/blob/main/CHANGELOG.md)
- [Commits](https://github.com/landlock-lsm/rust-landlock/compare/v0.4.3...v0.4.4)

Updates `anstyle-query` from 1.1.4 to 1.1.5
- [Commits](https://github.com/rust-cli/anstyle/compare/anstyle-query-v1.1.4...anstyle-query-v1.1.5)

Updates `anstyle-wincon` from 3.0.10 to 3.0.11
- [Commits](https://github.com/rust-cli/anstyle/compare/anstyle-wincon-v3.0.10...anstyle-wincon-v3.0.11)

Updates `cc` from 1.2.41 to 1.2.47
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.41...cc-v1.2.47)

Updates `clap_builder` from 4.5.49 to 4.5.53
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v4.5.49...v4.5.53)

Updates `find-msvc-tools` from 0.1.4 to 0.1.5
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/find-msvc-tools-v0.1.4...find-msvc-tools-v0.1.5)

Updates `hashbrown` from 0.16.0 to 0.16.1
- [Release notes](https://github.com/rust-lang/hashbrown/releases)
- [Changelog](https://github.com/rust-lang/hashbrown/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/hashbrown/compare/v0.16.0...v0.16.1)

Updates `indexmap` from 2.11.4 to 2.12.1
- [Changelog](https://github.com/indexmap-rs/indexmap/blob/main/RELEASES.md)
- [Commits](https://github.com/indexmap-rs/indexmap/compare/2.11.4...2.12.1)

Updates `is_terminal_polyfill` from 1.70.1 to 1.70.2
- [Changelog](https://github.com/polyfill-rs/is_terminal_polyfill/blob/main-v1.70/CHANGELOG.md)
- [Commits](https://github.com/polyfill-rs/is_terminal_polyfill/compare/v1.70.1...v1.70.2)

Updates `num_enum_derive` from 0.7.4 to 0.7.5
- [Commits](https://github.com/illicitonion/num_enum/compare/0.7.4...0.7.5)

Updates `once_cell_polyfill` from 1.70.1 to 1.70.2
- [Changelog](https://github.com/polyfill-rs/once_cell_polyfill/blob/v1.70.2/CHANGELOG.md)
- [Commits](https://github.com/polyfill-rs/once_cell_polyfill/compare/v1.70.1...v1.70.2)

Updates `proc-macro2` from 1.0.101 to 1.0.103
- [Release notes](https://github.com/dtolnay/proc-macro2/releases)
- [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.101...1.0.103)

Updates `quote` from 1.0.41 to 1.0.42
- [Release notes](https://github.com/dtolnay/quote/releases)
- [Commits](https://github.com/dtolnay/quote/compare/1.0.41...1.0.42)

Updates `serde_with_macros` from 3.15.0 to 3.16.0
- [Release notes](https://github.com/jonasbb/serde_with/releases)
- [Commits](https://github.com/jonasbb/serde_with/compare/v3.15.0...v3.16.0)

Updates `signal-hook-registry` from 1.4.6 to 1.4.7
- [Changelog](https://github.com/vorner/signal-hook/blob/master/CHANGELOG.md)
- [Commits](https://github.com/vorner/signal-hook/compare/registry-v1.4.6...registry-v1.4.7)

Updates `syn` from 2.0.106 to 2.0.111
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.106...2.0.111)

Updates `unicode-ident` from 1.0.19 to 1.0.22
- [Release notes](https://github.com/dtolnay/unicode-ident/releases)
- [Commits](https://github.com/dtolnay/unicode-ident/compare/1.0.19...1.0.22)

Updates `windows-sys` from 0.60.2 to 0.61.2
- [Release notes](https://github.com/microsoft/windows-rs/releases)
- [Commits](https://github.com/microsoft/windows-rs/commits)

Updates `zerocopy-derive` from 0.8.27 to 0.8.30
- [Release notes](https://github.com/google/zerocopy/releases)
- [Changelog](https://github.com/google/zerocopy/blob/main/CHANGELOG.md)
- [Commits](https://github.com/google/zerocopy/compare/v0.8.27...v0.8.30)

---
updated-dependencies:
- dependency-name: zbus
  dependency-version: 5.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-rust-vmm
- dependency-name: serde_with
  dependency-version: 3.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-rust-vmm
- dependency-name: bitflags
  dependency-version: 2.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-rust-vmm
- dependency-name: cfg-if
  dependency-version: 1.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: clap
  dependency-version: 4.5.53
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: zerocopy
  dependency-version: 0.8.30
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: io-uring
  dependency-version: 0.7.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: num_enum
  dependency-version: 0.7.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: getrandom
  dependency-version: 0.3.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: landlock
  dependency-version: 0.4.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: aho-corasick
  dependency-version: 1.1.4
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: anstyle-query
  dependency-version: 1.1.5
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: anstyle-wincon
  dependency-version: 3.0.11
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: cc
  dependency-version: 1.2.47
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: clap_builder
  dependency-version: 4.5.53
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: find-msvc-tools
  dependency-version: 0.1.5
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: hashbrown
  dependency-version: 0.16.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: indexmap
  dependency-version: 2.12.1
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: non-rust-vmm
- dependency-name: is_terminal_polyfill
  dependency-version: 1.70.2
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: jiff
  dependency-version: 0.2.16
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: jiff-static
  dependency-version: 0.2.16
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: libz-sys
  dependency-version: 1.1.23
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: num_enum_derive
  dependency-version: 0.7.5
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: once_cell_polyfill
  dependency-version: 1.70.2
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: openssl-src
  dependency-version: 300.5.4+3.5.4
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: openssl-sys
  dependency-version: 0.9.111
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: proc-macro2
  dependency-version: 1.0.103
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: quote
  dependency-version: 1.0.42
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: serde_with_macros
  dependency-version: 3.16.0
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: non-rust-vmm
- dependency-name: signal-hook-registry
  dependency-version: 1.4.7
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: syn
  dependency-version: 2.0.111
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: unicode-ident
  dependency-version: 1.0.22
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: zbus_macros
  dependency-version: 5.12.0
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: non-rust-vmm
- dependency-name: zerocopy-derive
  dependency-version: 0.8.30
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: zvariant
  dependency-version: 5.8.0
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: non-rust-vmm
- dependency-name: zvariant_derive
  dependency-version: 5.8.0
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: non-rust-vmm
- dependency-name: serde_with
  dependency-version: 3.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-rust-vmm
- dependency-name: bitflags
  dependency-version: 2.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-rust-vmm
- dependency-name: cfg-if
  dependency-version: 1.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: clap
  dependency-version: 4.5.53
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: zerocopy
  dependency-version: 0.8.30
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: bitfield-struct
  dependency-version: 0.12.1
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: non-rust-vmm
- dependency-name: num_enum
  dependency-version: 0.7.5
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: landlock
  dependency-version: 0.4.4
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: anstyle-query
  dependency-version: 1.1.5
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: anstyle-wincon
  dependency-version: 3.0.11
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: cc
  dependency-version: 1.2.47
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: clap_builder
  dependency-version: 4.5.53
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: find-msvc-tools
  dependency-version: 0.1.5
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: hashbrown
  dependency-version: 0.16.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: indexmap
  dependency-version: 2.12.1
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: non-rust-vmm
- dependency-name: is_terminal_polyfill
  dependency-version: 1.70.2
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: num_enum_derive
  dependency-version: 0.7.5
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: once_cell_polyfill
  dependency-version: 1.70.2
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: proc-macro2
  dependency-version: 1.0.103
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: quote
  dependency-version: 1.0.42
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: serde_with_macros
  dependency-version: 3.16.0
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: non-rust-vmm
- dependency-name: signal-hook-registry
  dependency-version: 1.4.7
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: syn
  dependency-version: 2.0.111
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: unicode-ident
  dependency-version: 1.0.22
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
- dependency-name: windows-sys
  dependency-version: 0.61.2
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: non-rust-vmm
- dependency-name: zerocopy-derive
  dependency-version: 0.8.30
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: non-rust-vmm
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-25 11:12:36 +00:00
Rob Bradford
bcf23c1bf6 ci: Move micro_http to rust-vmm dependabot group
This crate depends upon vmm-sys-util which is in this group so it also
needs to be in that group.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-11-25 09:06:51 +00:00
Philipp Schuster
67fc9d990e misc: vmm: drop extern crate, use modern rust
This commit is part of a series of similar commits.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-24 22:36:46 +00:00
Philipp Schuster
2157f1a1f2 misc: virtio-devices: drop extern crate, use modern rust
This commit is part of a series of similar commits.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-24 22:36:46 +00:00
Philipp Schuster
adb7cfd72c misc: vhost_user_net: drop extern crate, use modern rust
This commit is part of a series of similar commits.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-24 22:36:46 +00:00
Philipp Schuster
1f70e20c17 misc: vhost_user_block: drop extern crate, use modern rust
This commit is part of a series of similar commits.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-24 22:36:46 +00:00
Philipp Schuster
29e8a242b6 misc: tracer: drop extern crate, use modern rust
This commit is part of a series of similar commits.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-24 22:36:46 +00:00
Philipp Schuster
d32b2dc137 misc: tpm: drop extern crate, use modern rust
This commit is part of a series of similar commits.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-24 22:36:46 +00:00
Philipp Schuster
7de45b3a75 misc: tests: drop extern crate, use modern rust
This commit is part of a series of similar commits.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-24 22:36:46 +00:00
Philipp Schuster
3709105043 misc: rate_limiter: drop extern crate, use modern rust
This commit is part of a series of similar commits.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-24 22:36:46 +00:00
Philipp Schuster
2c1eccc6bc misc: performance-metrics: drop extern crate, use modern rust
This commit is part of a series of similar commits.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-24 22:36:46 +00:00
Philipp Schuster
6f4b5253b4 misc: pci: drop extern crate, use modern rust
This commit is part of a series of similar commits.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-24 22:36:46 +00:00
Philipp Schuster
492f24c632 misc: net_util: drop extern crate, use modern rust
This commit is part of a series of similar commits.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-24 22:36:46 +00:00
Philipp Schuster
47dff4f6bc misc: net_gen: drop extern crate, use modern rust
This commit is part of a series of similar commits.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-24 22:36:46 +00:00
Philipp Schuster
b3f929432e misc: hypervisor: drop extern crate, use modern rust
This commit is part of a series of similar commits.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-24 22:36:46 +00:00
Philipp Schuster
e39174ac51 misc: devices: drop extern crate, use modern rust
This commit is part of a series of similar commits.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-24 22:36:46 +00:00
Philipp Schuster
5f66a26b2e misc: block: drop extern crate, use modern rust
This commit is part of a series of similar commits.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-24 22:36:46 +00:00
Philipp Schuster
75cdfb0117 misc: arch: drop extern crate, use modern rust
This commit is the first in a series of similar commits to clean up
obsolete `extern crate` statements

Since Rust 1.30, normal macros can be imported via `use`, and with Rust
1.31 and edition 2018 this has become the preferred approach.
`extern crate` is only needed for `alloc` in `no_std` crates, which does
not apply here.

By dropping these (often redundant or odd) `extern crate` lines, we
expose the actual dependencies more clearly and reduce technical debt.

## Auto-generation of the series

Most of this series was produced automatically:

1. Removed all "extern crate" references
2. Run the script [0] to add missing `use` statements
3. Run `cargo +nightly fmt --all`
4. Fix the remaining problems manually

The treewide changes were then split into per-folder commits.

[0]
```python
import os
import re

# Mapping of macro/function usage to imports
MACRO_IMPORTS = {
    "info!": "use log::info;\n",
    "debug!": "use log::debug;\n",
    "error!": "use log::error;\n",
    "trace!": "use log::trace;\n",
    "warn!": "use log::warn;\n",
    "event!": "use event_monitor::event;\n",
    "anyhow!(": "use anyhow::anyhow;\n",
    "bitflags!(": "use bitflags::bitflags;\n",
    "ioctl_ior_nr!": "use vmm_sys_util::{ioctl_ior_nr};\n",
    "ioctl_iow_nr!": "use vmm_sys_util::{ioctl_iow_nr};\n",
}

# Regex for finding the first use statement
USE_REGEX = re.compile(r"^\s*(use|pub use) .+?;")

def process_file(path):
    with open(path, "r", encoding="utf-8") as f:
        lines = f.readlines()

    content = "".join(lines)
    existing_imports = set(lines)
    needed_imports = set()

    # Check macros/functions against mapping, only add if not already present
    for key, import_stmt in MACRO_IMPORTS.items():
        if key in content and import_stmt not in existing_imports:
            needed_imports.add(import_stmt)

    if not needed_imports:
        print(f"Unmodified {path} (no new imports needed)")
        return  # Nothing to do

    # Find first use or pub use statement
    for i, line in enumerate(lines):
        if USE_REGEX.match(line):
            insertion_index = i + 1
            break
    else:
        print(f"Unmodified {path} (no use or pub use statement found)")
        return  # No use statement found, skip file

    # Insert imports
    lines[insertion_index:insertion_index] = list(needed_imports)

    # Write back file
    with open(path, "w", encoding="utf-8") as f:
        f.writelines(lines)

    print(f"Modified {path}, added imports: {''.join(needed_imports).strip()}")

for root, _, files in os.walk("."):
    for file in files:
        if file.endswith(".rs"):
            process_file(os.path.join(root, file))
```

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-24 22:36:46 +00:00
Eugene Korenevsky
e6d31a3d81 block: qcow: switch qcow2 tests from focal to jammy qcow2 images
Signed-off-by: Eugene Korenevsky <ekorenevsky@aliyun.com>
2025-11-24 08:52:13 +00:00
Eugene Korenevsky
94ed7c1745 block: qcow: add integration tests for qcow2 compression
Add tests:
- zlib: test_virtio_block_qcow2_zlib()
- zstd: test_virtio_block_qcow2_zstd()
Both these tests use zlib- and zstd-compressed images as OS image.

Modify test_virtio_block_qcow2_backing_file() test: it is practical
to test qcow2 file-backing with compression, so use zlib-compressed
image as a backing file.

Signed-off-by: Eugene Korenevsky <ekorenevsky@aliyun.com>
2025-11-24 08:52:13 +00:00
Eugene Korenevsky
aa67250049 block: qcow: support compressed clusters (zlib, zstd)
Add support of reading and writing compressed clusters.
Support zlib and zstd compressions.

L2 cache: store entire L2 entries, not only standard cluster addresses.

Read path. Offsets of compressed clusters cannot be determined,
therefore replace QcowFile.file_offset_read() with QcowFile.file_read().
This method reads the cluster, decompresses it if necessary and returns
the data to the caller.

Write path. QcowFile.file_offset_write(): since writing to compressed
clusters is not generally possible, allocate a new standard
(non-compressed) cluster if compressed L2 entry is encountered; then
decompress compressed cluster into new cluster; then return offset
inside new cluster to the caller. Processing of standard clusters is
not changed.

Signed-off-by: Eugene Korenevsky <ekorenevsky@aliyun.com>
2025-11-24 08:52:13 +00:00
Rob Bradford
4d79709b5e tests: Re-enable test_windows_guest_snapshot_restore
Only for x86-64 for now as it's still failing on ARM64.

See: #4327

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-11-22 12:39:47 +00:00
Rob Bradford
e993310c96 hypervisor: kvm: Save KVM HyperV SynIC emulation state
As well as saving the MSRs as it is currently does ensure that the KVM
capability is enabled along with keeping the internal state updated.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
Co-authored-by: Chengyu Fu <chengyu.fu@linux.alibaba.com>
2025-11-22 12:39:47 +00:00
Philipp Schuster
16fbab30b1 docs: add gitlint guidance to CONTRIBUTING.md
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-22 10:38:38 +00:00
Philipp Schuster
f5d2973546 block: advisory locks: use byte-range locks to match QEMU behavior
The granularity has significant implications in typical cloud
deployments with network storage. The Linux kernel will sync advisory
locks to network file systems, but these backends may have different
policies and handle locks differently. For example, Netapp speaks a NFS
API but will treat advisory OFD locks for the whole file as mandatory
locks, whereas byte-range locks for the whole file will remain
advisory [0].

As it is a valid use case to prevent multiple CHV instances from
accessing the same disk but disk management software (e.g., Cinder in
OpenStack) should be able to snapshot disks while VMs are running, we
need special control over the lock granularity. Therefore, it is a valid
use case to lock the whole byte range of a disk image without
technically locking the whole file - to get the best of both worlds.

This also brings CHVs behavior in line with QEMU [1].

Whole-file locks remain a valid use case and could be supported later.
This patch only provides the necessary groundwork; making it
configurable is out of scope for now.

[0] https://kb.netapp.com/on-prem/ontap/da/NAS/NAS-KBs/How_is_Mandatory_Locking_supported_for_NFSv4_on_ONTAP_9
[1] <qemu>/util/osdep.c::qemu_lock_fcntl()

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-22 10:38:38 +00:00
Demi Marie Obenour
2be304b392 misc: Check that get_slice() returned a big enough slice
This should be guaranteed by GuestMemory and GuestMemoryRegion, but
those traits are currently safe, so add checks to guard against
incorrect implementations of them.

Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
2025-11-22 10:24:13 +00:00
Demi Marie Obenour
969a3b57a3 misc: tdx: make tdx_init_memory_region() unsafe
It takes a pointer to a userspace address that it accesses, so it should
be marked unsafe.  This was missed earlier.

Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
2025-11-22 10:24:13 +00:00
Demi Marie Obenour
021f450cdb virtio-devices: proper bounds checks
Callers of get_host_address_range() rely on it returning a pointer to at
least size bytes of memory.  mem.get_host_address() is an overrideable
method of a safe trait, so it is better for safe code to not rely on its
correctness for safety.  Instead, use mem.get_slice(), which returns a
VolatileSlice whose invariants guarantee that it points to a sufficient
amount of memory.  If mem.check_range() succeeds but mem.get_slice()
returns a slice that is too small, this means that there is either a
logic error or a situation the code cannot support yet, so panic.

Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
2025-11-22 10:24:13 +00:00
Demi Marie Obenour
0e21b56aea pci: do not check for page-aligned size and offset before calling mmap()
The kernel will validate that the size is page-aligned.  The file offset
is always zero, so the kernel will also validate that the offset is
page-aligned.

Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
2025-11-22 10:24:13 +00:00
Demi Marie Obenour
8be28f8438 misc: Work around vfio_dma_map being unsound
This API passes a u64 to a kernel API that treats the u64 as a userspace
address.  Therefore, it should be marked unsafe, but it currently is not
[1].  Wrap the call in an unsafe block to document that invariants must
be upheld to avoid undefined behavior.  This causes a compiler warning,
so suppress the warning with #[allow(unused_unsafe)].

[1]: https://github.com/rust-vmm/vfio/issues/100

Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
2025-11-22 10:24:13 +00:00
Demi Marie Obenour
12c7cc5e4f pci: Remove dma_map() and dma_unmap()
These APIs had no users, were not documented, and were unsound.

Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
2025-11-22 10:24:13 +00:00
Demi Marie Obenour
8f6a6a85e0 virtio-devices: mark Vdpa::dma_map as unsafe
I believe that its only caller used it safely, but it is still better to
mark the code as unsafe.  Also add additional validity checks.

Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
2025-11-22 10:24:13 +00:00
Demi Marie Obenour
06b76972e2 pci: move operation out of loop
No functional change intended.

Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
2025-11-22 10:24:13 +00:00
Demi Marie Obenour
199d2d05d8 hypervisor: tdx: do not use u64 to represent pointers
Also drop support for building the TDX code for 32-bit targets.  All
CPUs with TDX support are 64-bit so supporting 32-bit targets is not
needed.

Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
2025-11-22 10:24:13 +00:00
Demi Marie Obenour
42522a88c0 misc: do not use u64 to represent host pointers
To ensure that struct sizes are the same on 32-bit and 64-bit, various
kernel APIs use __u64 (Rust u64) to represent userspace pointers.
Userspace is expected to cast pointers to __u64 before passing them to
the kernel, and cast kernel-provided __u64 to a pointer before using
them.  However, various safe APIs in Cloud Hypervisor took
caller-provided u64 values and passed them to syscalls that interpret
them as userspace addresses.  Therefore, passing bad u64 values would
cause memory disclosure or corruption.

Fix the bug by using usize and pointer types as appropriate.  To make
soundness of the code easier to reason about, the PCI code gains a new
MmapRegion abstraction that ensures the validity of pointers.  The rest
of the code already has an MmapRegion abstraction it can use.  To avoid
having to reason about whether something is keeping the MmapRegion
alive, reference counting is added.  MmapRegion cannot hold references
to other objects, so the reference counting cannot introduce cycles.

Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
2025-11-22 10:24:13 +00:00
Demi Marie Obenour
fdc19ad85e misc: Mark memory region APIs as unsafe
To ensure that struct sizes are the same on 32-bit and 64-bit, various
kernel APIs use __u64 (Rust u64) to represent userspace pointers.
Userspace is expected to cast pointers to __u64 before passing them to
the kernel, and cast kernel-provided __u64 to a pointer before using
them.  However, various safe APIs in Cloud Hypervisor took
caller-provided u64 values and passed them to syscalls that treat them
as userspace addresses.  Therefore, passing bad u64 values would cause
memory disclosure or corruption.  The memory region APIs are one example
of this, so mark them as unsafe.

Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
2025-11-22 10:24:13 +00:00
Demi Marie Obenour
00f0b9e42c vmm: Fix clippy lints on RISC-V
These caused CI failures in #7129.

No functional change.

Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
2025-11-22 10:24:13 +00:00
dependabot[bot]
0ff8d1cb28 build: Bump actions/checkout from 5 to 6
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-22 00:05:53 +00:00
Thomas Prescher
b6032bc492 arch: fix extended topology enumeration subleafs
When booting a Linux guest in SMP configuration, on sapphire rapids
and granite rapids the following kernel warning can be observed:

[Firmware Bug]: CPUID leaf 0x1f subleaf 1 APIC ID mismatch 1 != 0
[Firmware Bug]: CPUID leaf 0x1f subleaf 2 APIC ID mismatch 1 != 0

The reason is that we announce the presence of the extended topology
leaf, but fail to announce the x2apic ID in EDX for each subleaf.

Signed-off-by: Thomas Prescher <thomas.prescher@cyberus-technology.de>
On-behalf-of: SAP thomas.prescher@sap.com
2025-11-21 17:17:27 +00:00
Stefan Nürnberger
95b8c6afdd seccomp: allow sendto for vfio_user devices
as of rust 1.90, writes to unix sockets use the sendto syscall. This
affects the vcpu threads when vfio_user devices are accessed.

Signed-off-by: Stefan Nürnberger <stefan.nuernberger@cyberus-technology.de>
2025-11-21 17:06:19 +00:00
Philipp Schuster
f02745a7ed vmm: unrelated small code improvements
Unfortunately, there is no lint for that.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-21 09:32:11 +00:00
Philipp Schuster
fed010fcd1 misc: clippy: add manual_string_new
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-21 09:32:11 +00:00
Philipp Schuster
b4c62bf159 misc: clippy: add semicolon_if_nothing_returned
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-21 09:32:11 +00:00
Philipp Schuster
ea4f07d3bf misc: clippy: add uninlined_format_args
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-21 09:32:11 +00:00
Philipp Schuster
7cb73e9e56 misc: clippy: add unnecessary_semicolon
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-21 09:32:11 +00:00
Philipp Schuster
06390342a6 misc: clippy: add default clippy lint groups
This is the first commit in a series of commits to improve the Code
Quality in Cloud Hypervisor in a sustainable way. These are the
default rules from `clippy::all` but written here to be more explicit.
`clippy::all` refers to all "default sensible" lints, not all
existing lints.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-21 09:32:11 +00:00
Philipp Schuster
11d17fbf79 docs: update CONTRIBUTING.md
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-20 21:15:03 +00:00
Philipp Schuster
e160a17131 net_util: unrelated code improvement
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-20 21:15:03 +00:00
Philipp Schuster
7364fbdc8e tests: move VM test into a test module
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-20 21:15:03 +00:00
Philipp Schuster
35b91f76af tests: prevent broken terminal after running cargo test -p vmm
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-20 21:15:03 +00:00
Philipp Schuster
d1680b9ff9 tests: streamline module names to unit_tests
This better aligns with the rest of the code and makes it clearer
that these tests can run "as is" in a normal hosted environments
without the special test environment.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-20 21:15:03 +00:00
Philipp Schuster
c990f1bdaa tests: enable cargo test --workspace + #[cfg(devcli_testenv)]
TL;DR: Massive quality of life improvement for devs

Cloud Hypervisor uses the Cargo test framework for multiple tests:

- normal unit tests
- unit tests requiring special environment (the Tap device tests)
- integration tests requiring a special environment

This prevented the execution of `cargo test --workspace`, which results
in a very poor developer experience. Although
`./scripts/run_unit_tests.sh` exists, there are valid reasons why devs
cannot or even don't want to use it.

By adding a new `chv_testenv` rustc config, we can conditionally only
activate tests when the `./scripts/` magic runs them. This improves
the general developer experience by a lot.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-20 21:15:03 +00:00
Bo Chen
e3e9e1c84c tests: Add retries for artifact downloads
This change makes integration tests more resilient to transient download
failures. This will reduce churn in our CI workflow, specifically for
the Merge Queue.

Examples:
https://github.com/cloud-hypervisor/cloud-hypervisor/actions/runs/19545345066/job/55962570896
https://github.com/cloud-hypervisor/cloud-hypervisor/actions/runs/19545345122/job/55962570736
https://github.com/cloud-hypervisor/cloud-hypervisor/actions/runs/19545345034/job/55962570724

Signed-off-by: Bo Chen <bchen@crusoe.ai>
2025-11-20 19:34:57 +00:00
Changyuan Lyu
be495ec64a arch: x86_64: fix cpuid leaf 0x1 EBX bits 23-16
Commit 5ec47d4883 was intended to patch ebx bits 23-16 in cpuid leaf
0x1, but it was not working as expected, as in rust, operator << has a
stronger precedence than & [1]. Later commit b6667f948e fixed the
operator precedence clippy warning, but did not fix the actual issue. As
a result, the current code is not changing ebx,

```
cpu_ebx |= ((dies_per_package as u32) * (cores_per_die as u32) * (threads_per_core as u32))
    & (0xff << 16);
```

Since the total number of logical processors is generally less than
65536, the right hand side of the expression is 0 in most cases.

[1] https://doc.rust-lang.org/reference/expressions.html#expression-precedence

Fixes: 5ec47d4883 ("arch: x86_64: enable HTT flag")
Signed-off-by: Changyuan Lyu <changyuanl@google.com>
2025-11-18 08:27:59 +00:00
dependabot[bot]
8ee26286ac build: Bump crate-ci/typos from 1.39.0 to 1.39.2
Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.39.0 to 1.39.2.
- [Release notes](https://github.com/crate-ci/typos/releases)
- [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crate-ci/typos/compare/v1.39.0...v1.39.2)

---
updated-dependencies:
- dependency-name: crate-ci/typos
  dependency-version: 1.39.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-18 00:27:28 +00:00
Philipp Schuster
935332bc42 misc: unrelated misc code improvements
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-17 16:59:49 +00:00
Philipp Schuster
e4fd066d82 misc: improve developer experience of cargo clippy
A major improvement to the developer experience of clippy in
Cloud Hypervisor.

1. Make `cargo clippy` just work with the same lints we use in CI
2. Simplify adding new lints

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-17 16:59:49 +00:00
Philipp Schuster
a7fa3a0c86 vm-migration: better naming + unittests
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-17 14:34:54 +00:00
Julian Stecklina
b6c266c880 vmm: avoid creating large temporary vector during migration
... by just passing the iterator along. For large VMs this bitmap is
gigantic. A 12TB VM has 384MB of dirty bitmap.

With all these optimizations from the previous commits in place, we
see quite the improvement when it comes to scanning the dirty bitmap.

For a bitmap with 1% bits (randomly) set, dirty_log() takes:

Original code: 2166ms (100.0%)
New code:       382ms ( 17.6%)

on my system. The sparser the dirty bitmap the faster. Scanning an
empty bitmap is 100x faster. For a 5% populated bitmap we are still 3x
faster.

If someone wants to play with this, there is a benchmark harness here:
https://github.com/blitz/chv-bitmap-bench

On-behalf-of: SAP julian.stecklina@sap.com
Signed-off-by: Julian Stecklina <julian.stecklina@cyberus-technology.de>
2025-11-17 14:34:54 +00:00
Julian Stecklina
fc99e299c3 virtio-devices: avoid creating a temporary vector
... by passing the slice along instead.

On-behalf-of: SAP julian.stecklina@sap.com
Signed-off-by: Julian Stecklina <julian.stecklina@cyberus-technology.de>
2025-11-17 14:34:54 +00:00
Julian Stecklina
3d5f9a3a98 virtio-devices: mark a possible improvement
This would be a good opportunity to optimize another pointless vector
away, but I don't have a good way to test this at the moment. But
maybe someone else gives it a shot.

On-behalf-of: SAP julian.stecklina@sap.com
Signed-off-by: Julian Stecklina <julian.stecklina@cyberus-technology.de>
2025-11-17 14:34:54 +00:00
Julian Stecklina
ad9034ed1d vm-migration: optimize dirty bitmap scanning
Adding itertools as dependency improves the iteration code in the
following significantly.

With this change, we don't need a copy of the vector. Just something
that can be coerced into an iterator. We also use the bit position
iterator to make the code somewhat clearer. The new code is much
faster, because it will not iterate over every bit, just each 1 bit in
the input.

The next commit will complete this optimization and have some concrete
numbers.

On-behalf-of: SAP julian.stecklina@sap.com
Signed-off-by: Julian Stecklina <julian.stecklina@cyberus-technology.de>
2025-11-17 14:34:54 +00:00
Julian Stecklina
96f4e33897 vm-migration: add helper to iterate over bitmaps
Instead of using ad-hoc code, just write an extension to the Iterator
trait that we can easily unit test.

Co-authored-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP julian.stecklina@sap.com
On-behalf-of: SAP philipp.schuster@sap.com
Signed-off-by: Julian Stecklina <julian.stecklina@cyberus-technology.de>
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
2025-11-17 14:34:54 +00:00
Rob Bradford
6147c4c8b7 tests: Disable nextest failure on fw_cfg tests on MSHV
Due to the fw_cfg test being disabled on MSHV this results in no tests
being runnable which results in an error in nextest. Reduce that error
to a warning use --no-tests=warn

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-11-17 10:22:34 +00:00
Rob Bradford
f9076cccfa tests: Add test timeout (10 minutes) to nextest configuration
Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-11-17 10:22:34 +00:00
Rob Bradford
9f046f02a2 tests: Disable test_snapshot_restore_with_fd()
This is now failing on x86-64 as well after the update of the Rust
version.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-11-17 10:22:34 +00:00
Rob Bradford
3734a13cbf tests: Use cargo nextest for integration tests
This alternative test runner supports retries and also reports how long
each test takes to run.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-11-17 10:22:34 +00:00
Rob Bradford
2707b0f72a build: Add cargo nextest to container
cargo nextest is an improved test runner that allows retries as well a
reporting the times for the test runs.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-11-17 10:22:34 +00:00
Rob Bradford
176023156e test_infra: Make guest ID generation multiprocess safe
When using nextest for running tests each test is run in its own process
so the old solution of using a static variable for the guest ID (used to
determine the network segment) no longer works.

Instead use a text file on the filesystem protected with an exclusive
lock. The test process will read from it and then write back the next ID
that can be used. It wraps around at the limit of u8 and skips ID 0.

This function intentionally panics rather than propagate errors as it
should only be called for testing purposes and there the panic handler
will give a useful backtrace and cleanup.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-11-17 10:22:34 +00:00
Rob Bradford
5051feb0bd build: Bump MSRV to 1.89.0
This is required to support exclusive locking on files which is needed
for safe test ID generation when using nextest (since it runs each test
as a separate process.)

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-11-17 10:22:34 +00:00
Matt Moriarity
ec57aade15 seccomp: allow sendto for vsock thread
as of rust 1.90, writes to unix socket streams use send_with_flags
instead of write, so it uses a sendto syscall instead of write.

Signed-off-by: Matt Moriarity <matt@mattmoriarity.com>
2025-11-13 18:47:01 +00:00
Philipp Schuster
02da2f2d36 misc: gitlint: python code improvements
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-13 19:16:45 +00:00
Philipp Schuster
62345cd6fd misc: gitlint: allow more prefixes disabling 72 width limit
Suggested-by Alyssa Ross [0].

[0]: https://github.com/cloud-hypervisor/cloud-hypervisor/pull/7471#discussion_r2519894440

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-13 19:16:45 +00:00
Philipp Schuster
f826d92601 misc: gitlint: allow well-known commit tags to exceed line limit
To get that list, I've used

```
git log | grep --fixed-strings -- "-by:" | head -n 100000 | sort | less
```

on the Linux kernel's git repository.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-11-13 19:16:45 +00:00
Rob Bradford
063aa4b7d5 arch: riscv64: Expose host extension set to guest via FDT
The set of extensions supported by a RISC-V system needs to be exposed
to the guest - currently that is a fixed, minimal set of extensions.
These extensions are not sufficient to boot Ubuntu 25.10 which now has a
mininimum requirement of RVA23S64 (which is a minimum set of extensions
that make sense for server use cases.)

The easiest way to convey the extensions that the guest should use is to
copy those that the host kernel understands (and thus includes in the
/proc/cpuinfo) data.

However since nested virtualisation is not currently possible - exclude
the "H" (Hypervisor) extension from the list of short (single letter)
extensions.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-11-13 14:34:38 +00:00
Rob Bradford
d586c844de tests: Update test_iommu_segments check
After updating the Linux kernel to 6.19.6 the second segment (segment=1)
is now under the 2nd IOMMU group (which it a more logical setup) and as
such the added device which is on that segment is in that second IOMMU
group.

The same check is made in test_vdpa_block so also test there.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-11-13 14:29:26 +00:00
Rob Bradford
b3b51bd3a2 tests: aarch64: Fix test_virtio_iommu for kernel IOMMU groups change
The numbers for the IOMMU groups have shifted after the update to Linux
kernel 6.16.9.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-11-13 14:29:26 +00:00
Rob Bradford
8bf284e713 scripts: Bump Linux version to 6.16.9
Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-11-13 14:29:26 +00:00
Rob Bradford
e023efce3d vmm: cpu: Retry signalling the vCPU thread if it doesn't acknowledge
Resignal every 10ms the thread if it has not acknowledged the signal via
setting the atomic when the vCPU thread was acknowledged. Further, avoid
an infinite loop by generating an error if it takes more than 1000ms to
interrupt the thread.

The retry helps mitigate a race condition where the signal is received
between checking the pause atomic and entering KVM_RUN ioctl when
pausing. Hitting this race condition would leave the
wait_untial_signal_acknowledged() method spinning indefinitely.

The timeout error avoids the VMM process being blocked indefinitely.

See: #7427

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-11-11 23:02:00 +00:00
Rob Bradford
bb7730e00f vmm: seccomp: Use rseq syscall constant
Formerly these syscall's had to be specified by number as the constants
were missing in musl.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-11-11 07:30:22 +00:00
Anirudh Rayabharam
dd66eb834c ci: dump kernel logs in MSHV workflow
Dump kernel logs after running the tests in the MSHV workflow to help
debug failures.

In addition to getting the kernel logs using `dmesg` also use AzCli to
retrieve the serial console logs. If the VM is hung or panicked, the
workflow would be unable to SSH into it and execute `dmesg`. In this
case the serial console logs would be helpful.

Signed-off-by: Anirudh Rayabharam <anrayabh@microsoft.com>
2025-11-08 16:06:15 +00:00
253 changed files with 5806 additions and 3262 deletions

3
.config/nextest.toml Normal file
View File

@@ -0,0 +1,3 @@
[profile.default]
# Don't let one individual test run for more than 10 minutes
slow-timeout = { period = "60s", terminate-after = 10 }

View File

@@ -11,6 +11,7 @@ updates:
- dependency-name: "kvm-bindings"
- dependency-name: "kvm-ioctls"
- dependency-name: "linux-loader"
- dependency-name: "micro_http"
- dependency-name: "mshv-bindings"
- dependency-name: "mshv-ioctls"
- dependency-name: "seccompiler"
@@ -41,6 +42,7 @@ updates:
- dependency-name: "kvm-bindings"
- dependency-name: "kvm-ioctls"
- dependency-name: "linux-loader"
- dependency-name: "micro_http"
- dependency-name: "mshv-bindings"
- dependency-name: "mshv-ioctls"
- dependency-name: "seccompiler"

View File

@@ -10,7 +10,7 @@ jobs:
name: Audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions-rust-lang/audit@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -15,13 +15,13 @@ jobs:
- stable
- beta
- nightly
- "1.88.0"
- "1.89.0"
target:
- x86_64-unknown-linux-gnu
- x86_64-unknown-linux-musl
steps:
- name: Code checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
fetch-depth: 0
@@ -35,40 +35,40 @@ jobs:
target: ${{ matrix.target }}
- name: Build (default features)
run: cargo rustc --locked --bin cloud-hypervisor -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
run: cargo build --locked --bin cloud-hypervisor
- name: Build (kvm)
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
run: cargo build --locked --bin cloud-hypervisor --no-default-features --features "kvm"
- name: Build (default features + tdx)
run: cargo rustc --locked --bin cloud-hypervisor --features "tdx" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
run: cargo build --locked --bin cloud-hypervisor --features "tdx"
- name: Build (default features + dbus_api)
run: cargo rustc --locked --bin cloud-hypervisor --features "dbus_api" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
run: cargo build --locked --bin cloud-hypervisor --features "dbus_api"
- name: Build (default features + guest_debug)
run: cargo rustc --locked --bin cloud-hypervisor --features "guest_debug" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
run: cargo build --locked --bin cloud-hypervisor --features "guest_debug"
- name: Build (default features + pvmemcontrol)
run: cargo rustc --locked --bin cloud-hypervisor --features "pvmemcontrol" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
run: cargo build --locked --bin cloud-hypervisor --features "pvmemcontrol"
- name: Build (default features + fw_cfg)
run: cargo rustc --locked --bin cloud-hypervisor --features "fw_cfg" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
run: cargo build --locked --bin cloud-hypervisor --features "fw_cfg"
- name: Build (default features + ivshmem)
run: cargo rustc --locked --bin cloud-hypervisor --features "ivshmem" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
run: cargo build --locked --bin cloud-hypervisor --features "ivshmem"
- name: Build (mshv)
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "mshv" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
run: cargo build --locked --bin cloud-hypervisor --no-default-features --features "mshv"
- name: Build (sev_snp)
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "sev_snp" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
run: cargo build --locked --bin cloud-hypervisor --no-default-features --features "sev_snp"
- name: Build (igvm)
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "igvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
run: cargo build --locked --bin cloud-hypervisor --no-default-features --features "igvm"
- name: Build (mshv + kvm)
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "mshv,kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
run: cargo build --locked --bin cloud-hypervisor --no-default-features --features "mshv,kvm"
- name: Release Build (default features)
run: cargo build --locked --all --release --target=${{ matrix.target }}

View File

@@ -3,10 +3,10 @@ on: [pull_request, merge_group]
jobs:
check:
name: DCO Check ("Signed-Off-By")
name: DCO Check ("Signed-off-by")
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Set up Python 3.x
uses: actions/setup-python@v6
with:

View File

@@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Code checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
@@ -41,7 +41,7 @@ jobs:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
# generate Docker tags based on the following events/attributes
tags: |
type=raw,value=20250815-0
type=raw,value=20251114-0
type=sha
- name: Build and push

View File

@@ -19,7 +19,7 @@ jobs:
RUSTFLAGS: -D warnings
steps:
- name: Code checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Install Rust toolchain (${{ matrix.rust }})
uses: dtolnay/rust-toolchain@stable
with:

View File

@@ -18,7 +18,7 @@ jobs:
RUSTFLAGS: -D warnings
steps:
- name: Code checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Install Rust toolchain (${{ matrix.rust }})
uses: dtolnay/rust-toolchain@stable
with:

View File

@@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0

View File

@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Lint Dockerfile
uses: hadolint/hadolint-action@master

View File

@@ -13,7 +13,7 @@ jobs:
- name: Fix workspace permissions
run: sudo chown -R runner:runner ${GITHUB_WORKSPACE}
- name: Code checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Run unit tests (musl)

View File

@@ -12,7 +12,7 @@ jobs:
METRICS_PUBLISH_KEY: ${{ secrets.METRICS_PUBLISH_KEY }}
steps:
- name: Code checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Run metrics tests

View File

@@ -13,7 +13,7 @@ jobs:
steps:
- name: Code checkout
if: ${{ github.event_name != 'pull_request' }}
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Run rate-limiter integration tests

View File

@@ -16,7 +16,7 @@ jobs:
run: sudo chown -R runner:runner ${GITHUB_WORKSPACE}
- name: Code checkout
if: ${{ github.event_name != 'pull_request' }}
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Run VFIO integration tests

View File

@@ -11,7 +11,7 @@ jobs:
steps:
- name: Code checkout
if: ${{ github.event_name != 'pull_request' }}
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Install Docker

View File

@@ -17,7 +17,7 @@ jobs:
steps:
- name: Code checkout
if: ${{ github.event_name != 'pull_request' || (matrix.runner == 'garm-jammy' && matrix.libc == 'gnu') }}
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Install Docker

View File

@@ -6,7 +6,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Code checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
# Fetch the entire history so git diff can compare against the base branch
fetch-depth: 0

View File

@@ -34,6 +34,12 @@ on:
USERNAME:
required: true
outputs:
RG_NAME:
description: 'Resource group of the VM'
value: ${{ jobs.infra-setup.outputs.RG_NAME }}
VM_NAME:
description: 'Name of the VM'
value: ${{ jobs.infra-setup.outputs.VM_NAME }}
PRIVATE_IP:
description: 'Private IP of the VM'
value: ${{ jobs.infra-setup.outputs.PRIVATE_IP }}
@@ -46,6 +52,8 @@ jobs:
runs-on: mshv
continue-on-error: true
outputs:
RG_NAME: ${{ steps.rg-setup.outputs.RG_NAME }}
VM_NAME: ${{ steps.vm-setup.outputs.VM_NAME }}
PRIVATE_IP: ${{ steps.get-vm-ip.outputs.PRIVATE_IP }}
steps:
- name: Install & login to AZ CLI
@@ -112,6 +120,7 @@ jobs:
# Create the resource group
echo "Creating resource group in location: ${LOCATION}"
az group create --name ${RG} --location ${LOCATION}
echo "RG_NAME=${RG}" >> $GITHUB_OUTPUT
echo "Resource group created successfully."
- name: Generate SSH Key
@@ -173,6 +182,9 @@ jobs:
--security-type Standard \
--output json
az vm boot-diagnostics enable --name ${VM_NAME} --resource-group ${RG}
echo "VM_NAME=${VM_NAME}" >> $GITHUB_OUTPUT
echo "VM creation process completed successfully."
- name: Get VM Private IP
@@ -234,4 +246,4 @@ jobs:
sudo groupadd -f docker
sudo usermod -a -G docker ${USERNAME}
sudo systemctl restart docker
EOF
EOF

View File

@@ -79,6 +79,28 @@ jobs:
sudo ./scripts/dev_cli.sh tests --hypervisor mshv --integration
EOF
- name: Dump dmesg
if: always()
continue-on-error: true
env:
KEY: azure_key_${{ github.run_id }}
PRIVATE_IP: ${{ needs.infra-setup.outputs.PRIVATE_IP }}
USERNAME: ${{ secrets.MSHV_USERNAME }}
run: |
ssh -i ~/.ssh/${KEY} -o StrictHostKeyChecking=no ${USERNAME}@${PRIVATE_IP} << EOF
sudo dmesg
EOF
- name: Dump serial console logs
if: always()
continue-on-error: true
env:
RG_NAME: ${{ needs.infra-setup.outputs.RG_NAME }}
VM_NAME: ${{ needs.infra-setup.outputs.VM_NAME }}
run: |
set -e
az vm boot-diagnostics get-boot-log --name "${VM_NAME}" --resource-group "${RG_NAME}" | jq -r
cleanup:
name: Cleanup
needs: run-tests
@@ -106,4 +128,4 @@ jobs:
else
echo "SSH key does not exist. Skipping deletion."
fi
echo "Cleanup process completed."
echo "Cleanup process completed."

View File

@@ -6,7 +6,7 @@ jobs:
runs-on: ubuntu-latest
container: openapitools/openapi-generator-cli
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Validate OpenAPI
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Code checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
fetch-depth: 0

View File

@@ -13,18 +13,18 @@ jobs:
steps:
- name: Code checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Install Rust toolchain
run: /opt/scripts/exec-in-qemu.sh rustup default 1.88.0
run: /opt/scripts/exec-in-qemu.sh rustup default 1.89.0
- name: Build test (kvm)
run: /opt/scripts/exec-in-qemu.sh cargo rustc --locked --no-default-features --features "kvm"
run: /opt/scripts/exec-in-qemu.sh cargo build --locked --no-default-features --features "kvm" -p cloud-hypervisor
- name: Clippy test (kvm)
run: /opt/scripts/exec-in-qemu.sh cargo clippy --locked --no-default-features --features "kvm"
run: /opt/scripts/exec-in-qemu.sh cargo clippy --locked --no-default-features --features "kvm" -p cloud-hypervisor
- name: Check no files were modified
run: test -z "$(git status --porcelain)"

View File

@@ -19,18 +19,18 @@ jobs:
steps:
- name: Code checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Install Rust toolchain
run: /opt/scripts/exec-in-qemu.sh rustup default 1.88.0
run: /opt/scripts/exec-in-qemu.sh rustup default 1.89.0
- name: Build ${{ matrix.module }} Module (kvm)
run: /opt/scripts/exec-in-qemu.sh cargo rustc --locked -p ${{ matrix.module }} --no-default-features --features "kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
run: /opt/scripts/exec-in-qemu.sh cargo build --locked -p ${{ matrix.module }} --no-default-features --features "kvm"
- name: Clippy ${{ matrix.module }} Module (kvm)
run: /opt/scripts/exec-in-qemu.sh cargo clippy --locked -p ${{ matrix.module }} --no-default-features --features "kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
run: /opt/scripts/exec-in-qemu.sh cargo clippy --locked -p ${{ matrix.module }} --no-default-features --features "kvm" -- -D warnings
- name: Test ${{ matrix.module }} Module (kvm)
run: /opt/scripts/exec-in-qemu.sh cargo test --locked -p ${{ matrix.module }} --no-default-features --features "kvm"

View File

@@ -29,7 +29,7 @@ jobs:
steps:
- name: Code checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
fetch-depth: 0
@@ -56,7 +56,7 @@ jobs:
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }}
args: --locked --all --all-targets --no-default-features --tests --examples --features "kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
args: --locked --all --all-targets --no-default-features --tests --examples --features "kvm" -- -D warnings
- name: Clippy (mshv)
uses: houseabsolute/actions-rust-cross@v1
@@ -65,7 +65,7 @@ jobs:
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }}
args: --locked --all --all-targets --no-default-features --tests --examples --features "mshv" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
args: --locked --all --all-targets --no-default-features --tests --examples --features "mshv" -- -D warnings
- name: Clippy (mshv + kvm)
uses: houseabsolute/actions-rust-cross@v1
@@ -74,7 +74,7 @@ jobs:
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }}
args: --locked --all --all-targets --no-default-features --tests --examples --features "mshv,kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
args: --locked --all --all-targets --no-default-features --tests --examples --features "mshv,kvm" -- -D warnings
- name: Clippy (default features)
uses: houseabsolute/actions-rust-cross@v1
@@ -83,7 +83,7 @@ jobs:
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }}
args: --locked --all --all-targets --tests --examples -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
args: --locked --all --all-targets --tests --examples -- -D warnings
- name: Clippy (default features + guest_debug)
uses: houseabsolute/actions-rust-cross@v1
@@ -92,7 +92,7 @@ jobs:
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }}
args: --locked --all --all-targets --tests --examples --features "guest_debug" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
args: --locked --all --all-targets --tests --examples --features "guest_debug" -- -D warnings
- name: Clippy (default features + pvmemcontrol)
uses: houseabsolute/actions-rust-cross@v1
@@ -101,7 +101,7 @@ jobs:
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }}
args: --locked --all --all-targets --tests --examples --features "pvmemcontrol" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
args: --locked --all --all-targets --tests --examples --features "pvmemcontrol" -- -D warnings
- name: Clippy (default features + tracing)
uses: houseabsolute/actions-rust-cross@v1
@@ -110,13 +110,13 @@ jobs:
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }}
args: --locked --all --all-targets --tests --examples --features "tracing" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
args: --locked --all --all-targets --tests --examples --features "tracing" -- -D warnings
- name: Clippy (default features + fw_cfg)
uses: actions-rs/cargo@v1
with:
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
command: clippy
args: --target=${{ matrix.target }} --locked --all --all-targets --tests --examples --features "fw_cfg" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
args: --target=${{ matrix.target }} --locked --all --all-targets --tests --examples --features "fw_cfg" -- -D warnings
- name: Clippy (default features + ivshmem)
uses: houseabsolute/actions-rust-cross@v1
@@ -125,7 +125,7 @@ jobs:
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }}
args: --locked --all --all-targets --tests --examples --features "ivshmem" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
args: --locked --all --all-targets --tests --examples --features "ivshmem" -- -D warnings
- name: Clippy (sev_snp)
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
@@ -135,7 +135,7 @@ jobs:
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }}
args: --locked --all --all-targets --no-default-features --tests --examples --features "sev_snp" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
args: --locked --all --all-targets --no-default-features --tests --examples --features "sev_snp" -- -D warnings
- name: Clippy (igvm)
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
@@ -145,7 +145,7 @@ jobs:
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }}
args: --locked --all --all-targets --no-default-features --tests --examples --features "igvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
args: --locked --all --all-targets --no-default-features --tests --examples --features "igvm" -- -D warnings
- name: Clippy (kvm + tdx)
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
@@ -155,7 +155,7 @@ jobs:
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }}
args: --locked --all --all-targets --no-default-features --tests --examples --features "tdx,kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
args: --locked --all --all-targets --no-default-features --tests --examples --features "tdx,kvm" -- -D warnings
- name: Check build did not modify any files
run: test -z "$(git status --porcelain)"
@@ -165,6 +165,6 @@ jobs:
name: Typos / Spellcheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
# Executes "typos ."
- uses: crate-ci/typos@v1.39.0
- uses: crate-ci/typos@v1.40.0

View File

@@ -29,7 +29,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Code checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Install musl-gcc
if: contains(matrix.platform.target, 'musl')
run: sudo apt install -y musl-tools
@@ -45,7 +45,7 @@ jobs:
target: ${{ matrix.platform.target }}
args: ${{ matrix.platform.args }}
strip: true
toolchain: "1.88.0"
toolchain: "1.89.0"
- name: Copy Release Binaries
if: github.event_name == 'create' && github.event.ref_type == 'tag'
shell: bash
@@ -54,7 +54,7 @@ jobs:
cp target/${{ matrix.platform.target }}/release/ch-remote ./${{ matrix.platform.name_ch_remote }}
- name: Upload Release Artifacts
if: github.event_name == 'create' && github.event.ref_type == 'tag'
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v6
with:
name: Artifacts for ${{ matrix.platform.target }}
path: |
@@ -80,7 +80,7 @@ jobs:
github.event_name == 'create' && github.event.ref_type == 'tag' &&
matrix.platform.target == 'x86_64-unknown-linux-gnu'
id: upload-release-cloud-hypervisor-vendored-sources
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v6
with:
path: cloud-hypervisor-${{ github.event.ref }}.tar.xz
name: cloud-hypervisor-${{ github.event.ref }}.tar.xz

View File

@@ -7,6 +7,6 @@ jobs:
name: REUSE Compliance Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: REUSE Compliance Check
uses: fsfe/reuse-action@v6

View File

@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Run the shell script checkers
uses: luizm/action-sh-checker@master
env:

View File

@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Code checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Install build dependencies

View File

@@ -1,7 +1,7 @@
[general]
extra-path=scripts/gitlint/rules
regex-style-search=true
ignore=body-max-line-length
ignore=body-max-line-length,body-hard-tab
[ignore-by-author-name]
regex=dependabot

View File

@@ -14,11 +14,33 @@ License](https://opensource.org/licenses/Apache-2.0).
## Coding Style
We follow the [Rust Style](https://github.com/rust-lang/rust/tree/HEAD/src/doc/style-guide/src)
convention and enforce it through the Continuous Integration (CI) process calling into `rustfmt`
for each submitted Pull Request (PR).
convention and enforce it through the Continuous Integration (CI) process calling into `rustfmt`,
`clippy`, and other well-known code quality tool of the ecosystem for each submitted Pull Request (PR).
## Basic Checks
```sh
# We currently rely on nightly-only formatting features
cargo +nightly fmt --all
cargo check --all-targets --tests
cargo clippy --all-targets --tests
# Please note that this will not execute integration tests.
cargo test --all-targets --tests
# To lint your last three commits
gitlint --commits "HEAD~3..HEAD"
```
### \[Optional\] Run Integration Tests
_Caution: These tests are taking a long time to complete (40+ mins) and need special setup._
```sh
bash ./scripts/dev_cli.sh tests --integration -- --test-filter '<optionally filter test by name pattern>'
```
### Setup Commit Hook
Please consider creating the following hook as `.git/hooks/pre-commit` in order
to ensure basic correctness of your code. You can extend this further if you
have specific features that you regularly develop against.
@@ -26,9 +48,9 @@ have specific features that you regularly develop against.
```sh
#!/bin/sh
cargo fmt -- --check || exit 1
cargo check --locked --all --all-targets --tests || exit 1
cargo clippy --locked --all --all-targets --tests -- -D warnings || exit 1
cargo +nightly fmt --all -- --check || exit 1
cargo check --locked --all-targets --tests || exit 1
cargo clippy --locked --all-targets --tests -- -D warnings || exit 1
```
You will need to `chmod +x .git/hooks/pre-commit` to have it run on every

353
Cargo.lock generated
View File

@@ -27,9 +27,9 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]]
name = "aho-corasick"
version = "1.1.3"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
dependencies = [
"memchr",
]
@@ -66,22 +66,22 @@ dependencies = [
[[package]]
name = "anstyle-query"
version = "1.1.4"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2"
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
dependencies = [
"windows-sys 0.60.2",
"windows-sys 0.61.0",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.10"
version = "3.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a"
checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
dependencies = [
"anstyle",
"once_cell_polyfill",
"windows-sys 0.60.2",
"windows-sys 0.61.0",
]
[[package]]
@@ -311,9 +311,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.9.4"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394"
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
[[package]]
name = "block"
@@ -321,6 +321,7 @@ version = "0.1.0"
dependencies = [
"byteorder",
"crc-any",
"flate2",
"io-uring",
"libc",
"log",
@@ -334,6 +335,7 @@ dependencies = [
"vm-memory",
"vm-virtio",
"vmm-sys-util",
"zstd",
]
[[package]]
@@ -363,19 +365,21 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cc"
version = "1.2.41"
version = "1.2.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7"
checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215"
dependencies = [
"find-msvc-tools",
"jobserver",
"libc",
"shlex",
]
[[package]]
name = "cfg-if"
version = "1.0.3"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "cfg_aliases"
@@ -385,18 +389,18 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "clap"
version = "4.5.49"
version = "4.5.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4512b90fa68d3a9932cea5184017c5d200f5921df706d45e853537dea51508f"
checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.5.49"
version = "4.5.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0025e98baa12e766c67ba13ff4695a887a1eba19569aad00a472546795bd6730"
checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00"
dependencies = [
"anstream",
"anstyle",
@@ -413,7 +417,7 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
[[package]]
name = "cloud-hypervisor"
version = "49.0.0"
version = "50.0.0"
dependencies = [
"anyhow",
"api_client",
@@ -540,7 +544,7 @@ dependencies = [
"anyhow",
"arch",
"bitfield-struct 0.12.1",
"bitflags 2.9.4",
"bitflags 2.10.0",
"byteorder",
"event_monitor",
"hypervisor",
@@ -598,10 +602,16 @@ dependencies = [
]
[[package]]
name = "endi"
version = "1.1.0"
name = "either"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "endi"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099"
[[package]]
name = "enumflags2"
@@ -653,7 +663,7 @@ version = "4.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e74d68fe2927dbf47aa976d14d93db9b23dced457c7bb2bdc6925a16d31b736e"
dependencies = [
"bitflags 2.9.4",
"bitflags 2.10.0",
"libc",
]
@@ -700,6 +710,7 @@ version = "0.1.0"
dependencies = [
"flume",
"libc",
"log",
"serde",
"serde_json",
]
@@ -709,6 +720,9 @@ name = "fastrand"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
dependencies = [
"getrandom 0.2.15",
]
[[package]]
name = "fdt"
@@ -718,19 +732,29 @@ checksum = "784a4df722dc6267a04af36895398f59d21d07dce47232adf31ec0ff2fa45e67"
[[package]]
name = "find-msvc-tools"
version = "0.1.4"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127"
checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844"
[[package]]
name = "flate2"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]]
name = "flume"
version = "0.11.1"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095"
checksum = "5e139bc46ca777eb5efaf62df0ab8cc5fd400866427e56c68b22e414e53bd3be"
dependencies = [
"fastrand",
"futures-core",
"futures-sink",
"nanorand",
"spin",
]
@@ -848,7 +872,7 @@ version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72742d2b395902caf8a5d520d0dd3334ba6d1138938429200e58d5174e275f3f"
dependencies = [
"bitflags 2.9.4",
"bitflags 2.10.0",
"cfg-if",
"log",
"managed",
@@ -875,20 +899,20 @@ dependencies = [
"cfg-if",
"js-sys",
"libc",
"wasi 0.11.1+wasi-snapshot-preview1",
"wasi",
"wasm-bindgen",
]
[[package]]
name = "getrandom"
version = "0.3.3"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
dependencies = [
"cfg-if",
"libc",
"r-efi",
"wasi 0.14.2+wasi-0.2.4",
"wasip2",
]
[[package]]
@@ -905,9 +929,9 @@ checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
[[package]]
name = "hashbrown"
version = "0.16.0"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
[[package]]
name = "hermit-abi"
@@ -997,9 +1021,9 @@ dependencies = [
[[package]]
name = "indexmap"
version = "2.11.4"
version = "2.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5"
checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2"
dependencies = [
"equivalent",
"hashbrown",
@@ -1007,11 +1031,11 @@ dependencies = [
[[package]]
name = "io-uring"
version = "0.7.10"
version = "0.7.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b"
checksum = "fdd7bddefd0a8833b88a4b68f90dae22c7450d11b354198baee3874fd811b344"
dependencies = [
"bitflags 2.9.4",
"bitflags 2.10.0",
"cfg-if",
"libc",
]
@@ -1027,9 +1051,18 @@ dependencies = [
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
[[package]]
name = "itertools"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
dependencies = [
"either",
]
[[package]]
name = "itoa"
@@ -1039,28 +1072,38 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "jiff"
version = "0.2.15"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49"
checksum = "49cce2b81f2098e7e3efc35bc2e0a6b7abec9d34128283d7a26fa8f32a6dbb35"
dependencies = [
"jiff-static",
"log",
"portable-atomic",
"portable-atomic-util",
"serde",
"serde_core",
]
[[package]]
name = "jiff-static"
version = "0.2.15"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4"
checksum = "980af8b43c3ad5d8d349ace167ec8170839f753a42d233ba19e08afe1850fa69"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "jobserver"
version = "0.1.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
dependencies = [
"getrandom 0.3.4",
"libc",
]
[[package]]
name = "js-sys"
version = "0.3.77"
@@ -1088,7 +1131,7 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c8f7370330b4f57981e300fa39b02088f2f2a5c2d0f1f994e8090589619c56d"
dependencies = [
"bitflags 2.9.4",
"bitflags 2.10.0",
"kvm-bindings",
"libc",
"vmm-sys-util",
@@ -1096,9 +1139,9 @@ dependencies = [
[[package]]
name = "landlock"
version = "0.4.3"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "affe8b77dce5b172f8e290bd801b12832a77cd1942d1ea98259916e89d5829d6"
checksum = "49fefd6652c57d68aaa32544a4c0e642929725bdc1fd929367cdeb673ab81088"
dependencies = [
"enumflags2",
"libc",
@@ -1113,9 +1156,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.177"
version = "0.2.178"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
[[package]]
name = "libredox"
@@ -1123,7 +1166,7 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb"
dependencies = [
"bitflags 2.9.4",
"bitflags 2.10.0",
"libc",
]
@@ -1143,9 +1186,9 @@ dependencies = [
[[package]]
name = "libz-sys"
version = "1.1.22"
version = "1.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d"
checksum = "15d118bbf3771060e7311cc7bb0545b01d08a8b4a7de949198dec1fa0ca1c0f7"
dependencies = [
"cc",
"libc",
@@ -1179,9 +1222,9 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.28"
version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
name = "managed"
@@ -1220,6 +1263,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
dependencies = [
"adler2",
"simd-adler32",
]
[[package]]
@@ -1230,9 +1274,9 @@ checksum = "c505b3e17ed6b70a7ed2e67fbb2c560ee327353556120d6e72f5232b6880d536"
[[package]]
name = "mshv-bindings"
version = "0.6.0"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "805cf329582f770f62cc612716a04c14815276ae266b6298375a672d3c5a5184"
checksum = "66f415da68542aca92b33f55ac3e93031dc30a2941952b99679258f7e0527353"
dependencies = [
"libc",
"num_enum",
@@ -1244,9 +1288,9 @@ dependencies = [
[[package]]
name = "mshv-ioctls"
version = "0.6.0"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aefaab4c067cf5226a917227640d835327b25b71a8d465f815f74f490344e10a"
checksum = "e52a2a02c4107e08f46ba9dfc4e0f4461dffd44fbeca3e5631b4a047d15376c9"
dependencies = [
"libc",
"mshv-bindings",
@@ -1254,15 +1298,6 @@ dependencies = [
"vmm-sys-util",
]
[[package]]
name = "nanorand"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3"
dependencies = [
"getrandom 0.2.15",
]
[[package]]
name = "net_gen"
version = "0.1.0"
@@ -1275,7 +1310,7 @@ name = "net_util"
version = "0.1.0"
dependencies = [
"epoll",
"getrandom 0.3.3",
"getrandom 0.3.4",
"libc",
"log",
"net_gen",
@@ -1298,7 +1333,7 @@ version = "0.30.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
dependencies = [
"bitflags 2.9.4",
"bitflags 2.10.0",
"cfg-if",
"cfg_aliases",
"libc",
@@ -1322,9 +1357,9 @@ dependencies = [
[[package]]
name = "num_enum"
version = "0.7.4"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a"
checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c"
dependencies = [
"num_enum_derive",
"rustversion",
@@ -1332,9 +1367,9 @@ dependencies = [
[[package]]
name = "num_enum_derive"
version = "0.7.4"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d"
checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7"
dependencies = [
"proc-macro-crate",
"proc-macro2",
@@ -1359,9 +1394,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "once_cell_polyfill"
version = "1.70.1"
version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]]
name = "open-enum"
@@ -1385,18 +1420,18 @@ dependencies = [
[[package]]
name = "openssl-src"
version = "300.5.3+3.5.4"
version = "300.5.4+3.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc6bad8cd0233b63971e232cc9c5e83039375b8586d2312f31fda85db8f888c2"
checksum = "a507b3792995dae9b0df8a1c1e3771e8418b7c2d9f0baeba32e6fe8b06c7cb72"
dependencies = [
"cc",
]
[[package]]
name = "openssl-sys"
version = "0.9.109"
version = "0.9.111"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571"
checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321"
dependencies = [
"cc",
"libc",
@@ -1665,18 +1700,18 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.101"
version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.41"
version = "1.0.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
dependencies = [
"proc-macro2",
]
@@ -1713,7 +1748,7 @@ version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
dependencies = [
"getrandom 0.3.3",
"getrandom 0.3.4",
]
[[package]]
@@ -1739,7 +1774,7 @@ version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
dependencies = [
"bitflags 2.9.4",
"bitflags 2.10.0",
]
[[package]]
@@ -1811,7 +1846,7 @@ version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e"
dependencies = [
"bitflags 2.9.4",
"bitflags 2.10.0",
"errno",
"libc",
"linux-raw-sys",
@@ -1901,9 +1936,9 @@ dependencies = [
[[package]]
name = "serde_with"
version = "3.15.0"
version = "3.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6093cd8c01b25262b84927e0f7151692158fab02d961e04c979d3903eba7ecc5"
checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7"
dependencies = [
"serde_core",
"serde_with_macros",
@@ -1911,9 +1946,9 @@ dependencies = [
[[package]]
name = "serde_with_macros"
version = "3.15.0"
version = "3.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7e6c180db0816026a61afa1cff5344fb7ebded7e4d3062772179f2501481c27"
checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c"
dependencies = [
"darling",
"proc-macro2",
@@ -1943,13 +1978,19 @@ dependencies = [
[[package]]
name = "signal-hook-registry"
version = "1.4.6"
version = "1.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b"
checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad"
dependencies = [
"libc",
]
[[package]]
name = "simd-adler32"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2"
[[package]]
name = "slab"
version = "0.4.11"
@@ -1977,7 +2018,7 @@ version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f84d13b3b8a0d4e91a2629911e951db1bb8671512f5c09d7d4ba34500ba68c8"
dependencies = [
"bitflags 2.9.4",
"bitflags 2.10.0",
"libc",
"libssh2-sys",
"parking_lot",
@@ -1997,9 +2038,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.106"
version = "2.0.111"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87"
dependencies = [
"proc-macro2",
"quote",
@@ -2013,7 +2054,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16"
dependencies = [
"fastrand",
"getrandom 0.3.3",
"getrandom 0.3.4",
"once_cell",
"rustix",
"windows-sys 0.61.0",
@@ -2100,9 +2141,9 @@ dependencies = [
[[package]]
name = "toml_edit"
version = "0.23.7"
version = "0.23.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d"
checksum = "5d7cbc3b4b49633d57a0509303158ca50de80ae32c265093b24c414705807832"
dependencies = [
"indexmap",
"toml_datetime",
@@ -2143,9 +2184,9 @@ dependencies = [
[[package]]
name = "tracing"
version = "0.1.41"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647"
dependencies = [
"pin-project-lite",
"tracing-attributes",
@@ -2154,9 +2195,9 @@ dependencies = [
[[package]]
name = "tracing-attributes"
version = "0.1.30"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
dependencies = [
"proc-macro2",
"quote",
@@ -2165,9 +2206,9 @@ dependencies = [
[[package]]
name = "tracing-core"
version = "0.1.34"
version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c"
dependencies = [
"once_cell",
]
@@ -2185,9 +2226,9 @@ dependencies = [
[[package]]
name = "unicode-ident"
version = "1.0.19"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
[[package]]
name = "utf8parse"
@@ -2197,13 +2238,14 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "uuid"
version = "1.18.1"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2"
checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a"
dependencies = [
"getrandom 0.3.3",
"getrandom 0.3.4",
"js-sys",
"rand",
"serde_core",
"wasm-bindgen",
]
@@ -2247,7 +2289,7 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8db5bc783aad75202ad4cbcdc5e893cff1dd8fa24a1bcdb4de8998d3c4d169a"
dependencies = [
"bitflags 2.9.4",
"bitflags 2.10.0",
"libc",
"log",
"serde",
@@ -2265,7 +2307,7 @@ version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a4dcad85a129d97d5d4b2f3c47a4affdeedd76bdcd02094bcb5d9b76cac2d05"
dependencies = [
"bitflags 2.9.4",
"bitflags 2.10.0",
"libc",
"uuid",
"vm-memory",
@@ -2418,6 +2460,7 @@ name = "vm-migration"
version = "0.1.0"
dependencies = [
"anyhow",
"itertools",
"serde",
"serde_json",
"thiserror 2.0.17",
@@ -2439,7 +2482,7 @@ dependencies = [
"acpi_tables",
"anyhow",
"arch",
"bitflags 2.9.4",
"bitflags 2.10.0",
"block",
"blocking",
"cfg-if",
@@ -2518,12 +2561,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "wasi"
version = "0.14.2+wasi-0.2.4"
name = "wasip2"
version = "1.0.1+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
dependencies = [
"wit-bindgen-rt",
"wit-bindgen",
]
[[package]]
@@ -2697,27 +2740,24 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
[[package]]
name = "winnow"
version = "0.7.13"
version = "0.7.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf"
checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829"
dependencies = [
"memchr",
]
[[package]]
name = "wit-bindgen-rt"
version = "0.39.0"
name = "wit-bindgen"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
dependencies = [
"bitflags 2.9.4",
]
checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
[[package]]
name = "zbus"
version = "5.11.0"
version = "5.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d07e46d035fb8e375b2ce63ba4e4ff90a7f73cf2ffb0138b29e1158d2eaadf7"
checksum = "b622b18155f7a93d1cd2dc8c01d2d6a44e08fb9ebb7b3f9e6ed101488bad6c91"
dependencies = [
"async-broadcast",
"async-executor",
@@ -2739,7 +2779,8 @@ dependencies = [
"serde_repr",
"tracing",
"uds_windows",
"windows-sys 0.60.2",
"uuid",
"windows-sys 0.61.0",
"winnow",
"zbus_macros",
"zbus_names",
@@ -2748,9 +2789,9 @@ dependencies = [
[[package]]
name = "zbus_macros"
version = "5.11.0"
version = "5.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57e797a9c847ed3ccc5b6254e8bcce056494b375b511b3d6edcec0aeb4defaca"
checksum = "1cdb94821ca8a87ca9c298b5d1cbd80e2a8b67115d99f6e4551ac49e42b6a314"
dependencies = [
"proc-macro-crate",
"proc-macro2",
@@ -2775,18 +2816,18 @@ dependencies = [
[[package]]
name = "zerocopy"
version = "0.8.27"
version = "0.8.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c"
checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.27"
version = "0.8.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831"
checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a"
dependencies = [
"proc-macro2",
"quote",
@@ -2794,10 +2835,38 @@ dependencies = [
]
[[package]]
name = "zvariant"
version = "5.7.0"
name = "zstd"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "999dd3be73c52b1fccd109a4a81e4fcd20fab1d3599c8121b38d04e1419498db"
checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
dependencies = [
"zstd-safe",
]
[[package]]
name = "zstd-safe"
version = "7.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
dependencies = [
"zstd-sys",
]
[[package]]
name = "zstd-sys"
version = "2.0.16+zstd.1.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748"
dependencies = [
"cc",
"pkg-config",
]
[[package]]
name = "zvariant"
version = "5.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2be61892e4f2b1772727be11630a62664a1826b62efa43a6fe7449521cb8744c"
dependencies = [
"endi",
"enumflags2",
@@ -2809,9 +2878,9 @@ dependencies = [
[[package]]
name = "zvariant_derive"
version = "5.7.0"
version = "5.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6643fd0b26a46d226bd90d3f07c1b5321fe9bb7f04673cb37ac6d6883885b68e"
checksum = "da58575a1b2b20766513b1ec59d8e2e68db2745379f961f86650655e862d2006"
dependencies = [
"proc-macro-crate",
"proc-macro2",

View File

@@ -1,21 +1,6 @@
[package]
authors = ["The Cloud Hypervisor Authors"]
build = "build.rs"
default-run = "cloud-hypervisor"
description = "Open source Virtual Machine Monitor (VMM) that runs on top of KVM & MSHV"
edition = "2024"
homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
license = "Apache-2.0 AND BSD-3-Clause"
name = "cloud-hypervisor"
version = "49.0.0"
# Minimum buildable version:
# Keep in sync with version in .github/workflows/build.yaml
# Policy on MSRV (see #4318):
# Can only be bumped if satisfying any of the following:
# a.) A dependency requires it,
# b.) If we want to use a new feature and that MSRV is at least 6 months old,
# c.) There is a security issue that is addressed by the toolchain update.
rust-version = "1.88.0"
# Cloud Hypervisor Workspace
#
# The main crate producing the binaries is in `./cloud-hypervisor`.
[profile.release]
codegen-units = 1
@@ -28,59 +13,12 @@ debug = true
inherits = "release"
strip = false
[dependencies]
anyhow = { workspace = true }
api_client = { path = "api_client" }
clap = { workspace = true, features = ["string"] }
dhat = { workspace = true, optional = true }
env_logger = { workspace = true }
epoll = { workspace = true }
event_monitor = { path = "event_monitor" }
hypervisor = { path = "hypervisor" }
libc = { workspace = true }
log = { workspace = true, features = ["std"] }
option_parser = { path = "option_parser" }
seccompiler = { workspace = true }
serde_json = { workspace = true }
signal-hook = { workspace = true }
thiserror = { workspace = true }
tpm = { path = "tpm" }
tracer = { path = "tracer" }
vm-memory = { workspace = true }
vmm = { path = "vmm" }
vmm-sys-util = { workspace = true }
zbus = { version = "5.7.1", optional = true }
[dev-dependencies]
dirs = { workspace = true }
net_util = { path = "net_util" }
serde_json = { workspace = true }
test_infra = { path = "test_infra" }
wait-timeout = { workspace = true }
# Please adjust `vmm::feature_list()` accordingly when changing the
# feature list below
[features]
dbus_api = ["vmm/dbus_api", "zbus"]
default = ["io_uring", "kvm"]
dhat-heap = ["dhat", "vmm/dhat-heap"] # For heap profiling
fw_cfg = ["vmm/fw_cfg"]
guest_debug = ["vmm/guest_debug"]
igvm = ["mshv", "vmm/igvm"]
io_uring = ["vmm/io_uring"]
ivshmem = ["vmm/ivshmem"]
kvm = ["vmm/kvm"]
mshv = ["vmm/mshv"]
pvmemcontrol = ["vmm/pvmemcontrol"]
sev_snp = ["igvm", "mshv", "vmm/sev_snp"]
tdx = ["vmm/tdx"]
tracing = ["tracer/tracing", "vmm/tracing"]
[workspace]
members = [
"api_client",
"arch",
"block",
"cloud-hypervisor",
"devices",
"event_monitor",
"hypervisor",
@@ -103,6 +41,7 @@ members = [
"vmm",
]
package.edition = "2024"
resolver = "3"
[workspace.dependencies]
# rust-vmm crates
@@ -110,8 +49,8 @@ acpi_tables = { git = "https://github.com/rust-vmm/acpi_tables", branch = "main"
kvm-bindings = "0.12.1"
kvm-ioctls = "0.22.1"
linux-loader = "0.13.1"
mshv-bindings = "0.6.0"
mshv-ioctls = "0.6.0"
mshv-bindings = "0.6.5"
mshv-ioctls = "0.6.5"
seccompiler = "0.5.0"
vfio-bindings = { version = "0.6.0", default-features = false }
vfio-ioctls = { version = "0.5.1", default-features = false }
@@ -132,23 +71,52 @@ igvm_defs = { git = "https://github.com/microsoft/igvm", branch = "main" }
# serde crates
serde = "1.0.228"
serde_json = "1.0.145"
serde_with = { version = "3.15.0", default-features = false }
serde_with = { version = "3.16.1", default-features = false }
# other crates
anyhow = "1.0.99"
bitflags = "2.9.4"
bitflags = "2.10.0"
byteorder = "1.5.0"
cfg-if = "1.0.3"
clap = "4.5.49"
cfg-if = "1.0.4"
clap = "4.5.53"
dhat = "0.3.3"
dirs = "6.0.0"
env_logger = "0.11.8"
epoll = "4.4.0"
flume = "0.11.1"
libc = "0.2.177"
log = "0.4.28"
flume = "0.12.0"
itertools = "0.14.0"
libc = "0.2.178"
log = "0.4.29"
signal-hook = "0.3.18"
thiserror = "2.0.17"
uuid = { version = "1.18.1" }
uuid = { version = "1.19.0" }
wait-timeout = "0.2.1"
zerocopy = { version = "0.8.27", default-features = false }
zerocopy = { version = "0.8.31", default-features = false }
[workspace.lints.clippy]
# Any clippy lint (group) in alphabetical order:
# https://rust-lang.github.io/rust-clippy/master/index.html
# Groups
all = "deny" # shorthand for the other groups but here for compleness
complexity = "deny"
correctness = "deny"
perf = "deny"
style = "deny"
suspicious = "deny"
# Individual Lints
assertions_on_result_states = "deny"
if_not_else = "deny"
manual_string_new = "deny"
map_unwrap_or = "deny"
needless_pass_by_value = "deny"
redundant_else = "deny"
semicolon_if_nothing_returned = "deny"
undocumented_unsafe_blocks = "deny"
uninlined_format_args = "deny"
unnecessary_semicolon = "deny"
[workspace.lints.rust]
# `level = warn` is irrelevant here but mandatory for rustc/cargo
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(devcli_testenv)'] }

View File

@@ -7,3 +7,6 @@ version = "0.1.0"
[dependencies]
thiserror = { workspace = true }
vmm-sys-util = { workspace = true }
[lints]
workspace = true

View File

@@ -142,7 +142,7 @@ pub fn simple_api_full_command_with_fds_and_response<T: Read + Write + ScmSocket
method: &str,
full_command: &str,
request_body: Option<&str>,
request_fds: Vec<RawFd>,
request_fds: &[RawFd],
) -> Result<Option<String>, Error> {
socket
.send_with_fds(
@@ -150,7 +150,7 @@ pub fn simple_api_full_command_with_fds_and_response<T: Read + Write + ScmSocket
"{method} /api/v1/{full_command} HTTP/1.1\r\nHost: localhost\r\nAccept: */*\r\n"
)
.as_bytes()],
&request_fds,
request_fds,
)
.map_err(Error::SocketSendFds)?;
@@ -178,7 +178,7 @@ pub fn simple_api_full_command_with_fds<T: Read + Write + ScmSocket>(
method: &str,
full_command: &str,
request_body: Option<&str>,
request_fds: Vec<RawFd>,
request_fds: &[RawFd],
) -> Result<(), Error> {
let response = simple_api_full_command_with_fds_and_response(
socket,
@@ -201,7 +201,7 @@ pub fn simple_api_full_command<T: Read + Write + ScmSocket>(
full_command: &str,
request_body: Option<&str>,
) -> Result<(), Error> {
simple_api_full_command_with_fds(socket, method, full_command, request_body, Vec::new())
simple_api_full_command_with_fds(socket, method, full_command, request_body, &[])
}
pub fn simple_api_full_command_and_response<T: Read + Write + ScmSocket>(
@@ -210,13 +210,7 @@ pub fn simple_api_full_command_and_response<T: Read + Write + ScmSocket>(
full_command: &str,
request_body: Option<&str>,
) -> Result<Option<String>, Error> {
simple_api_full_command_with_fds_and_response(
socket,
method,
full_command,
request_body,
Vec::new(),
)
simple_api_full_command_with_fds_and_response(socket, method, full_command, request_body, &[])
}
pub fn simple_api_command_with_fds<T: Read + Write + ScmSocket>(
@@ -224,7 +218,7 @@ pub fn simple_api_command_with_fds<T: Read + Write + ScmSocket>(
method: &str,
c: &str,
request_body: Option<&str>,
request_fds: Vec<RawFd>,
request_fds: &[RawFd],
) -> Result<(), Error> {
// Create the full VM command. For VMM commands, use
// simple_api_full_command().
@@ -239,5 +233,5 @@ pub fn simple_api_command<T: Read + Write + ScmSocket>(
c: &str,
request_body: Option<&str>,
) -> Result<(), Error> {
simple_api_command_with_fds(socket, method, c, request_body, Vec::new())
simple_api_command_with_fds(socket, method, c, request_body, &[])
}

View File

@@ -27,3 +27,6 @@ vmm-sys-util = { workspace = true, features = ["with-serde"] }
[target.'cfg(any(target_arch = "aarch64", target_arch = "riscv64"))'.dependencies]
fdt_parser = { version = "0.1.5", package = "fdt" }
vm-fdt = { workspace = true }
[lints]
workspace = true

View File

@@ -19,6 +19,7 @@ use hypervisor::arch::aarch64::regs::{
AARCH64_ARCH_TIMER_HYP_IRQ, AARCH64_ARCH_TIMER_PHYS_NONSECURE_IRQ,
AARCH64_ARCH_TIMER_PHYS_SECURE_IRQ, AARCH64_ARCH_TIMER_VIRT_IRQ, AARCH64_PMU_IRQ,
};
use log::{debug, warn};
use thiserror::Error;
use vm_fdt::{FdtWriter, FdtWriterResult};
use vm_memory::{Address, Bytes, GuestMemory, GuestMemoryError, GuestMemoryRegion};
@@ -87,6 +88,7 @@ pub enum Error {
}
type Result<T> = result::Result<T, Error>;
#[derive(Copy, Clone)]
pub enum CacheLevel {
/// L1 data cache
L1D = 0,
@@ -110,9 +112,7 @@ pub fn get_cache_size(cache_level: CacheLevel) -> u32 {
}
let file_path = Path::new(&file_directory);
if !file_path.exists() {
0
} else {
if file_path.exists() {
let src = fs::read_to_string(file_directory).expect("File not exists or file corrupted.");
// The content of the file is as simple as a size, like: "32K"
let src = src.trim();
@@ -126,6 +126,8 @@ pub fn get_cache_size(cache_level: CacheLevel) -> u32 {
"G" => 1024u32.pow(3),
_ => 1,
}
} else {
0
}
}
@@ -141,11 +143,11 @@ pub fn get_cache_coherency_line_size(cache_level: CacheLevel) -> u32 {
}
let file_path = Path::new(&file_directory);
if !file_path.exists() {
0
} else {
if file_path.exists() {
let src = fs::read_to_string(file_directory).expect("File not exists or file corrupted.");
src.trim().parse::<u32>().unwrap()
} else {
0
}
}
@@ -161,11 +163,11 @@ pub fn get_cache_number_of_sets(cache_level: CacheLevel) -> u32 {
}
let file_path = Path::new(&file_directory);
if !file_path.exists() {
0
} else {
if file_path.exists() {
let src = fs::read_to_string(file_directory).expect("File not exists or file corrupted.");
src.trim().parse::<u32>().unwrap()
} else {
0
}
}
@@ -186,9 +188,7 @@ pub fn get_cache_shared(cache_level: CacheLevel) -> bool {
}
let file_path = Path::new(&file_directory);
if !file_path.exists() {
result = false;
} else {
if file_path.exists() {
let src = fs::read_to_string(file_directory).expect("File not exists or file corrupted.");
let src = src.trim();
if src.is_empty() {
@@ -196,6 +196,8 @@ pub fn get_cache_shared(cache_level: CacheLevel) -> bool {
} else {
result = src.contains('-') || src.contains(',');
}
} else {
result = false;
}
result
@@ -206,7 +208,7 @@ pub fn get_cache_shared(cache_level: CacheLevel) -> bool {
pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHasher>(
guest_mem: &GuestMemoryMmap,
cmdline: &str,
vcpu_mpidr: Vec<u64>,
vcpu_mpidr: &[u64],
vcpu_topology: Option<(u16, u16, u16, u16)>,
device_info: &HashMap<(DeviceType, String), T, S>,
gic_device: &Arc<Mutex<dyn Vgic>>,
@@ -233,7 +235,7 @@ pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHash
// This is not mandatory but we use it to point the root node to the node
// containing description of the interrupt controller for this VM.
fdt.property_u32("interrupt-parent", GIC_PHANDLE)?;
create_cpu_nodes(&mut fdt, &vcpu_mpidr, vcpu_topology, numa_nodes)?;
create_cpu_nodes(&mut fdt, vcpu_mpidr, vcpu_topology, numa_nodes)?;
create_memory_node(&mut fdt, guest_mem, numa_nodes)?;
create_chosen_node(&mut fdt, cmdline, initrd)?;
create_gic_node(&mut fdt, gic_device)?;
@@ -257,10 +259,10 @@ pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHash
Ok(fdt_final)
}
pub fn write_fdt_to_memory(fdt_final: Vec<u8>, guest_mem: &GuestMemoryMmap) -> Result<()> {
pub fn write_fdt_to_memory(fdt_final: &[u8], guest_mem: &GuestMemoryMmap) -> Result<()> {
// Write FDT to memory.
guest_mem
.write_slice(fdt_final.as_slice(), super::layout::FDT_START)
.write_slice(fdt_final, super::layout::FDT_START)
.map_err(Error::WriteFdtToMemory)?;
Ok(())
}
@@ -311,9 +313,7 @@ fn create_cpu_nodes(
let cache_path = Path::new("/sys/devices/system/cpu/cpu0/cache");
let cache_exist: bool = cache_path.exists();
if !cache_exist {
warn!("cache sysfs system does not exist.");
} else {
if cache_exist {
// L1 Data Cache Info.
l1_d_cache_size = get_cache_size(CacheLevel::L1D);
l1_d_cache_line_size = get_cache_coherency_line_size(CacheLevel::L1D);
@@ -341,6 +341,8 @@ fn create_cpu_nodes(
if l3_cache_size != 0 {
l3_cache_shared = get_cache_shared(CacheLevel::L3);
}
} else {
warn!("cache sysfs system does not exist.");
}
for (cpu_id, mpidr) in vcpu_mpidr.iter().enumerate().take(num_cpus) {
@@ -1150,7 +1152,7 @@ fn print_node(node: fdt_parser::node::FdtNode<'_, '_>, n_spaces: usize) {
array,
indent = (n_spaces + 2)
);
};
}
}
// Print children nodes if there is any

View File

@@ -125,7 +125,7 @@ pub fn arch_memory_regions() -> Vec<(GuestAddress, usize, RegionType)> {
pub fn configure_system<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHasher>(
guest_mem: &GuestMemoryMmap,
cmdline: &str,
vcpu_mpidr: Vec<u64>,
vcpu_mpidr: &[u64],
vcpu_topology: Option<(u16, u16, u16, u16)>,
device_info: &HashMap<(DeviceType, String), T, S>,
initrd: &Option<super::InitramfsConfig>,
@@ -154,7 +154,7 @@ pub fn configure_system<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::Bui
fdt::print_fdt(&fdt_final);
}
fdt::write_fdt_to_memory(fdt_final, guest_mem).map_err(Error::WriteFdtToMemory)?;
fdt::write_fdt_to_memory(&fdt_final, guest_mem).map_err(Error::WriteFdtToMemory)?;
Ok(())
}
@@ -192,7 +192,7 @@ pub fn get_host_cpu_phys_bits(hypervisor: &dyn hypervisor::Hypervisor) -> u8 {
}
#[cfg(test)]
mod tests {
mod unit_tests {
use super::*;
#[test]

View File

@@ -8,9 +8,6 @@
//! Implements platform specific functionality.
//! Supported platforms: x86_64, aarch64, riscv64.
#[macro_use]
extern crate log;
use std::collections::BTreeMap;
use std::sync::Arc;
use std::{fmt, result};

View File

@@ -15,6 +15,7 @@ use std::{cmp, result, str};
use byteorder::{BigEndian, ByteOrder};
use hypervisor::arch::riscv64::aia::Vaia;
use log::debug;
use thiserror::Error;
use vm_fdt::{FdtWriter, FdtWriterResult};
use vm_memory::{Address, Bytes, GuestMemory, GuestMemoryError, GuestMemoryRegion};
@@ -65,6 +66,7 @@ pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHash
guest_mem: &GuestMemoryMmap,
cmdline: &str,
num_vcpu: u32,
isa_string: &str,
device_info: &HashMap<(DeviceType, String), T, S>,
aia_device: &Arc<Mutex<dyn Vaia>>,
initrd: &Option<InitramfsConfig>,
@@ -84,7 +86,7 @@ pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHash
// Properties
fdt.property_u32("#address-cells", ADDRESS_CELLS)?;
fdt.property_u32("#size-cells", SIZE_CELLS)?;
create_cpu_nodes(&mut fdt, num_vcpu)?;
create_cpu_nodes(&mut fdt, num_vcpu, isa_string)?;
create_memory_node(&mut fdt, guest_mem)?;
create_chosen_node(&mut fdt, cmdline, initrd)?;
create_aia_node(&mut fdt, aia_device)?;
@@ -99,16 +101,16 @@ pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHash
Ok(fdt_final)
}
pub fn write_fdt_to_memory(fdt_final: Vec<u8>, guest_mem: &GuestMemoryMmap) -> Result<()> {
pub fn write_fdt_to_memory(fdt_final: &[u8], guest_mem: &GuestMemoryMmap) -> Result<()> {
// Write FDT to memory.
guest_mem
.write_slice(fdt_final.as_slice(), super::layout::FDT_START)
.write_slice(fdt_final, super::layout::FDT_START)
.map_err(Error::WriteFdtToMemory)?;
Ok(())
}
// Following are the auxiliary function for creating the different nodes that we append to our FDT.
fn create_cpu_nodes(fdt: &mut FdtWriter, num_cpus: u32) -> FdtWriterResult<()> {
fn create_cpu_nodes(fdt: &mut FdtWriter, num_cpus: u32, isa_string: &str) -> FdtWriterResult<()> {
// See https://elixir.bootlin.com/linux/v6.10/source/Documentation/devicetree/bindings/riscv/cpus.yaml
let cpus = fdt.begin_node("cpus")?;
// As per documentation, on RISC-V 64-bit systems value should be set to 1.
@@ -123,7 +125,7 @@ fn create_cpu_nodes(fdt: &mut FdtWriter, num_cpus: u32) -> FdtWriterResult<()> {
fdt.property_string("device_type", "cpu")?;
fdt.property_string("compatible", "riscv")?;
fdt.property_string("mmu-type", "sv48")?;
fdt.property_string("riscv,isa", "rv64imafdc_smaia_ssaia")?;
fdt.property_string("riscv,isa", isa_string)?;
fdt.property_string("status", "okay")?;
fdt.property_u32("reg", cpu_index)?;
fdt.property_u32("phandle", CPU_BASE_PHANDLE + cpu_index)?;
@@ -471,7 +473,7 @@ fn print_node(node: fdt_parser::node::FdtNode<'_, '_>, n_spaces: usize) {
array,
indent = (n_spaces + 2)
);
};
}
}
// Print children nodes if there is any

View File

@@ -12,6 +12,8 @@ pub mod uefi;
use std::collections::HashMap;
use std::fmt::Debug;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::sync::{Arc, Mutex};
use hypervisor::arch::riscv64::aia::Vaia;
@@ -51,6 +53,22 @@ pub enum Error {
/// Error configuring the general purpose registers
#[error("Error configuring the general purpose registers")]
RegsConfiguration(#[source] hypervisor::HypervisorCpuError),
/// Error opening /proc/cpuinfo
#[error("Error opening /proc/cpuinfo")]
OpenCpuInfo(#[source] std::io::Error),
/// Error reading /proc/cpuinfo
#[error("Error reading /proc/cpuinfo")]
ReadCpuInfo(#[source] std::io::Error),
/// Invalid ISA string
#[error("Invalid ISA string: {0}")]
InvalidIsaString(String),
/// Error parsing /proc/cpuinfo
#[error("Error parsing /proc/cpuinfo")]
CpuInfoParsing,
}
#[derive(Debug, Copy, Clone)]
@@ -104,6 +122,43 @@ pub fn arch_memory_regions() -> Vec<(GuestAddress, usize, RegionType)> {
]
}
// Read the first "isa" string from /proc/cpuinfo and filter out the H extension,
// while correctly preserving multi-letter extensions.
fn isa_string_from_host() -> Result<String, Error> {
let file = File::open("/proc/cpuinfo").map_err(Error::OpenCpuInfo)?;
let reader = BufReader::new(file);
for line in reader.lines() {
let line = line.map_err(Error::ReadCpuInfo)?;
let trimmed_line = line.trim();
if trimmed_line.starts_with("isa") {
let parts: Vec<&str> = trimmed_line.split(':').collect();
if parts.len() == 2 {
let isa_string = parts[1].trim();
// Split the string by underscores to separate single letter vs long-form
// extensions
let mut components: Vec<String> =
isa_string.split('_').map(|s| s.to_string()).collect();
if components.is_empty() {
return Err(Error::InvalidIsaString(isa_string.to_string()));
}
// Remove H extension if present in single letter extensions
let first_component = components[0].chars().filter(|&c| c != 'h').collect();
components[0] = first_component;
return Ok(components.join("_"));
}
}
}
Err(Error::CpuInfoParsing)
}
/// Configures the system and should be called once per vm before starting vcpu threads.
#[allow(clippy::too_many_arguments)]
pub fn configure_system<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHasher>(
@@ -115,10 +170,12 @@ pub fn configure_system<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::Bui
pci_space_info: &[PciSpaceInfo],
aia_device: &Arc<Mutex<dyn Vaia>>,
) -> super::Result<()> {
let isa_string = isa_string_from_host()?;
let fdt_final = fdt::create_fdt(
guest_mem,
cmdline,
num_vcpu,
&isa_string,
device_info,
aia_device,
initrd,
@@ -130,7 +187,7 @@ pub fn configure_system<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::Bui
fdt::print_fdt(&fdt_final);
}
fdt::write_fdt_to_memory(fdt_final, guest_mem).map_err(Error::WriteFdtToMemory)?;
fdt::write_fdt_to_memory(&fdt_final, guest_mem).map_err(Error::WriteFdtToMemory)?;
Ok(())
}
@@ -161,7 +218,7 @@ pub fn get_host_cpu_phys_bits(_hypervisor: &dyn hypervisor::Hypervisor) -> u8 {
}
#[cfg(test)]
mod tests {
mod unit_tests {
use super::*;
#[test]

View File

@@ -6,11 +6,19 @@
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-BSD-3-Clause file.
pub mod interrupts;
pub mod layout;
pub mod regs;
#[cfg(feature = "tdx")]
pub mod tdx;
mod mpspec;
mod mptable;
pub mod regs;
mod smbios;
use std::arch::x86_64;
use std::mem;
use hypervisor::arch::x86::{CPUID_FLAG_VALID_INDEX, CpuIdEntry};
@@ -19,6 +27,7 @@ use linux_loader::loader::bootparam::{boot_params, setup_header};
use linux_loader::loader::elf::start_info::{
hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info,
};
use log::{debug, error, info};
use thiserror::Error;
use vm_memory::{
Address, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic,
@@ -26,10 +35,6 @@ use vm_memory::{
};
use crate::{GuestMemoryMmap, InitramfsConfig, RegionType};
mod smbios;
use std::arch::x86_64;
#[cfg(feature = "tdx")]
pub mod tdx;
// While modern architectures support more than 255 CPUs via x2APIC,
// legacy devices such as mptable support at most 254 CPUs.
@@ -39,12 +44,17 @@ pub const MAX_SUPPORTED_CPUS_LEGACY: u32 = 254;
#[cfg(feature = "kvm")]
const TSC_DEADLINE_TIMER_ECX_BIT: u8 = 24; // tsc deadline timer ecx bit.
const HYPERVISOR_ECX_BIT: u8 = 31; // Hypervisor ecx bit.
const VMX_ECX_BIT: u8 = 5; // VMX for Intel
const SVM_ECX_BIT: u8 = 2; // SVM for AMD
const MTRR_EDX_BIT: u8 = 12; // Hypervisor ecx bit.
const INVARIANT_TSC_EDX_BIT: u8 = 8; // Invariant TSC bit on 0x8000_0007 EDX
const AMX_BF16: u8 = 22; // AMX tile computation on bfloat16 numbers
const AMX_TILE: u8 = 24; // AMX tile load/store instructions
const AMX_INT8: u8 = 25; // AMX tile computation on 8-bit integers
const AMX_FP16: u8 = 21; // AMX tile computation on fp16 numbers
const AMX_COMPLEX: u8 = 8; // AMX tile computation on complex numbers
// KVM feature bits
#[cfg(feature = "tdx")]
const KVM_FEATURE_CLOCKSOURCE_BIT: u8 = 0;
@@ -278,7 +288,7 @@ impl CpuidPatch {
}
}
pub fn patch_cpuid(cpuid: &mut [CpuIdEntry], patches: Vec<CpuidPatch>) {
pub fn patch_cpuid(cpuid: &mut [CpuIdEntry], patches: &[CpuidPatch]) {
for entry in cpuid {
for patch in patches.iter() {
if entry.function == patch.function && entry.index == patch.index {
@@ -615,14 +625,14 @@ pub fn generate_common_cpuid(
.get_supported_cpuid()
.map_err(Error::CpuidGetSupported)?;
CpuidPatch::patch_cpuid(&mut cpuid, cpuid_patches);
CpuidPatch::patch_cpuid(&mut cpuid, &cpuid_patches);
#[cfg(feature = "tdx")]
let tdx_capabilities = if config.tdx {
let caps = hypervisor
.tdx_capabilities()
.map_err(Error::TdxCapabilities)?;
info!("TDX capabilities {:#?}", caps);
info!("TDX capabilities {caps:#?}");
Some(caps)
} else {
None
@@ -633,8 +643,14 @@ pub fn generate_common_cpuid(
match entry.function {
// Clear AMX related bits if the AMX feature is not enabled
0x7 => {
if !config.amx && entry.index == 0 {
entry.edx &= !((1 << AMX_BF16) | (1 << AMX_TILE) | (1 << AMX_INT8))
if !config.amx {
if entry.index == 0 {
entry.edx &= !((1 << AMX_BF16) | (1 << AMX_TILE) | (1 << AMX_INT8));
}
if entry.index == 1 {
entry.eax &= !(1 << AMX_FP16);
entry.edx &= !(1 << AMX_COMPLEX);
}
}
}
0xd =>
@@ -656,6 +672,25 @@ pub fn generate_common_cpuid(
}
}
}
0x1d => {
// Tile Information (purely AMX related).
if !config.amx {
entry.eax = 0;
entry.ebx = 0;
entry.ecx = 0;
entry.edx = 0;
}
}
0x1e => {
// TMUL information (purely AMX related)
if !config.amx {
entry.eax = 0;
entry.ebx = 0;
entry.ecx = 0;
entry.edx = 0;
}
}
// Copy host L1 cache details if not populated by KVM
0x8000_0005 => {
if entry.eax == 0 && entry.ebx == 0 && entry.ecx == 0 && entry.edx == 0 {
@@ -701,7 +736,7 @@ pub fn generate_common_cpuid(
| (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT)
| (1 << KVM_FEATURE_ASYNC_PF_BIT)
| (1 << KVM_FEATURE_ASYNC_PF_VMEXIT_BIT)
| (1 << KVM_FEATURE_STEAL_TIME_BIT))
| (1 << KVM_FEATURE_STEAL_TIME_BIT));
}
}
_ => {}
@@ -773,6 +808,7 @@ pub fn generate_common_cpuid(
Ok(cpuid)
}
#[allow(clippy::too_many_arguments)]
pub fn configure_vcpu(
vcpu: &dyn hypervisor::Vcpu,
id: u32,
@@ -781,6 +817,7 @@ pub fn configure_vcpu(
kvm_hyperv: bool,
cpu_vendor: CpuVendor,
topology: (u16, u16, u16, u16),
nested: bool,
) -> super::Result<()> {
let x2apic_id = get_x2apic_id(id, Some(topology));
@@ -799,6 +836,17 @@ pub fn configure_vcpu(
entry.ebx &= 0xffffff;
entry.ebx |= x2apic_id << 24;
apic_id_patched = true;
if !nested {
// Disable nested virtualization for Intel
entry.ecx &= !(1 << VMX_ECX_BIT);
}
break;
}
if entry.function == 0x8000_0001 {
if !nested {
// Disable the nested virtualization for AMD
entry.ecx &= !(1 << SVM_ECX_BIT);
}
break;
}
}
@@ -824,7 +872,7 @@ pub fn configure_vcpu(
* APIC_BUS_CYCLE_NS */
..Default::default()
});
};
}
}
for c in &cpuid {
@@ -1303,9 +1351,10 @@ fn update_cpuid_topology(
let die_width = u16::BITS - (dies_per_package - 1).leading_zeros() + core_width;
// The very old way: a flat number of logical CPUs per package: CPUID.1H:EBX[23:16] bits.
let core_count = dies_per_package as u32 * cores_per_die as u32 * threads_per_core as u32;
let mut cpu_ebx = CpuidPatch::get_cpuid_reg(cpuid, 0x1, None, CpuidReg::EBX).unwrap_or(0);
cpu_ebx |= ((dies_per_package as u32) * (cores_per_die as u32) * (threads_per_core as u32))
& (0xff << 16);
cpu_ebx &= !(0xff << 16);
cpu_ebx |= (core_count & 0xff) << 16;
CpuidPatch::set_cpuid_reg(cpuid, 0x1, None, CpuidReg::EBX, cpu_ebx);
let mut cpu_edx = CpuidPatch::get_cpuid_reg(cpuid, 0x1, None, CpuidReg::EDX).unwrap_or(0);
@@ -1346,6 +1395,7 @@ fn update_cpuid_topology(
u32::from(threads_per_core),
);
CpuidPatch::set_cpuid_reg(cpuid, 0x1f, Some(0), CpuidReg::ECX, 1 << 8);
CpuidPatch::set_cpuid_reg(cpuid, 0x1f, Some(0), CpuidReg::EDX, x2apic_id);
CpuidPatch::set_cpuid_reg(cpuid, 0x1f, Some(1), CpuidReg::EAX, core_width);
CpuidPatch::set_cpuid_reg(
@@ -1356,6 +1406,7 @@ fn update_cpuid_topology(
u32::from(cores_per_die * threads_per_core),
);
CpuidPatch::set_cpuid_reg(cpuid, 0x1f, Some(1), CpuidReg::ECX, 2 << 8);
CpuidPatch::set_cpuid_reg(cpuid, 0x1f, Some(1), CpuidReg::EDX, x2apic_id);
CpuidPatch::set_cpuid_reg(cpuid, 0x1f, Some(2), CpuidReg::EAX, die_width);
CpuidPatch::set_cpuid_reg(
@@ -1366,6 +1417,7 @@ fn update_cpuid_topology(
u32::from(dies_per_package * cores_per_die * threads_per_core),
);
CpuidPatch::set_cpuid_reg(cpuid, 0x1f, Some(2), CpuidReg::ECX, 5 << 8);
CpuidPatch::set_cpuid_reg(cpuid, 0x1f, Some(2), CpuidReg::EDX, x2apic_id);
if matches!(cpu_vendor, CpuVendor::AMD) {
CpuidPatch::set_cpuid_reg(
@@ -1412,7 +1464,7 @@ fn update_cpuid_topology(
edx_bit: Some(28),
},
];
CpuidPatch::patch_cpuid(cpuid, cpuid_patches);
CpuidPatch::patch_cpuid(cpuid, &cpuid_patches);
CpuidPatch::set_cpuid_reg(
cpuid,
0x8000_0008,
@@ -1427,7 +1479,7 @@ fn update_cpuid_topology(
}
}
#[cfg(test)]
mod tests {
mod unit_tests {
use linux_loader::loader::bootparam::boot_e820_entry;
use super::*;

View File

@@ -8,6 +8,7 @@
use std::{mem, result, slice};
use libc::c_uchar;
use log::{info, warn};
use thiserror::Error;
use vm_memory::{Address, ByteValued, Bytes, GuestAddress, GuestMemory, GuestMemoryError};
@@ -297,7 +298,7 @@ pub fn setup_mptable(
}
#[cfg(test)]
mod tests {
mod unit_tests {
use vm_memory::bitmap::BitmapSlice;
use vm_memory::{GuestUsize, VolatileMemoryError, VolatileSlice, WriteVolatile};

View File

@@ -82,7 +82,7 @@ pub fn setup_fpu(vcpu: &dyn hypervisor::Vcpu) -> Result<()> {
///
/// * `vcpu` - Structure for the VCPU that holds the VCPU's fd.
pub fn setup_msrs(vcpu: &dyn hypervisor::Vcpu) -> Result<()> {
vcpu.set_msrs(&vcpu.boot_msr_entries())
vcpu.set_msrs(vcpu.boot_msr_entries())
.map_err(Error::SetModelSpecificRegisters)?;
Ok(())
@@ -108,7 +108,7 @@ pub fn setup_regs(vcpu: &dyn hypervisor::Vcpu, entry_point: EntryPoint) -> Resul
regs.set_rsp(BOOT_STACK_POINTER.raw_value());
regs.set_rsi(ZERO_PAGE_START.raw_value());
}
};
}
vcpu.set_regs(&regs).map_err(Error::SetBaseRegisters)
}
@@ -196,7 +196,7 @@ pub fn configure_segments_and_sregs(
}
#[cfg(test)]
mod tests {
mod unit_tests {
use vm_memory::GuestAddress;
use super::*;

View File

@@ -272,7 +272,7 @@ pub fn setup_smbios(
}
#[cfg(test)]
mod tests {
mod unit_tests {
use super::*;
#[test]

View File

@@ -5,6 +5,7 @@ use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
use std::str::FromStr;
use log::{debug, info};
use thiserror::Error;
use uuid::Uuid;
use vm_memory::{ByteValued, Bytes, GuestAddress, GuestMemoryError};
@@ -304,7 +305,7 @@ fn align_hob(v: u64) -> u64 {
impl TdHob {
fn update_offset<T>(&mut self) {
self.current_offset = align_hob(self.current_offset + std::mem::size_of::<T>() as u64)
self.current_offset = align_hob(self.current_offset + std::mem::size_of::<T>() as u64);
}
pub fn start(offset: u64) -> TdHob {
@@ -519,7 +520,7 @@ impl TdHob {
}
#[cfg(test)]
mod tests {
mod unit_tests {
use super::*;
#[test]
@@ -528,7 +529,7 @@ mod tests {
let mut f = std::fs::File::open("tdvf.fd").unwrap();
let (sections, _) = parse_tdvf_sections(&mut f).unwrap();
for section in sections {
eprintln!("{section:x?}")
eprintln!("{section:x?}");
}
}
}

View File

@@ -11,7 +11,8 @@ io_uring = ["dep:io-uring"]
[dependencies]
byteorder = { workspace = true }
crc-any = "2.5.0"
io-uring = { version = "0.7.10", optional = true }
flate2 = "1.0"
io-uring = { version = "0.7.11", optional = true }
libc = { workspace = true }
log = { workspace = true }
remain = "0.2.15"
@@ -28,3 +29,7 @@ vm-memory = { workspace = true, features = [
] }
vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = { workspace = true }
zstd = "0.13"
[lints]
workspace = true

View File

@@ -18,6 +18,12 @@ pub enum DiskFileError {
/// Failed creating a new AsyncIo.
#[error("Failed creating a new AsyncIo")]
NewAsyncIo(#[source] std::io::Error),
/// Unsupported operation.
#[error("Unsupported operation")]
Unsupported,
/// Resize failed
#[error("Resize failed")]
ResizeError(#[source] std::io::Error),
}
pub type DiskFileResult<T> = std::result::Result<T, DiskFileError>;
@@ -56,11 +62,22 @@ impl AsRawFd for BorrowedDiskFd<'_> {
/// This allows abstracting over raw image formats as well as structured
/// image formats.
pub trait DiskFile: Send {
fn size(&mut self) -> DiskFileResult<u64>;
/// Returns the logical disk size a guest will see.
///
/// For raw formats, this is equal to [`Self::physical_size`]. For file formats
/// that wrap disk images in a container (e.g. QCOW2), this refers to the
/// effective size that the guest will see.
fn logical_size(&mut self) -> DiskFileResult<u64>;
/// Returns the physical size of the underlying file.
fn physical_size(&mut self) -> DiskFileResult<u64>;
fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>>;
fn topology(&mut self) -> DiskTopology {
DiskTopology::default()
}
fn resize(&mut self, _size: u64) -> DiskFileResult<()> {
Err(DiskFileError::Unsupported)
}
/// Returns the file descriptor of the underlying disk image file.
///
/// The file descriptor is supposed to be used for `fcntl()` calls but no

View File

@@ -101,13 +101,52 @@ impl LockState {
}
}
/// The granularity of the advisory lock.
///
/// The granularity has significant implications in typical cloud deployments
/// with network storage. The Linux kernel will sync advisory locks to network
/// file systems, but these backends may have different policies and handle
/// locks differently. For example, Netapp speaks a NFS API but will treat
/// advisory OFD locks for the whole file as mandatory locks, whereas byte-range
/// locks for the whole file will remain advisory [0].
///
/// As it is a valid use case to prevent multiple CHV instances from accessing
/// the same disk but disk management software (e.g., Cinder in OpenStack)
/// should be able to snapshot disks while VMs are running, we need special
/// control over the lock granularity. Therefore, it is a valid use case to lock
/// the whole byte range of a disk image without technically locking the whole
/// file - to get the best of both worlds.
///
/// [0] https://kb.netapp.com/on-prem/ontap/da/NAS/NAS-KBs/How_is_Mandatory_Locking_supported_for_NFSv4_on_ONTAP_9
#[derive(Clone, Copy, Debug)]
pub enum LockGranularity {
WholeFile,
ByteRange(u64 /* from, inclusive */, u64 /* len */),
}
impl LockGranularity {
const fn l_start(self) -> u64 {
match self {
LockGranularity::WholeFile => 0,
LockGranularity::ByteRange(start, _) => start,
}
}
const fn l_len(self) -> u64 {
match self {
LockGranularity::WholeFile => 0, /* EOF */
LockGranularity::ByteRange(_, len) => len,
}
}
}
/// Returns a [`struct@libc::flock`] structure for the whole file.
const fn get_flock(lock_type: LockType) -> libc::flock {
const fn get_flock(lock_type: LockType, granularity: LockGranularity) -> libc::flock {
libc::flock {
l_type: lock_type.to_libc_val() as libc::c_short,
l_whence: libc::SEEK_SET as libc::c_short,
l_start: 0,
l_len: 0, /* EOF */
l_start: granularity.l_start() as libc::c_long,
l_len: granularity.l_len() as libc::c_long,
l_pid: 0, /* filled by callee */
}
}
@@ -122,8 +161,13 @@ const fn get_flock(lock_type: LockType) -> libc::flock {
/// - `file`: The file to acquire a lock for [`LockType`]. The file's state will
/// be logically mutated, but not technically.
/// - `lock_type`: The [`LockType`]
pub fn try_acquire_lock<Fd: AsRawFd>(file: Fd, lock_type: LockType) -> Result<(), LockError> {
let flock = get_flock(lock_type);
/// - `granularity`: The [`LockGranularity`].
pub fn try_acquire_lock<Fd: AsRawFd>(
file: &Fd,
lock_type: LockType,
granularity: LockGranularity,
) -> Result<(), LockError> {
let flock = get_flock(lock_type, granularity);
let res = fcntl(file.as_raw_fd(), FcntlArg::F_OFD_SETLK(&flock));
match res {
@@ -146,8 +190,9 @@ pub fn try_acquire_lock<Fd: AsRawFd>(file: Fd, lock_type: LockType) -> Result<()
///
/// # Parameters
/// - `file`: The file to clear all locks for [`LockType`].
pub fn clear_lock<Fd: AsRawFd>(file: Fd) -> Result<(), LockError> {
try_acquire_lock(file, LockType::Unlock)
/// - `granularity`: The [`LockGranularity`].
pub fn clear_lock<Fd: AsRawFd>(file: &Fd, granularity: LockGranularity) -> Result<(), LockError> {
try_acquire_lock(file, LockType::Unlock, granularity)
}
/// Returns the current lock state using [`fcntl`] with respect to the given
@@ -155,8 +200,12 @@ pub fn clear_lock<Fd: AsRawFd>(file: Fd) -> Result<(), LockError> {
///
/// # Parameters
/// - `file`: The file for which to get the lock state.
pub fn get_lock_state<Fd: AsRawFd>(file: Fd) -> Result<LockState, LockError> {
let mut flock = get_flock(LockType::Write);
/// - `granularity`: The [`LockGranularity`].
pub fn get_lock_state<Fd: AsRawFd>(
file: &Fd,
granularity: LockGranularity,
) -> Result<LockState, LockError> {
let mut flock = get_flock(LockType::Write, granularity);
let res = fcntl(file.as_raw_fd(), FcntlArg::F_OFD_GETLK(&mut flock));
match res {
0 => {

View File

@@ -75,9 +75,17 @@ impl Seek for FixedVhd {
}
impl BlockBackend for FixedVhd {
fn size(&self) -> std::result::Result<u64, crate::Error> {
fn logical_size(&self) -> Result<u64, crate::Error> {
Ok(self.size)
}
/// Returns the physical size of the underlying file.
fn physical_size(&self) -> Result<u64, crate::Error> {
self.file
.metadata()
.map(|m| m.len())
.map_err(crate::Error::GetFileMetadata)
}
}
impl Clone for FixedVhd {

View File

@@ -23,14 +23,22 @@ impl FixedVhdDiskAsync {
}
impl DiskFile for FixedVhdDiskAsync {
fn size(&mut self) -> DiskFileResult<u64> {
Ok(self.0.size().unwrap())
fn logical_size(&mut self) -> DiskFileResult<u64> {
Ok(self.0.logical_size().unwrap())
}
fn physical_size(&mut self) -> DiskFileResult<u64> {
Ok(self.0.physical_size().unwrap())
}
fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
Ok(Box::new(
FixedVhdAsync::new(self.0.as_raw_fd(), ring_depth, self.0.size().unwrap())
.map_err(DiskFileError::NewAsyncIo)?,
FixedVhdAsync::new(
self.0.as_raw_fd(),
ring_depth,
self.0.logical_size().unwrap(),
)
.map_err(DiskFileError::NewAsyncIo)?,
) as Box<dyn AsyncIo>)
}

View File

@@ -23,13 +23,23 @@ impl FixedVhdDiskSync {
}
impl DiskFile for FixedVhdDiskSync {
fn size(&mut self) -> DiskFileResult<u64> {
Ok(self.0.size().unwrap())
fn logical_size(&mut self) -> DiskFileResult<u64> {
Ok(self.0.logical_size().unwrap())
}
fn physical_size(&mut self) -> DiskFileResult<u64> {
self.0.physical_size().map_err(|e| {
let io_inner = match e {
crate::Error::GetFileMetadata(e) => e,
_ => unreachable!(),
};
DiskFileError::Size(io_inner)
})
}
fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
Ok(Box::new(
FixedVhdSync::new(self.0.as_raw_fd(), self.0.size().unwrap())
FixedVhdSync::new(self.0.as_raw_fd(), self.0.logical_size().unwrap())
.map_err(DiskFileError::NewAsyncIo)?,
) as Box<dyn AsyncIo>)
}

View File

@@ -8,9 +8,6 @@
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
#[macro_use]
extern crate log;
pub mod async_io;
pub mod fcntl;
pub mod fixed_vhd;
@@ -45,6 +42,7 @@ use std::{cmp, result};
#[cfg(feature = "io_uring")]
use io_uring::{IoUring, Probe, opcode};
use libc::{S_IFBLK, S_IFMT, ioctl};
use log::{error, info, warn};
use serde::{Deserialize, Serialize};
use smallvec::SmallVec;
use thiserror::Error;
@@ -82,8 +80,8 @@ pub enum Error {
DetectImageType(#[source] std::io::Error),
#[error("Failure in fixed vhd")]
FixedVhdError(#[source] std::io::Error),
#[error("Getting a block's metadata fails for any reason")]
GetFileMetadata,
#[error("Getting a block's metadata failed")]
GetFileMetadata(#[source] std::io::Error),
#[error("The requested operation would cause a seek beyond disk end")]
InvalidOffset,
#[error("Failure in qcow")]
@@ -98,7 +96,7 @@ pub enum Error {
fn build_device_id(disk_path: &Path) -> result::Result<String, Error> {
let blk_metadata = match disk_path.metadata() {
Err(_) => return Err(Error::GetFileMetadata),
Err(e) => return Err(Error::GetFileMetadata(e)),
Ok(m) => m,
};
// This is how kvmtool does it.
@@ -122,7 +120,7 @@ pub fn build_serial(disk_path: &Path) -> Vec<u8> {
// This will also zero out any leftover bytes.
let disk_id = m.as_bytes();
let bytes_to_copy = cmp::min(disk_id.len(), VIRTIO_BLK_ID_BYTES as usize);
default_serial[..bytes_to_copy].clone_from_slice(&disk_id[..bytes_to_copy])
default_serial[..bytes_to_copy].clone_from_slice(&disk_id[..bytes_to_copy]);
}
}
default_serial
@@ -138,7 +136,7 @@ pub enum ExecuteError {
Read(#[source] GuestMemoryError),
#[error("Failed to read_exact")]
ReadExact(#[source] io::Error),
#[error("Can't execute an operation other than `read` on a read-only device")]
#[error("Can't execute an operation other than `read` or `get_id` on a read-only device")]
ReadOnly,
#[error("Failed to seek")]
Seek(#[source] io::Error),
@@ -295,14 +293,7 @@ impl Request {
error!("Only head descriptor present: request = {req:?}");
})?;
if !desc.has_next() {
status_desc = desc;
// Only flush requests are allowed to skip the data descriptor.
if req.request_type != RequestType::Flush {
error!("Need a data descriptor: request = {req:?}");
return Err(Error::DescriptorChainTooShort);
}
} else {
if desc.has_next() {
req.data_descriptors.reserve_exact(1);
while desc.has_next() {
if desc.is_write_only() && req.request_type == RequestType::Out {
@@ -328,6 +319,13 @@ impl Request {
})?;
}
status_desc = desc;
} else {
status_desc = desc;
// Only flush requests are allowed to skip the data descriptor.
if req.request_type != RequestType::Flush {
error!("Need a data descriptor: request = {req:?}");
return Err(Error::DescriptorChainTooShort);
}
}
// The status MUST always be writable.
@@ -398,7 +396,7 @@ impl Request {
.map_err(ExecuteError::Write)?;
}
RequestType::Unsupported(t) => return Err(ExecuteError::Unsupported(t)),
};
}
}
Ok(len)
}
@@ -440,14 +438,17 @@ impl Request {
let origin_ptr = mem
.get_slice(data_addr, data_len)
.map_err(ExecuteError::GetHostAddress)?
.ptr_guard();
.map_err(ExecuteError::GetHostAddress)?;
assert!(origin_ptr.len() >= data_len);
let origin_ptr = origin_ptr.ptr_guard();
// Verify the buffer alignment.
// In case it's not properly aligned, an intermediate buffer is
// created with the correct alignment, and a copy from/to the
// origin buffer is performed, depending on the type of operation.
let iov_base = if !(origin_ptr.as_ptr() as u64).is_multiple_of(SECTOR_SIZE) {
let iov_base = if (origin_ptr.as_ptr() as u64).is_multiple_of(SECTOR_SIZE) {
origin_ptr.as_ptr() as *mut libc::c_void
} else {
let layout = Layout::from_size_align(data_len, SECTOR_SIZE as usize).unwrap();
// SAFETY: layout has non-zero size
let aligned_ptr = unsafe { alloc_zeroed(layout) };
@@ -475,8 +476,6 @@ impl Request {
});
aligned_ptr as *mut libc::c_void
} else {
origin_ptr.as_ptr() as *mut libc::c_void
};
let iovec = libc::iovec {
@@ -563,7 +562,7 @@ impl Request {
aligned_operation.aligned_ptr as *const u8,
aligned_operation.origin_ptr as *mut u8,
aligned_operation.size,
)
);
};
}
@@ -574,7 +573,7 @@ impl Request {
dealloc(
aligned_operation.aligned_ptr as *mut u8,
aligned_operation.layout,
)
);
};
}
@@ -582,7 +581,7 @@ impl Request {
}
pub fn set_writeback(&mut self, writeback: bool) {
self.writeback = writeback
self.writeback = writeback;
}
}
@@ -645,7 +644,7 @@ pub fn block_io_uring_is_supported() -> bool {
let io_uring = match IoUring::new(1) {
Ok(io_uring) => io_uring,
Err(e) => {
info!("{} failed to create io_uring instance: {}", error_msg, e);
info!("{error_msg} failed to create io_uring instance: {e}");
return false;
}
};
@@ -658,26 +657,26 @@ pub fn block_io_uring_is_supported() -> bool {
match submitter.register_probe(&mut probe) {
Ok(_) => {}
Err(e) => {
info!("{} failed to register a probe: {}", error_msg, e);
info!("{error_msg} failed to register a probe: {e}");
return false;
}
}
// Check IORING_OP_FSYNC is supported
if !probe.is_supported(opcode::Fsync::CODE) {
info!("{} IORING_OP_FSYNC operation not supported", error_msg);
info!("{error_msg} IORING_OP_FSYNC operation not supported");
return false;
}
// Check IORING_OP_READV is supported
if !probe.is_supported(opcode::Readv::CODE) {
info!("{} IORING_OP_READV operation not supported", error_msg);
info!("{error_msg} IORING_OP_READV operation not supported");
return false;
}
// Check IORING_OP_WRITEV is supported
if !probe.is_supported(opcode::Writev::CODE) {
info!("{} IORING_OP_WRITEV operation not supported", error_msg);
info!("{error_msg} IORING_OP_WRITEV operation not supported");
return false;
}
@@ -835,7 +834,14 @@ pub fn detect_image_type(f: &mut File) -> std::io::Result<ImageType> {
}
pub trait BlockBackend: Read + Write + Seek + Send + Debug {
fn size(&self) -> Result<u64, Error>;
/// Returns the logical disk size a guest will see.
///
/// For raw formats, this is equal to [`Self::physical_size`]. For file formats
/// that wrap disk images in a container (e.g. QCOW2), this refers to the
/// effective size that the guest will see.
fn logical_size(&self) -> Result<u64, Error>;
/// Returns the physical size of the underlying file.
fn physical_size(&self) -> Result<u64, Error>;
}
#[derive(Debug)]
@@ -862,6 +868,7 @@ ioctl_io_nr!(BLKPBSZGET, 0x12, 123);
ioctl_io_nr!(BLKIOMIN, 0x12, 120);
ioctl_io_nr!(BLKIOOPT, 0x12, 121);
#[derive(Copy, Clone)]
enum BlockSize {
LogicalBlock,
PhysicalBlock,
@@ -901,7 +908,7 @@ impl DiskTopology {
};
if ret != 0 {
return Err(std::io::Error::last_os_error());
};
}
Ok(block_size)
}

87
block/src/qcow/decoder.rs Normal file
View File

@@ -0,0 +1,87 @@
// Copyright 2025 The Cloud Hypervisor Authors. All rights reserved.
//
// SPDX-License-Identifier: Apache-2.0
use thiserror::Error;
#[derive(Debug, Error)]
pub enum Error {
#[error("Zlib decompress error")]
ZlibDecompress(#[source] flate2::DecompressError),
#[error("Zlib unexpected status: {0:?}")]
ZlibUnexpectedStatus(flate2::Status),
#[error("Zstd decompress error")]
ZstdDecompress(#[source] std::io::Error),
#[error("Zstd: failed to fill buffer")]
ZstdFillBuffer(#[source] std::io::Error),
}
pub type Result<T> = std::result::Result<T, Error>;
/// Generic trait for decoding zlib/zstd formats
pub trait Decoder {
fn decode(&self, input: &[u8], output: &mut [u8]) -> Result<usize>;
}
#[derive(Default)]
pub struct ZlibDecoder {}
impl Decoder for ZlibDecoder {
fn decode(&self, input: &[u8], output: &mut [u8]) -> Result<usize> {
use flate2::{Decompress, FlushDecompress, Status};
let mut decompressor = Decompress::new(false);
let status = decompressor
.decompress(input, output, FlushDecompress::Finish)
.map_err(Error::ZlibDecompress)?;
if status == Status::StreamEnd {
Ok(decompressor.total_out() as usize)
} else {
Err(Error::ZlibUnexpectedStatus(status))
}
}
}
#[derive(Default)]
pub struct ZstdDecoder {}
impl Decoder for ZstdDecoder {
fn decode(&self, input: &[u8], output: &mut [u8]) -> Result<usize> {
use std::io::Read;
let mut decoder = zstd::stream::read::Decoder::new(input).map_err(Error::ZstdDecompress)?;
let decoded_size = decoder.read(output).map_err(Error::ZstdFillBuffer)?;
Ok(decoded_size)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_zlib_decode() {
let d = ZlibDecoder::default();
let valid_input = vec![99, 96, 100, 98, 6, 0];
let mut output1 = vec![0; 4];
d.decode(&valid_input, &mut output1).unwrap();
assert_eq!(&output1, b"\x00\x01\x02\x03");
let invalid_input = vec![1, 2, 3, 4];
let mut output2 = vec![0; 1024];
d.decode(&invalid_input, &mut output2).unwrap_err();
}
#[test]
fn test_zstd_decode() {
let d = ZstdDecoder::default();
let valid_input = vec![40, 181, 47, 253, 32, 2, 17, 0, 0, 1, 254];
let mut output1 = vec![0; 2];
d.decode(&valid_input, &mut output1).unwrap();
assert_eq!(&output1, b"\x01\xfe");
let invalid_input = vec![1, 2, 3, 4];
let mut output2 = vec![0; 1024];
d.decode(&invalid_input, &mut output2).unwrap_err();
}
}

View File

@@ -4,6 +4,7 @@
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
mod decoder;
mod qcow_raw_file;
mod raw_file;
mod refcount;
@@ -17,7 +18,8 @@ use std::os::fd::{AsRawFd, RawFd};
use std::str;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use libc::{EINVAL, ENOSPC, ENOTSUP};
use libc::{EINVAL, EIO, ENOSPC};
use log::error;
use remain::sorted;
use thiserror::Error;
use vmm_sys_util::file_traits::{FileSetLen, FileSync};
@@ -25,6 +27,7 @@ use vmm_sys_util::seek_hole::SeekHole;
use vmm_sys_util::write_zeroes::{PunchHole, WriteZeroesAt};
use crate::BlockBackend;
use crate::qcow::decoder::{Decoder, ZlibDecoder, ZstdDecoder};
use crate::qcow::qcow_raw_file::QcowRawFile;
pub use crate::qcow::raw_file::RawFile;
use crate::qcow::refcount::RefCount;
@@ -42,8 +45,6 @@ pub enum Error {
BackingFileOpen(#[source] Box<Error>),
#[error("Backing file name is too long: {0} bytes over")]
BackingFileTooLong(usize),
#[error("Compressed blocks not supported")]
CompressedBlocksNotSupported,
#[error("Failed to evict cache")]
EvictingCache(#[source] io::Error),
#[error("File larger than max of {MAX_QCOW_FILE_SIZE}: {0}")]
@@ -110,6 +111,8 @@ pub enum Error {
TooManyL1Entries(u64),
#[error("Ref count table too large: {0}")]
TooManyRefcounts(u64),
#[error("Unsupported compression type")]
UnsupportedCompressionType,
#[error("Unsupported refcount order")]
UnsupportedRefcountOrder,
#[error("Unsupported version: {0}")]
@@ -122,11 +125,18 @@ pub enum Error {
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Copy, Clone)]
pub enum ImageType {
Raw,
Qcow2,
}
#[derive(Clone, Debug)]
pub enum CompressionType {
Zlib,
Zstd,
}
// Maximum data size supported.
const MAX_QCOW_FILE_SIZE: u64 = 0x01 << 44; // 16 TB.
@@ -153,15 +163,55 @@ const L1_TABLE_OFFSET_MASK: u64 = 0x00ff_ffff_ffff_fe00;
const L2_TABLE_OFFSET_MASK: u64 = 0x00ff_ffff_ffff_fe00;
// Flags
const COMPRESSED_FLAG: u64 = 1 << 62;
const COMPRESSED_SECTOR_SIZE: u64 = 512;
const CLUSTER_USED_FLAG: u64 = 1 << 63;
const COMPATIBLE_FEATURES_LAZY_REFCOUNTS: u64 = 1;
// Compression types as defined in https://www.qemu.org/docs/master/interop/qcow2.html
const COMPRESSION_TYPE_ZLIB: u64 = 0; // zlib/deflate <https://www.ietf.org/rfc/rfc1951.txt>
const COMPRESSION_TYPE_ZSTD: u64 = 1; // zstd <http://github.com/facebook/zstd>
// The format supports a "header extension area", that crosvm does not use.
const QCOW_EMPTY_HEADER_EXTENSION_SIZE: u32 = 8;
// Defined by the specification
const MAX_BACKING_FILE_SIZE: u32 = 1023;
fn l2_entry_is_empty(l2_entry: u64) -> bool {
l2_entry == 0
}
fn l2_entry_is_compressed(l2_entry: u64) -> bool {
l2_entry & COMPRESSED_FLAG != 0
}
// Get file offset and size of compressed cluster data
fn l2_entry_compressed_cluster_layout(l2_entry: u64, cluster_bits: u32) -> (u64, usize) {
let compressed_size_shift = 62 - (cluster_bits - 8);
let compressed_size_mask = (1 << (cluster_bits - 8)) - 1;
let compressed_cluster_addr = l2_entry & ((1 << compressed_size_shift) - 1);
let nsectors = (l2_entry >> compressed_size_shift & compressed_size_mask) + 1;
let compressed_cluster_size = ((nsectors * COMPRESSED_SECTOR_SIZE)
- (compressed_cluster_addr & (COMPRESSED_SECTOR_SIZE - 1)))
as usize;
(compressed_cluster_addr, compressed_cluster_size)
}
// Get file offset of standard (non-compressed) cluster
fn l2_entry_std_cluster_addr(l2_entry: u64) -> u64 {
l2_entry & L2_TABLE_OFFSET_MASK
}
// Make L2 entry for standard (non-compressed) cluster
fn l2_entry_make_std(cluster_addr: u64) -> u64 {
(cluster_addr & L2_TABLE_OFFSET_MASK) | CLUSTER_USED_FLAG
}
// Make L1 entry with optional flags
fn l1_entry_make(cluster_addr: u64, refcount_is_one: bool) -> u64 {
(cluster_addr & L1_TABLE_OFFSET_MASK) | (refcount_is_one as u64 * CLUSTER_USED_FLAG)
}
/// Contains the information from the header of a qcow file.
#[derive(Clone, Debug)]
pub struct QcowHeader {
@@ -190,6 +240,7 @@ pub struct QcowHeader {
pub autoclear_features: u64,
pub refcount_order: u32,
pub header_size: u32,
pub compression_type: CompressionType,
// Post-header entries
pub backing_file_path: Option<String>,
@@ -255,8 +306,19 @@ impl QcowHeader {
} else {
read_u32_from_file(f)?
},
compression_type: CompressionType::Zlib,
backing_file_path: None,
};
if version == 3 && header.header_size > V3_BARE_HEADER_SIZE {
let raw_compression_type = read_u64_from_file(f)? >> (64 - 8);
header.compression_type = if raw_compression_type == COMPRESSION_TYPE_ZLIB {
Ok(CompressionType::Zlib)
} else if raw_compression_type == COMPRESSION_TYPE_ZSTD {
Ok(CompressionType::Zstd)
} else {
Err(Error::UnsupportedCompressionType)
}?;
}
if header.backing_file_size > MAX_BACKING_FILE_SIZE {
return Err(Error::BackingFileTooLong(header.backing_file_size as usize));
}
@@ -274,6 +336,13 @@ impl QcowHeader {
Ok(header)
}
pub fn get_decoder(&self) -> Box<dyn Decoder> {
match self.compression_type {
CompressionType::Zlib => Box::new(ZlibDecoder {}),
CompressionType::Zstd => Box::new(ZstdDecoder {}),
}
}
pub fn create_for_size_and_path(
version: u32,
size: u64,
@@ -337,6 +406,7 @@ impl QcowHeader {
autoclear_features: 0,
refcount_order: DEFAULT_REFCOUNT_ORDER,
header_size,
compression_type: CompressionType::Zlib,
backing_file_path: backing_file.map(String::from),
})
}
@@ -588,17 +658,6 @@ impl QcowFile {
let l2_entries = cluster_size / size_of::<u64>() as u64;
// Check for compressed blocks
for l2_addr_disk in l1_table.get_values() {
if *l2_addr_disk != 0
&& let Err(e) = Self::read_l2_cluster(&mut raw_file, *l2_addr_disk)
&& let Some(os_error) = e.raw_os_error()
&& os_error == ENOTSUP
{
return Err(Error::CompressedBlocksNotSupported);
}
}
let mut qcow = QcowFile {
raw_file,
header,
@@ -630,7 +689,7 @@ impl QcowFile {
/// Creates a new QcowFile at the given path.
pub fn new(file: RawFile, version: u32, virtual_size: u64) -> Result<QcowFile> {
let header = QcowHeader::create_for_size_and_path(version, virtual_size, None)?;
QcowFile::new_from_header(file, header)
QcowFile::new_from_header(file, &header)
}
/// Creates a new QcowFile at the given path.
@@ -652,12 +711,12 @@ impl QcowFile {
.map_err(|e| Error::BackingFileOpen(Box::new(e)))?;
let size = backing_file.virtual_size();
let header = QcowHeader::create_for_size_and_path(version, size, Some(backing_file_name))?;
let mut result = QcowFile::new_from_header(file, header)?;
let mut result = QcowFile::new_from_header(file, &header)?;
result.backing_file = Some(Box::new(backing_file));
Ok(result)
}
fn new_from_header(mut file: RawFile, header: QcowHeader) -> Result<QcowFile> {
fn new_from_header(mut file: RawFile, header: &QcowHeader) -> Result<QcowFile> {
file.rewind().map_err(Error::SeekingFile)?;
header.write_to(&mut file)?;
@@ -714,11 +773,7 @@ impl QcowFile {
let raw_file = &mut self.raw_file;
self.l2_cache
.insert(l1_index, table, |index, evicted| {
raw_file.write_pointer_table(
l1_table[index],
evicted.get_values(),
CLUSTER_USED_FLAG,
)
raw_file.write_pointer_table_direct(l1_table[index], evicted.iter())
})
.map_err(Error::EvictingCache)?;
}
@@ -805,7 +860,7 @@ impl QcowFile {
// Add references to the L1 table clusters.
fn set_l1_refcounts(
refcounts: &mut [u16],
header: QcowHeader,
header: &QcowHeader,
cluster_size: u64,
) -> Result<()> {
let entries_per_cluster = cluster_size / size_of::<u64>() as u64;
@@ -820,7 +875,7 @@ impl QcowFile {
// Traverse the L1 and L2 tables to find all reachable data clusters.
fn set_data_refcounts(
refcounts: &mut [u16],
header: QcowHeader,
header: &QcowHeader,
cluster_size: u64,
raw_file: &mut QcowRawFile,
) -> Result<()> {
@@ -859,7 +914,7 @@ impl QcowFile {
// Add references to the top-level refcount table clusters.
fn set_refcount_table_refcounts(
refcounts: &mut [u16],
header: QcowHeader,
header: &QcowHeader,
cluster_size: u64,
) -> Result<()> {
let refcount_table_offset = header.refcount_table_offset;
@@ -943,7 +998,7 @@ impl QcowFile {
// Rewrite the top-level refcount table.
raw_file
.write_pointer_table(header.refcount_table_offset, ref_table, 0)
.write_pointer_table_direct(header.refcount_table_offset, ref_table.iter())
.map_err(Error::WritingHeader)?;
// Rewrite the header again, now with lazy refcounts disabled.
@@ -997,9 +1052,9 @@ impl QcowFile {
// Find all references clusters and rebuild refcounts.
set_header_refcount(&mut refcounts, cluster_size)?;
set_l1_refcounts(&mut refcounts, header.clone(), cluster_size)?;
set_data_refcounts(&mut refcounts, header.clone(), cluster_size, raw_file)?;
set_refcount_table_refcounts(&mut refcounts, header.clone(), cluster_size)?;
set_l1_refcounts(&mut refcounts, &header, cluster_size)?;
set_data_refcounts(&mut refcounts, &header, cluster_size, raw_file)?;
set_refcount_table_refcounts(&mut refcounts, &header, cluster_size)?;
// Allocate clusters to store the new reference count blocks.
let ref_table = alloc_refblocks(&mut refcounts, cluster_size, refblock_clusters)?;
@@ -1050,11 +1105,40 @@ impl QcowFile {
(address / self.raw_file.cluster_size()) % self.l2_entries
}
// Gets the offset of the given guest address in the host file. If L1, L2, or data clusters have
// yet to be allocated, return None.
fn file_offset_read(&mut self, address: u64) -> std::io::Result<Option<u64>> {
// Decompress the cluster, return EIO on failure
fn decompress_l2_cluster(&mut self, l2_entry: u64) -> std::io::Result<Vec<u8>> {
let (compressed_cluster_addr, compressed_cluster_size) =
l2_entry_compressed_cluster_layout(l2_entry, self.header.cluster_bits);
// Read compressed cluster from raw file
self.raw_file
.file_mut()
.seek(SeekFrom::Start(compressed_cluster_addr))?;
let mut compressed_cluster = vec![0; compressed_cluster_size];
self.raw_file
.file_mut()
.read_exact(&mut compressed_cluster)?;
let decoder = self.header.get_decoder();
// Decompress
let cluster_size = self.raw_file.cluster_size() as usize;
let mut decompressed_cluster = vec![0; cluster_size];
let decompressed_size = decoder
.decode(&compressed_cluster, &mut decompressed_cluster)
.map_err(|_| std::io::Error::from_raw_os_error(EIO))?;
if decompressed_size as u64 != self.raw_file.cluster_size() {
return Err(std::io::Error::from_raw_os_error(EIO));
}
Ok(decompressed_cluster)
}
fn file_read(
&mut self,
address: u64,
count: usize,
buf: &mut [u8],
) -> std::io::Result<Option<()>> {
let err_inval = std::io::Error::from_raw_os_error(EINVAL);
if address >= self.virtual_size() {
return Err(std::io::Error::from_raw_os_error(EINVAL));
return Err(err_inval);
}
let l1_index = self.l1_table_index(address) as usize;
@@ -1072,11 +1156,28 @@ impl QcowFile {
self.cache_l2_cluster(l1_index, l2_addr_disk, false)?;
let cluster_addr = self.l2_cache.get(l1_index).unwrap()[l2_index];
if cluster_addr == 0 {
let l2_entry = self.l2_cache.get(l1_index).unwrap()[l2_index];
if l2_entry_is_empty(l2_entry) {
// Reading from an unallocated cluster will return zeros.
return Ok(None);
} else if l2_entry_is_compressed(l2_entry) {
// Compressed cluster.
// Read it, decompress, then return slice from decompressed data.
let mut decompressed_cluster = self.decompress_l2_cluster(l2_entry)?;
decompressed_cluster.resize(self.raw_file.cluster_size() as usize, 0);
let start = self.raw_file.cluster_offset(address) as usize;
let end = start.checked_add(count);
if end.is_none() || end.unwrap() > decompressed_cluster.len() {
return Err(err_inval);
}
buf[..count].copy_from_slice(&decompressed_cluster[start..end.unwrap()]);
} else {
let start = l2_entry_std_cluster_addr(l2_entry) + self.raw_file.cluster_offset(address);
let raw_file = self.raw_file.file_mut();
raw_file.seek(SeekFrom::Start(start))?;
raw_file.read_exact(buf)?;
}
Ok(Some(cluster_addr + self.raw_file.cluster_offset(address)))
Ok(Some(()))
}
// Gets the offset of the given guest address in the host file. If L1, L2, or data clusters need
@@ -1100,29 +1201,67 @@ impl QcowFile {
set_refcounts.push((new_addr, 1));
}
let cluster_addr = match self.l2_cache.get(l1_index).unwrap()[l2_index] {
0 => {
let initial_data = if let Some(backing) = self.backing_file.as_mut() {
let cluster_size = self.raw_file.cluster_size();
let cluster_begin = address - (address % cluster_size);
let mut cluster_data = vec![0u8; cluster_size as usize];
backing.seek(SeekFrom::Start(cluster_begin))?;
backing.read_exact(&mut cluster_data)?;
Some(cluster_data)
} else {
None
};
// Need to allocate a data cluster
let cluster_addr = self.append_data_cluster(initial_data)?;
self.update_cluster_addr(l1_index, l2_index, cluster_addr, &mut set_refcounts)?;
cluster_addr
let l2_entry = self.l2_cache.get(l1_index).unwrap()[l2_index];
let cluster_addr = if l2_entry_is_compressed(l2_entry) {
// Writing to compressed cluster.
let (compressed_cluster_addr, compressed_cluster_size) =
l2_entry_compressed_cluster_layout(l2_entry, self.header.cluster_bits);
// Allocate new cluster, decompress into new cluster, then use
// offset of new cluster.
let decompressed_cluster = self.decompress_l2_cluster(l2_entry)?;
let cluster_addr = self.append_data_cluster(None)?;
self.update_cluster_addr(l1_index, l2_index, cluster_addr, &mut set_refcounts)?;
self.raw_file
.file_mut()
.seek(SeekFrom::Start(cluster_addr))?;
let nwritten = self.raw_file.file_mut().write(&decompressed_cluster)?;
if nwritten != decompressed_cluster.len() {
return Err(std::io::Error::from_raw_os_error(EIO));
}
a => a,
// Decrement refcount for each cluster spanned by the old compressed data
let compressed_clusters_end = self.raw_file.cluster_address(
compressed_cluster_addr // Start of compressed data
+ compressed_cluster_size as u64 // Add size to get end address
+ self.raw_file.cluster_size()
- 1, // Catch possibly partially used last cluster
);
let mut addr = self.raw_file.cluster_address(compressed_cluster_addr);
while addr < compressed_clusters_end {
let refcount = self
.refcounts
.get_cluster_refcount(&mut self.raw_file, addr)
.map_err(|e| std::io::Error::other(Error::GettingRefcount(e)))?;
if refcount > 0 {
self.set_cluster_refcount_track_freed(addr, refcount - 1)?;
}
addr += self.raw_file.cluster_size();
}
cluster_addr
} else if l2_entry_is_empty(l2_entry) {
let initial_data = if let Some(backing) = self.backing_file.as_mut() {
let cluster_size = self.raw_file.cluster_size();
let cluster_begin = address - (address % cluster_size);
let mut cluster_data = vec![0u8; cluster_size as usize];
backing.seek(SeekFrom::Start(cluster_begin))?;
backing.read_exact(&mut cluster_data)?;
Some(cluster_data)
} else {
None
};
// Need to allocate a data cluster
let cluster_addr = self.append_data_cluster(initial_data)?;
self.update_cluster_addr(l1_index, l2_index, cluster_addr, &mut set_refcounts)?;
cluster_addr
} else {
l2_entry_std_cluster_addr(l2_entry)
};
for (addr, count) in set_refcounts {
let mut newly_unref = self.set_cluster_refcount(addr, count)?;
self.unref_clusters.append(&mut newly_unref);
self.set_cluster_refcount_track_freed(addr, count)?;
}
Ok(cluster_addr + self.raw_file.cluster_offset(address))
@@ -1157,7 +1296,7 @@ impl QcowFile {
self.l1_table[l1_index] = new_addr;
}
// 'unwrap' is OK because it was just added.
self.l2_cache.get_mut(l1_index).unwrap()[l2_index] = cluster_addr;
self.l2_cache.get_mut(l1_index).unwrap()[l2_index] = l2_entry_make_std(cluster_addr);
Ok(())
}
@@ -1166,7 +1305,7 @@ impl QcowFile {
// First use a pre allocated cluster if one is available.
if let Some(free_cluster) = self.avail_clusters.pop() {
if let Some(initial_data) = initial_data {
self.raw_file.write_cluster(free_cluster, initial_data)?;
self.raw_file.write_cluster(free_cluster, &initial_data)?;
} else {
self.raw_file.zero_cluster(free_cluster)?;
}
@@ -1176,7 +1315,7 @@ impl QcowFile {
let max_valid_cluster_offset = self.refcounts.max_valid_cluster_offset();
if let Some(new_cluster) = self.raw_file.add_cluster_end(max_valid_cluster_offset)? {
if let Some(initial_data) = initial_data {
self.raw_file.write_cluster(new_cluster, initial_data)?;
self.raw_file.write_cluster(new_cluster, &initial_data)?;
}
Ok(new_cluster)
} else {
@@ -1190,8 +1329,7 @@ impl QcowFile {
fn append_data_cluster(&mut self, initial_data: Option<Vec<u8>>) -> std::io::Result<u64> {
let new_addr: u64 = self.get_new_cluster(initial_data)?;
// The cluster refcount starts at one indicating it is used but doesn't need COW.
let mut newly_unref = self.set_cluster_refcount(new_addr, 1)?;
self.unref_clusters.append(&mut newly_unref);
self.set_cluster_refcount_track_freed(new_addr, 1)?;
Ok(new_addr)
}
@@ -1296,8 +1434,7 @@ impl QcowFile {
}
let new_refcount = refcount - 1;
let mut newly_unref = self.set_cluster_refcount(cluster_addr, new_refcount)?;
self.unref_clusters.append(&mut newly_unref);
self.set_cluster_refcount_track_freed(cluster_addr, new_refcount)?;
// Rewrite the L2 entry to remove the cluster mapping.
// unwrap is safe as we just checked/inserted this entry.
@@ -1334,10 +1471,9 @@ impl QcowFile {
// Partial cluster - zero out the relevant bytes if it was allocated.
// Any space in unallocated clusters can be left alone, since
// unallocated clusters already read back as zeroes.
if let Some(offset) = self.file_offset_read(curr_addr)? {
// Partial cluster - zero it out.
self.raw_file.file_mut().write_zeroes_at(offset, count)?;
}
let offset = self.file_offset_write(curr_addr)?;
// Partial cluster - zero it out.
self.raw_file.file_mut().write_zeroes_at(offset, count)?;
}
nwritten += count;
@@ -1348,14 +1484,8 @@ impl QcowFile {
// Reads an L2 cluster from the disk, returning an error if the file can't be read or if any
// cluster is compressed.
fn read_l2_cluster(raw_file: &mut QcowRawFile, cluster_addr: u64) -> std::io::Result<Vec<u64>> {
let file_values = raw_file.read_pointer_cluster(cluster_addr, None)?;
if file_values.iter().any(|entry| entry & COMPRESSED_FLAG != 0) {
return Err(std::io::Error::from_raw_os_error(ENOTSUP));
}
Ok(file_values
.iter()
.map(|entry| *entry & L2_TABLE_OFFSET_MASK)
.collect())
let l2_table = raw_file.read_pointer_cluster(cluster_addr, None)?;
Ok(l2_table)
}
// Put an L2 cluster to the cache with evicting less-used cluster
@@ -1383,16 +1513,23 @@ impl QcowFile {
let l1_table = &self.l1_table;
let raw_file = &mut self.raw_file;
self.l2_cache.insert(l1_index, l2_table, |index, evicted| {
raw_file.write_pointer_table(
l1_table[index],
evicted.get_values(),
CLUSTER_USED_FLAG,
)
raw_file.write_pointer_table_direct(l1_table[index], evicted.iter())
})?;
}
Ok(new_cluster)
}
// Set the refcount for a cluster and add any unreferenced clusters to the unref list.
fn set_cluster_refcount_track_freed(
&mut self,
address: u64,
refcount: u16,
) -> std::io::Result<()> {
let mut newly_unref = self.set_cluster_refcount(address, refcount)?;
self.unref_clusters.append(&mut newly_unref);
Ok(())
}
// Set the refcount for a cluster with the given address.
// Returns a list of any refblocks that can be reused, this happens when a refblock is moved,
// the old location can be reused.
@@ -1413,7 +1550,9 @@ impl QcowFile {
refcount_set = true;
}
Ok(Some(freed_cluster)) => {
unref_clusters.push(freed_cluster);
// Recursively set the freed refcount block's refcount to 0
let mut freed = self.set_cluster_refcount(freed_cluster, 0)?;
unref_clusters.append(&mut freed);
refcount_set = true;
}
Err(refcount::Error::EvictingRefCounts(e)) => {
@@ -1456,11 +1595,8 @@ impl QcowFile {
// The index must be valid from when we inserted it.
let addr = self.l1_table[*l1_index];
if addr != 0 {
self.raw_file.write_pointer_table(
addr,
l2_table.get_values(),
CLUSTER_USED_FLAG,
)?;
self.raw_file
.write_pointer_table_direct(addr, l2_table.iter())?;
} else {
return Err(std::io::Error::from_raw_os_error(EINVAL));
}
@@ -1474,10 +1610,21 @@ impl QcowFile {
// Push L1 table and refcount table last as all the clusters they point to are now
// guaranteed to be valid.
let mut sync_required = if self.l1_table.dirty() {
// Write L1 table with OFLAG_COPIED bits
let refcounts = &mut self.refcounts;
self.raw_file.write_pointer_table(
self.header.l1_table_offset,
self.l1_table.get_values(),
0,
self.l1_table.iter(),
|raw_file, l2_addr| {
if l2_addr == 0 {
Ok(0)
} else {
let refcount = refcounts
.get_cluster_refcount(raw_file, l2_addr)
.map_err(|e| std::io::Error::other(Error::GettingRefcount(e)))?;
Ok(l1_entry_make(l2_addr, refcount == 1))
}
},
)?;
self.l1_table.mark_clean();
true
@@ -1512,14 +1659,10 @@ impl Read for QcowFile {
let mut nread: usize = 0;
while nread < read_count {
let curr_addr = address + nread as u64;
let file_offset = self.file_offset_read(curr_addr)?;
let count = self.limit_range_cluster(curr_addr, read_count - nread);
if let Some(offset) = file_offset {
self.raw_file.file_mut().seek(SeekFrom::Start(offset))?;
self.raw_file
.file_mut()
.read_exact(&mut buf[nread..(nread + count)])?;
if (self.file_read(curr_addr, count, &mut buf[nread..(nread + count)])?).is_some() {
// Data is successfully read from the cluster
} else if let Some(backing) = self.backing_file.as_mut() {
backing.seek(SeekFrom::Start(curr_addr))?;
backing.read_exact(&mut buf[nread..(nread + count)])?;
@@ -1665,9 +1808,15 @@ impl SeekHole for QcowFile {
}
impl BlockBackend for QcowFile {
fn size(&self) -> std::result::Result<u64, crate::Error> {
fn logical_size(&self) -> std::result::Result<u64, crate::Error> {
Ok(self.virtual_size())
}
fn physical_size(&self) -> std::result::Result<u64, crate::Error> {
self.raw_file
.physical_size()
.map_err(crate::Error::GetFileMetadata)
}
}
// Returns an Error if the given offset doesn't align to a cluster boundary.
@@ -1815,7 +1964,7 @@ pub fn detect_image_type(file: &mut RawFile) -> Result<ImageType> {
}
#[cfg(test)]
mod tests {
mod unit_tests {
use std::fs::File;
use std::path::Path;
@@ -2743,8 +2892,6 @@ mod tests {
assert_eq!(orig, read);
}
}
assert_eq!(qcow_file.first_zero_refcount().unwrap(), None);
});
}

View File

@@ -61,25 +61,49 @@ impl QcowRawFile {
self.read_pointer_table(offset, count, mask)
}
/// Writes `table` of u64 pointers to `offset` in the file.
/// `non_zero_flags` will be ORed with all non-zero values in `table`.
/// writing.
pub fn write_pointer_table(
/// Internal helper for creating a buffered writer for pointer tables.
#[inline]
fn setup_pointer_table_writer<T>(
&mut self,
offset: u64,
table: &[u64],
non_zero_flags: u64,
) -> io::Result<()> {
entries: &impl Iterator<Item = T>,
) -> io::Result<BufWriter<RawFile>> {
self.file.seek(SeekFrom::Start(offset))?;
let mut buffer = BufWriter::with_capacity(std::mem::size_of_val(table), &mut self.file);
for addr in table {
let val = if *addr == 0 {
0
} else {
*addr | non_zero_flags
};
buffer.write_u64::<BigEndian>(val)?;
let my_file = self.file.try_clone()?;
let capacity = entries.size_hint().0 * size_of::<u64>();
Ok(BufWriter::with_capacity(capacity, my_file))
}
/// Writes a pointer table to `offset` in the file.
/// Entries are computed on-the-fly by the callback.
pub fn write_pointer_table<'a, T: Copy + 'a>(
&mut self,
offset: u64,
entries: impl Iterator<Item = &'a T>,
mut f: impl FnMut(&mut QcowRawFile, T) -> io::Result<u64>,
) -> io::Result<()> {
let mut buffer = self.setup_pointer_table_writer(offset, &entries)?;
for addr in entries {
let entry = f(self, *addr)?;
buffer.write_u64::<BigEndian>(entry)?;
}
buffer.flush()?;
Ok(())
}
/// Writes a pointer table directly without transforming values.
pub fn write_pointer_table_direct<'a>(
&mut self,
offset: u64,
entries: impl Iterator<Item = &'a u64>,
) -> io::Result<()> {
let mut buffer = self.setup_pointer_table_writer(offset, &entries)?;
for &entry in entries {
buffer.write_u64::<BigEndian>(entry)?;
}
buffer.flush()?;
Ok(())
}
@@ -101,6 +125,7 @@ impl QcowRawFile {
for count in table {
buffer.write_u16::<BigEndian>(*count)?;
}
buffer.flush()?;
Ok(())
}
@@ -135,6 +160,11 @@ impl QcowRawFile {
address & self.cluster_mask
}
/// Returns the base address of the cluster containing `address`.
pub fn cluster_address(&self, address: u64) -> u64 {
address & !self.cluster_mask
}
/// Zeros out a cluster in the file.
pub fn zero_cluster(&mut self, address: u64) -> io::Result<()> {
let cluster_size = self.cluster_size as usize;
@@ -144,11 +174,15 @@ impl QcowRawFile {
}
/// Writes
pub fn write_cluster(&mut self, address: u64, data: Vec<u8>) -> io::Result<()> {
pub fn write_cluster(&mut self, address: u64, data: &[u8]) -> io::Result<()> {
let cluster_size = self.cluster_size as usize;
self.file.seek(SeekFrom::Start(address))?;
self.file.write_all(&data[0..cluster_size])
}
pub fn physical_size(&self) -> Result<u64, std::io::Error> {
self.file.metadata().map(|m| m.len())
}
}
impl Clone for QcowRawFile {

View File

@@ -259,7 +259,7 @@ impl Write for RawFile {
// SAFETY: tmp_ptr was allocated by alloc_zeroed with layout
unsafe { dealloc(tmp_ptr, layout) };
return Err(io::Error::last_os_error());
};
}
tmp_buf[file_offset..(file_offset + buf_len)].copy_from_slice(buf);
@@ -354,7 +354,11 @@ impl SeekHole for RawFile {
}
impl BlockBackend for RawFile {
fn size(&self) -> std::result::Result<u64, crate::Error> {
fn logical_size(&self) -> std::result::Result<u64, crate::Error> {
Ok(self.metadata().map_err(crate::Error::RawFileError)?.len())
}
fn physical_size(&self) -> std::result::Result<u64, crate::Error> {
Ok(self.metadata().map_err(crate::Error::RawFileError)?.len())
}
}

View File

@@ -119,7 +119,9 @@ impl RefCount {
}
// Unwrap is safe here as the entry was filled directly above.
let dropped_cluster = if !self.refblock_cache.get(table_index).unwrap().dirty() {
let dropped_cluster = if self.refblock_cache.get(table_index).unwrap().dirty() {
None
} else {
// Free the previously used block and use a new one. Writing modified counts to new
// blocks keeps the on-disk state consistent even if it's out of date.
if let Some((addr, _)) = new_cluster.take() {
@@ -128,8 +130,6 @@ impl RefCount {
} else {
return Err(Error::NeedNewCluster);
}
} else {
None
};
self.refblock_cache.get_mut(table_index).unwrap()[block_index] = refcount;
@@ -156,11 +156,8 @@ impl RefCount {
/// Returns true if the table changed since the previous `flush_table()` call.
pub fn flush_table(&mut self, raw_file: &mut QcowRawFile) -> io::Result<bool> {
if self.ref_table.dirty() {
raw_file.write_pointer_table(
self.refcount_table_offset,
self.ref_table.get_values(),
0,
)?;
raw_file
.write_pointer_table_direct(self.refcount_table_offset, self.ref_table.iter())?;
self.ref_table.mark_clean();
Ok(true)
} else {

View File

@@ -7,7 +7,7 @@
use std::collections::HashMap;
use std::collections::hash_map::IterMut;
use std::io;
use std::ops::{Index, IndexMut};
use std::ops::{Deref, Index, IndexMut};
use std::slice::SliceIndex;
/// Trait that allows for checking if an implementor is dirty. Useful for types that are cached so
@@ -85,6 +85,14 @@ impl<T: 'static + Copy + Default> IndexMut<usize> for VecCache<T> {
}
}
impl<T: 'static + Copy + Default> Deref for VecCache<T> {
type Target = [T];
fn deref(&self) -> &[T] {
&self.vec
}
}
#[derive(Clone, Debug)]
pub struct CacheMap<T: Cacheable> {
capacity: usize,
@@ -135,7 +143,7 @@ impl<T: Cacheable> CacheMap<T> {
}
#[cfg(test)]
mod tests {
mod unit_tests {
use super::*;
struct NumCache(());

View File

@@ -9,11 +9,11 @@ use std::os::fd::AsRawFd;
use vmm_sys_util::eventfd::EventFd;
use crate::AsyncAdaptor;
use crate::async_io::{
AsyncIo, AsyncIoResult, BorrowedDiskFd, DiskFile, DiskFileError, DiskFileResult,
};
use crate::qcow::{QcowFile, RawFile, Result as QcowResult};
use crate::{AsyncAdaptor, BlockBackend};
pub struct QcowDiskSync {
qcow_file: QcowFile,
@@ -28,12 +28,22 @@ impl QcowDiskSync {
}
impl DiskFile for QcowDiskSync {
fn size(&mut self) -> DiskFileResult<u64> {
fn logical_size(&mut self) -> DiskFileResult<u64> {
self.qcow_file
.seek(SeekFrom::End(0))
.map_err(DiskFileError::Size)
}
fn physical_size(&mut self) -> DiskFileResult<u64> {
self.qcow_file.physical_size().map_err(|e| {
let io_inner = match e {
crate::Error::GetFileMetadata(e) => e,
_ => unreachable!(),
};
DiskFileError::Size(io_inner)
})
}
fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
Ok(Box::new(QcowSync::new(self.qcow_file.clone())) as Box<dyn AsyncIo>)
}

View File

@@ -7,6 +7,7 @@ use std::io::{Error, Seek, SeekFrom};
use std::os::unix::io::{AsRawFd, RawFd};
use io_uring::{IoUring, opcode, types};
use log::warn;
use vmm_sys_util::eventfd::EventFd;
use crate::async_io::{
@@ -25,12 +26,19 @@ impl RawFileDisk {
}
impl DiskFile for RawFileDisk {
fn size(&mut self) -> DiskFileResult<u64> {
fn logical_size(&mut self) -> DiskFileResult<u64> {
self.file
.seek(SeekFrom::End(0))
.map_err(DiskFileError::Size)
}
fn physical_size(&mut self) -> DiskFileResult<u64> {
self.file
.metadata()
.map(|m| m.len())
.map_err(DiskFileError::Size)
}
fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
Ok(Box::new(
RawFileAsync::new(self.file.as_raw_fd(), ring_depth)
@@ -47,6 +55,10 @@ impl DiskFile for RawFileDisk {
}
}
fn resize(&mut self, size: u64) -> DiskFileResult<()> {
self.file.set_len(size).map_err(DiskFileError::ResizeError)
}
fn fd(&mut self) -> BorrowedDiskFd<'_> {
BorrowedDiskFd::new(self.file.as_raw_fd())
}
@@ -97,7 +109,7 @@ impl AsyncIo for RawFileAsync {
.build()
.user_data(user_data),
)
.map_err(|_| AsyncIoError::ReadVectored(Error::other("Submission queue is full")))?
.map_err(|_| AsyncIoError::ReadVectored(Error::other("Submission queue is full")))?;
};
// Update the submission queue and submit new operations to the
@@ -125,7 +137,7 @@ impl AsyncIo for RawFileAsync {
.build()
.user_data(user_data),
)
.map_err(|_| AsyncIoError::WriteVectored(Error::other("Submission queue is full")))?
.map_err(|_| AsyncIoError::WriteVectored(Error::other("Submission queue is full")))?;
};
// Update the submission queue and submit new operations to the
@@ -147,7 +159,7 @@ impl AsyncIo for RawFileAsync {
.build()
.user_data(user_data),
)
.map_err(|_| AsyncIoError::Fsync(Error::other("Submission queue is full")))?
.map_err(|_| AsyncIoError::Fsync(Error::other("Submission queue is full")))?;
};
// Update the submission queue and submit new operations to the
@@ -199,7 +211,7 @@ impl AsyncIo for RawFileAsync {
)
.map_err(|_| {
AsyncIoError::ReadVectored(Error::other("Submission queue is full"))
})?
})?;
};
submitted = true;
}
@@ -219,7 +231,7 @@ impl AsyncIo for RawFileAsync {
)
.map_err(|_| {
AsyncIoError::WriteVectored(Error::other("Submission queue is full"))
})?
})?;
};
submitted = true;
}

View File

@@ -9,6 +9,7 @@ use std::fs::File;
use std::io::{Seek, SeekFrom};
use std::os::unix::io::{AsRawFd, RawFd};
use log::warn;
use vmm_sys_util::aio;
use vmm_sys_util::eventfd::EventFd;
@@ -28,12 +29,19 @@ impl RawFileDiskAio {
}
impl DiskFile for RawFileDiskAio {
fn size(&mut self) -> DiskFileResult<u64> {
fn logical_size(&mut self) -> DiskFileResult<u64> {
self.file
.seek(SeekFrom::End(0))
.map_err(DiskFileError::Size)
}
fn physical_size(&mut self) -> DiskFileResult<u64> {
self.file
.metadata()
.map(|m| m.len())
.map_err(DiskFileError::Size)
}
fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
Ok(Box::new(
RawFileAsyncAio::new(self.file.as_raw_fd(), ring_depth)

View File

@@ -7,6 +7,7 @@ use std::fs::File;
use std::io::{Seek, SeekFrom};
use std::os::unix::io::{AsRawFd, RawFd};
use log::warn;
use vmm_sys_util::eventfd::EventFd;
use crate::DiskTopology;
@@ -25,12 +26,19 @@ impl RawFileDiskSync {
}
impl DiskFile for RawFileDiskSync {
fn size(&mut self) -> DiskFileResult<u64> {
fn logical_size(&mut self) -> DiskFileResult<u64> {
self.file
.seek(SeekFrom::End(0))
.map_err(DiskFileError::Size)
}
fn physical_size(&mut self) -> DiskFileResult<u64> {
self.file
.metadata()
.map(|m| m.len())
.map_err(DiskFileError::Size)
}
fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
Ok(Box::new(RawFileSync::new(self.file.as_raw_fd())) as Box<dyn AsyncIo>)
}

View File

@@ -117,7 +117,7 @@ pub fn is_fixed_vhd(f: &mut File) -> std::io::Result<bool> {
}
#[cfg(test)]
mod tests {
mod unit_tests {
use std::fs::File;
use std::io::{Seek, SeekFrom, Write};

View File

@@ -202,9 +202,16 @@ impl Seek for Vhdx {
}
impl BlockBackend for Vhdx {
fn size(&self) -> std::result::Result<u64, crate::Error> {
fn logical_size(&self) -> std::result::Result<u64, crate::Error> {
Ok(self.virtual_disk_size())
}
fn physical_size(&self) -> std::result::Result<u64, crate::Error> {
self.file
.metadata()
.map(|m| m.len())
.map_err(crate::Error::GetFileMetadata)
}
}
impl Clone for Vhdx {

View File

@@ -2,8 +2,6 @@
//
// SPDX-License-Identifier: Apache-2.0
extern crate log;
use std::collections::btree_map::BTreeMap;
use std::fs::File;
use std::io::{self, Read, Seek, SeekFrom, Write};

View File

@@ -128,7 +128,7 @@ pub fn read(
_ => {
return Err(VhdxIoError::InvalidBatEntryState);
}
};
}
sector_count -= sector.free_sectors;
sector_index += sector.free_sectors;
read_count += sector.free_bytes as usize;
@@ -210,7 +210,7 @@ pub fn write(
_ => {
return Err(VhdxIoError::InvalidBatEntryState);
}
};
}
sector_count -= sector.free_sectors;
sector_index += sector.free_sectors;
write_count += sector.free_bytes as usize;

View File

@@ -8,11 +8,11 @@ use std::os::fd::AsRawFd;
use vmm_sys_util::eventfd::EventFd;
use crate::AsyncAdaptor;
use crate::async_io::{
AsyncIo, AsyncIoResult, BorrowedDiskFd, DiskFile, DiskFileError, DiskFileResult,
};
use crate::vhdx::{Result as VhdxResult, Vhdx};
use crate::{AsyncAdaptor, BlockBackend, Error};
pub struct VhdxDiskSync {
vhdx_file: Vhdx,
@@ -27,10 +27,20 @@ impl VhdxDiskSync {
}
impl DiskFile for VhdxDiskSync {
fn size(&mut self) -> DiskFileResult<u64> {
fn logical_size(&mut self) -> DiskFileResult<u64> {
Ok(self.vhdx_file.virtual_disk_size())
}
fn physical_size(&mut self) -> DiskFileResult<u64> {
self.vhdx_file.physical_size().map_err(|e| {
let io_inner = match e {
Error::GetFileMetadata(e) => e,
_ => unreachable!(),
};
DiskFileError::Size(io_inner)
})
}
fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
Ok(
Box::new(VhdxSync::new(self.vhdx_file.clone()).map_err(DiskFileError::NewAsyncIo)?)

View File

@@ -0,0 +1,69 @@
[package]
authors = ["The Cloud Hypervisor Authors"]
build = "build.rs"
default-run = "cloud-hypervisor"
description = "Open source Virtual Machine Monitor (VMM) that runs on top of KVM & MSHV"
edition = "2024"
homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
license = "Apache-2.0 AND BSD-3-Clause"
name = "cloud-hypervisor"
version = "50.0.0"
# Minimum buildable version:
# Keep in sync with version in .github/workflows/build.yaml
# Policy on MSRV (see #4318):
# Can only be bumped if satisfying any of the following:
# a.) A dependency requires it,
# b.) If we want to use a new feature and that MSRV is at least 6 months old,
# c.) There is a security issue that is addressed by the toolchain update.
rust-version = "1.89.0"
[dependencies]
anyhow = { workspace = true }
api_client = { path = "../api_client" }
clap = { workspace = true, features = ["string"] }
dhat = { workspace = true, optional = true }
env_logger = { workspace = true }
epoll = { workspace = true }
event_monitor = { path = "../event_monitor" }
hypervisor = { path = "../hypervisor" }
libc = { workspace = true }
log = { workspace = true, features = ["std"] }
option_parser = { path = "../option_parser" }
seccompiler = { workspace = true }
serde_json = { workspace = true }
signal-hook = { workspace = true }
thiserror = { workspace = true }
tpm = { path = "../tpm" }
tracer = { path = "../tracer" }
vm-memory = { workspace = true }
vmm = { path = "../vmm" }
vmm-sys-util = { workspace = true }
zbus = { version = "5.7.1", optional = true }
[dev-dependencies]
dirs = { workspace = true }
net_util = { path = "../net_util" }
serde_json = { workspace = true }
test_infra = { path = "../test_infra" }
wait-timeout = { workspace = true }
# Please adjust `vmm::feature_list()` accordingly when changing the
# feature list below
[features]
dbus_api = ["vmm/dbus_api", "zbus"]
default = ["io_uring", "kvm"]
dhat-heap = ["dhat", "vmm/dhat-heap"] # For heap profiling
fw_cfg = ["vmm/fw_cfg"]
guest_debug = ["vmm/guest_debug"]
igvm = ["mshv", "vmm/igvm"]
io_uring = ["vmm/io_uring"]
ivshmem = ["vmm/ivshmem"]
kvm = ["vmm/kvm"]
mshv = ["vmm/mshv"]
pvmemcontrol = ["vmm/pvmemcontrol"]
sev_snp = ["igvm", "mshv", "vmm/sev_snp"]
tdx = ["vmm/tdx"]
tracing = ["tracer/tracing", "vmm/tracing"]
[lints]
workspace = true

View File

@@ -65,6 +65,8 @@ enum Error {
ReadingStdin(#[source] std::io::Error),
#[error("Error reading from file")]
ReadingFile(#[source] std::io::Error),
#[error("Invalid disk size")]
InvalidDiskSize(#[source] ByteSizedParseError),
}
enum TargetApi<'a> {
@@ -320,6 +322,22 @@ fn rest_api_do_command(matches: &ArgMatches, socket: &mut UnixStream) -> ApiResu
)?;
simple_api_command(socket, "PUT", "resize", Some(&resize)).map_err(Error::HttpApiClient)
}
Some("resize-disk") => {
let resize_disk = resize_disk_config(
matches
.subcommand_matches("resize-disk")
.unwrap()
.get_one::<String>("disk")
.unwrap(),
matches
.subcommand_matches("resize-disk")
.unwrap()
.get_one::<String>("size")
.unwrap(),
)?;
simple_api_command(socket, "PUT", "resize-disk", Some(&resize_disk))
.map_err(Error::HttpApiClient)
}
Some("resize-zone") => {
let resize_zone = resize_zone_config(
matches
@@ -399,7 +417,7 @@ fn rest_api_do_command(matches: &ArgMatches, socket: &mut UnixStream) -> ApiResu
.get_one::<String>("net_config")
.unwrap(),
)?;
simple_api_command_with_fds(socket, "PUT", "add-net", Some(&net_config), fds)
simple_api_command_with_fds(socket, "PUT", "add-net", Some(&net_config), &fds)
.map_err(Error::HttpApiClient)
}
Some("add-user-device") => {
@@ -454,7 +472,7 @@ fn rest_api_do_command(matches: &ArgMatches, socket: &mut UnixStream) -> ApiResu
.get_one::<String>("restore_config")
.unwrap(),
)?;
simple_api_command_with_fds(socket, "PUT", "restore", Some(&restore_config), fds)
simple_api_command_with_fds(socket, "PUT", "restore", Some(&restore_config), &fds)
.map_err(Error::HttpApiClient)
}
Some("coredump") => {
@@ -762,6 +780,15 @@ fn resize_config(
Ok(serde_json::to_string(&resize).unwrap())
}
fn resize_disk_config(id: &str, size: &str) -> Result<String, Error> {
let resize_disk = vmm::api::VmResizeDiskData {
id: id.to_owned(),
desired_size: size.parse::<ByteSized>().map_err(Error::InvalidDiskSize)?.0,
};
Ok(serde_json::to_string(&resize_disk).unwrap())
}
fn resize_zone_config(id: &str, size: &str) -> Result<String, Error> {
let resize_zone = vmm::api::VmResizeZoneData {
id: id.to_owned(),
@@ -1022,6 +1049,20 @@ fn get_cli_commands_sorted() -> Box<[Command]> {
.help("New memory size in bytes (supports K/M/G suffix)")
.num_args(1),
),
Command::new("resize-disk")
.about("Resize an attached disk")
.arg(
Arg::new("disk")
.long("disk")
.help("Disk identifier")
.num_args(1),
)
.arg(
Arg::new("size")
.long("size")
.help("New disk size")
.num_args(1),
),
Command::new("resize-zone")
.about("Resize a memory zone")
.arg(
@@ -1137,6 +1178,7 @@ fn main() {
if let Err(top_error) = target_api.do_command(&matches) {
// Helper to join strings with a newline.
#[allow(clippy::needless_pass_by_value)]
fn join_strs(mut acc: String, next: String) -> String {
if !acc.is_empty() {
acc.push('\n');
@@ -1161,7 +1203,7 @@ fn main() {
if let Some(api_client::Error::ServerResponse(status_code, body)) =
error.downcast_ref::<api_client::Error>()
{
let body = body.as_ref().map(|body| body.as_str()).unwrap_or("");
let body = body.as_ref().map_or("", |body| body.as_str());
// Retrieve the list of error messages back.
let lines: Vec<&str> = match serde_json::from_str(body) {
@@ -1201,11 +1243,11 @@ fn main() {
server_api_error_display_modifier,
);
process::exit(1)
};
}
}
#[cfg(test)]
mod tests {
mod unit_tests {
use std::cmp::Ordering;
use super::*;

View File

@@ -213,7 +213,8 @@ fn get_cli_options_sorted(
topology=<threads_per_core>:<cores_per_die>:<dies_per_package>:<packages>,\
kvm_hyperv=on|off,max_phys_bits=<maximum_number_of_physical_bits>,\
affinity=<list_of_vcpus_with_their_associated_cpuset>,\
features=<list_of_features_to_enable>",
features=<list_of_features_to_enable>,\
nested=on|off",
)
.default_value(default_vcpus)
.group("vm-config"),
@@ -486,7 +487,7 @@ fn create_app(default_vcpus: String, default_memory: String, default_rng: String
.args(args)
}
fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
fn start_vmm(cmd_arguments: &ArgMatches) -> Result<Option<String>, Error> {
let log_level = match cmd_arguments.get_count("v") {
0 => LevelFilter::Warn,
1 => LevelFilter::Info,
@@ -722,7 +723,7 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
cmd_arguments.contains_id("kernel") || cmd_arguments.contains_id("firmware");
if payload_present {
let vm_params = VmParams::from_arg_matches(&cmd_arguments);
let vm_params = VmParams::from_arg_matches(cmd_arguments);
let vm_config = VmConfig::parse(vm_params).map_err(Error::ParsingConfig)?;
// Create and boot the VM based off the VM config we just built.
@@ -770,7 +771,7 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
.map_err(Error::VmmThread)?;
if let Some(api_handle) = vmm_thread_handle.http_api_handle {
http_api_graceful_shutdown(api_handle).map_err(Error::HttpApiShutdown)?
http_api_graceful_shutdown(api_handle).map_err(Error::HttpApiShutdown)?;
}
#[cfg(feature = "dbus_api")]
@@ -884,7 +885,7 @@ fn main() {
warn!("Error expanding FD table: {e}");
}
let exit_code = match start_vmm(cmd_arguments) {
let exit_code = match start_vmm(&cmd_arguments) {
Ok(path) => {
path.map(|s| std::fs::remove_file(s).ok());
info!("Cloud Hypervisor exited successfully");
@@ -961,6 +962,7 @@ mod unit_tests {
max_phys_bits: 46,
affinity: None,
features: CpuFeatures::default(),
nested: true,
},
memory: MemoryConfig {
size: 536_870_912,
@@ -2010,6 +2012,6 @@ mod unit_tests {
let (default_vcpus, default_memory, default_rng) = prepare_default_values();
let args = get_cli_options_sorted(default_vcpus, default_memory, default_rng);
assert_args_sorted(|| args.iter())
assert_args_sorted(|| args.iter());
}
}

View File

@@ -20,7 +20,7 @@ linux-loader = { workspace = true, features = [
"pe",
], optional = true }
log = { workspace = true }
num_enum = "0.7.4"
num_enum = "0.7.5"
pci = { path = "../pci" }
serde = { workspace = true, features = ["derive"] }
thiserror = { workspace = true }
@@ -34,7 +34,7 @@ vm-memory = { workspace = true, features = [
] }
vm-migration = { path = "../vm-migration" }
vmm-sys-util = { workspace = true }
zerocopy = { version = "0.8.27", features = [
zerocopy = { version = "0.8.31", features = [
"alloc",
"derive",
], optional = true }
@@ -48,3 +48,6 @@ fw_cfg = ["arch/fw_cfg", "bitfield-struct", "linux-loader", "zerocopy"]
ivshmem = []
kvm = ["arch/kvm"]
pvmemcontrol = []
[lints]
workspace = true

View File

@@ -9,6 +9,7 @@ use std::thread;
use std::time::Instant;
use acpi_tables::{Aml, AmlSink, aml};
use log::{error, info, warn};
use vm_device::BusDevice;
use vm_device::interrupt::InterruptSourceGroup;
use vm_memory::GuestAddress;
@@ -44,7 +45,7 @@ impl AcpiShutdownDevice {
impl BusDevice for AcpiShutdownDevice {
// Spec has all fields as zero
fn read(&mut self, _base: u64, _offset: u64, data: &mut [u8]) {
data.fill(0)
data.fill(0);
}
fn write(&mut self, _base: u64, _offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
@@ -213,7 +214,7 @@ impl Aml for AcpiGedDevice {
),
],
)
.to_aml_bytes(sink)
.to_aml_bytes(sink);
}
}

View File

@@ -3,8 +3,6 @@
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
use super::interrupt_controller::{Error, InterruptController};
extern crate arch;
use std::result;
use std::sync::{Arc, Mutex};
@@ -19,6 +17,8 @@ use vm_memory::address::Address;
use vm_migration::{Migratable, Pausable, Snapshottable, Transportable};
use vmm_sys_util::eventfd::EventFd;
use super::interrupt_controller::{Error, InterruptController};
type Result<T> = result::Result<T, Error>;
// Reserve 32 IRQs for legacy devices.
@@ -39,6 +39,7 @@ pub struct Aia {
}
impl Aia {
#[allow(clippy::needless_pass_by_value)]
pub fn new(
vcpu_count: u32,
interrupt_manager: Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
@@ -51,9 +52,8 @@ impl Aia {
})
.map_err(Error::CreateInterruptSourceGroup)?;
let vaia = vm
.create_vaia(Aia::create_default_config(vcpu_count as u64))
.map_err(Error::CreateAia)?;
let config = Aia::create_default_config(vcpu_count as u64);
let vaia = vm.create_vaia(&config).map_err(Error::CreateAia)?;
let aia = Aia {
interrupt_source_group,

View File

@@ -9,6 +9,7 @@ use std::io;
use std::io::Write;
use std::sync::{Arc, Barrier};
use log::error;
use vm_device::BusDevice;
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};

View File

@@ -2,8 +2,6 @@
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
use super::interrupt_controller::{Error, InterruptController};
extern crate arch;
use std::result;
use std::sync::{Arc, Mutex};
@@ -19,6 +17,8 @@ use vm_memory::address::Address;
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
use vmm_sys_util::eventfd::EventFd;
use super::interrupt_controller::{Error, InterruptController};
type Result<T> = result::Result<T, Error>;
// Reserve 32 IRQs for legacy devices.
@@ -38,6 +38,7 @@ pub struct Gic {
}
impl Gic {
#[allow(clippy::needless_pass_by_value)]
pub fn new(
vcpu_count: u32,
interrupt_manager: Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
@@ -50,9 +51,8 @@ impl Gic {
})
.map_err(Error::CreateInterruptSourceGroup)?;
let vgic = vm
.create_vgic(Gic::create_default_config(vcpu_count as u64))
.map_err(Error::CreateGic)?;
let config = Gic::create_default_config(vcpu_count as u64);
let vgic = vm.create_vgic(&config).map_err(Error::CreateGic)?;
let gic = Gic {
interrupt_source_group,
@@ -167,10 +167,7 @@ impl Pausable for Gic {
// Flush tables to guest RAM
let vgic = self.vgic.as_ref().unwrap().clone();
vgic.lock().unwrap().save_data_tables().map_err(|e| {
MigratableError::Pause(anyhow!(
"Could not save GICv3ITS GIC pending tables {:?}",
e
))
MigratableError::Pause(anyhow!("Could not save GICv3ITS GIC pending tables {e:?}",))
})?;
Ok(())
}

View File

@@ -13,6 +13,7 @@ use std::result;
use std::sync::{Arc, Barrier};
use byteorder::{ByteOrder, LittleEndian};
use log::{debug, error, trace, warn};
use serde::{Deserialize, Serialize};
use vm_device::BusDevice;
use vm_device::interrupt::{
@@ -190,8 +191,8 @@ impl Ioapic {
pub fn new(
id: String,
apic_address: GuestAddress,
interrupt_manager: Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
state: Option<IoapicState>,
interrupt_manager: &dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>,
state: Option<&IoapicState>,
) -> Result<Ioapic> {
let interrupt_source_group = interrupt_manager
.create_group(MsiIrqGroupConfig {

View File

@@ -11,6 +11,7 @@ use std::sync::{Arc, Barrier, Mutex};
use anyhow::anyhow;
use byteorder::{ByteOrder, LittleEndian};
use log::{debug, error, warn};
use pci::{
BarReprogrammingParams, PCI_CONFIGURATION_ID, PciBarConfiguration, PciBarPrefetchable,
PciBarRegionType, PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType,
@@ -33,7 +34,7 @@ const IVSHMEM_DEVICE_ID: u16 = 0x1110;
const IVSHMEM_REG_BAR_SIZE: u64 = 0x100;
type GuestRegionMmap = vm_memory::GuestRegionMmap<AtomicBitmap>;
type MmapRegion = vm_memory::MmapRegion<AtomicBitmap>;
#[derive(Debug, Error)]
pub enum IvshmemError {
@@ -68,7 +69,7 @@ pub trait IvshmemOps: Send + Sync {
start_addr: u64,
size: usize,
backing_file: Option<PathBuf>,
) -> Result<(Arc<GuestRegionMmap>, UserspaceMapping), IvshmemError>;
) -> Result<(Arc<MmapRegion>, UserspaceMapping), IvshmemError>;
fn unmap_ram_region(&mut self, mapping: UserspaceMapping) -> Result<(), IvshmemError>;
}
@@ -95,7 +96,7 @@ pub struct IvshmemDevice {
region_size: u64,
ivshmem_ops: Arc<Mutex<dyn IvshmemOps>>,
backend_file: Option<PathBuf>,
region: Option<Arc<GuestRegionMmap>>,
region: Option<Arc<MmapRegion>>,
userspace_mapping: Option<UserspaceMapping>,
}
@@ -113,14 +114,14 @@ impl IvshmemDevice {
region_size: u64,
backend_file: Option<PathBuf>,
ivshmem_ops: Arc<Mutex<dyn IvshmemOps>>,
snapshot: Option<Snapshot>,
snapshot: Option<&Snapshot>,
) -> Result<Self, IvshmemError> {
let pci_configuration_state =
vm_migration::state_from_id(snapshot.as_ref(), PCI_CONFIGURATION_ID).map_err(|e| {
IvshmemError::RetrievePciConfigurationState(anyhow!(
"Failed to get PciConfigurationState from Snapshot: {e}",
))
})?;
let pci_configuration_state = vm_migration::state_from_id(snapshot, PCI_CONFIGURATION_ID)
.map_err(|e| {
IvshmemError::RetrievePciConfigurationState(anyhow!(
"Failed to get PciConfigurationState from Snapshot: {e}",
))
})?;
let state: Option<IvshmemDeviceState> = snapshot
.as_ref()
@@ -180,11 +181,7 @@ impl IvshmemDevice {
Ok(device)
}
pub fn set_region(
&mut self,
region: Arc<GuestRegionMmap>,
userspace_mapping: UserspaceMapping,
) {
pub fn set_region(&mut self, region: Arc<MmapRegion>, userspace_mapping: UserspaceMapping) {
self.region = Some(region);
self.userspace_mapping = Some(userspace_mapping);
}
@@ -209,7 +206,7 @@ impl IvshmemDevice {
impl BusDevice for IvshmemDevice {
fn read(&mut self, base: u64, offset: u64, data: &mut [u8]) {
self.read_bar(base, offset, data)
self.read_bar(base, offset, data);
}
fn write(&mut self, base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
@@ -233,20 +230,18 @@ impl PciDevice for IvshmemDevice {
if let Some(resources) = resources {
for resource in resources {
match resource {
Resource::PciBar { index, base, .. } => {
match index {
IVSHMEM_BAR0_IDX => {
bar0_addr = Some(GuestAddress(base));
}
IVSHMEM_BAR1_IDX => {}
IVSHMEM_BAR2_IDX => {
bar2_addr = Some(GuestAddress(base));
}
_ => {
error!("Unexpected pci bar index {index}");
}
};
}
Resource::PciBar { index, base, .. } => match index {
IVSHMEM_BAR0_IDX => {
bar0_addr = Some(GuestAddress(base));
}
IVSHMEM_BAR1_IDX => {}
IVSHMEM_BAR2_IDX => {
bar2_addr = Some(GuestAddress(base));
}
_ => {
error!("Unexpected pci bar index {index}");
}
},
_ => {
error!("Unexpected resource {resource:?}");
}
@@ -348,7 +343,7 @@ impl PciDevice for IvshmemDevice {
_ => {
warn!("Invalid bar_idx: {bar_idx}");
}
};
}
}
fn write_bar(&mut self, base: u64, offset: u64, _data: &[u8]) -> Option<Arc<Barrier>> {

View File

@@ -13,6 +13,7 @@ use std::{mem, thread};
#[cfg_attr(target_env = "musl", allow(deprecated))]
use libc::time_t;
use libc::{CLOCK_REALTIME, clock_gettime, gmtime_r, timespec, tm};
use log::{info, warn};
use vm_device::BusDevice;
use vmm_sys_util::eventfd::EventFd;
@@ -87,11 +88,11 @@ impl BusDevice for Cmos {
}
}
} else {
self.data[(self.index & INDEX_MASK) as usize] = data[0]
self.data[(self.index & INDEX_MASK) as usize] = data[0];
}
}
o => warn!("bad write offset on CMOS device: {o}"),
};
}
None
}

View File

@@ -6,6 +6,7 @@
use std::fmt;
use std::time::Instant;
use log::{error, warn};
use vm_device::BusDevice;
/// Debug I/O port, see:
@@ -62,7 +63,7 @@ impl DebugPort {
impl BusDevice for DebugPort {
fn read(&mut self, _base: u64, _offset: u64, _data: &mut [u8]) {
error!("Invalid read to debug port")
error!("Invalid read to debug port");
}
fn write(

View File

@@ -35,6 +35,7 @@ use bitfield_struct::bitfield;
use linux_loader::bootparam::boot_params;
#[cfg(target_arch = "aarch64")]
use linux_loader::loader::pe::arm64_image_header as boot_params;
use log::{debug, error};
use vm_device::BusDevice;
use vm_memory::bitmap::AtomicBitmap;
use vm_memory::{
@@ -442,7 +443,7 @@ impl FwCfg {
fw_cfg_item_list: Option<Vec<FwCfgItem>>,
) -> Result<()> {
if let Some(mem_size) = mem_size {
self.add_e820(mem_size)?
self.add_e820(mem_size)?;
}
if let Some(kernel) = kernel {
self.add_kernel_data(&kernel)?;
@@ -451,7 +452,7 @@ impl FwCfg {
self.add_kernel_cmdline(cmdline);
}
if let Some(initramfs) = initramfs {
self.add_initramfs_data(&initramfs)?
self.add_initramfs_data(&initramfs)?;
}
if let Some(fw_cfg_item_list) = fw_cfg_item_list {
for item in fw_cfg_item_list {
@@ -626,7 +627,7 @@ impl FwCfg {
&access_resp.0.to_be_bytes(),
GuestAddress(dma_address + core::mem::offset_of!(FwCfgDmaAccess, control_be) as u64),
) {
error!("fw_cfg: finishing dma: {e:?}")
error!("fw_cfg: finishing dma: {e:?}");
}
}
@@ -710,7 +711,7 @@ impl FwCfg {
let bytes = n.to_le_bytes();
data.copy_from_slice(&bytes[start..end]);
}
};
}
Some(size as u8)
}
@@ -756,7 +757,7 @@ impl BusDevice for FwCfg {
"fw_cfg: read from unknown port {port:#x}: {size:#x} bytes and offset {offset:#x}."
);
}
};
}
}
fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
@@ -792,13 +793,13 @@ impl BusDevice for FwCfg {
_ => debug!(
"fw_cfg: write to unknown port {port:#x}: {size:#x} bytes and offset {offset:#x} ."
),
};
}
None
}
}
#[cfg(test)]
mod tests {
mod unit_tests {
use std::ffi::CString;
use std::io::Write;

View File

@@ -9,6 +9,7 @@
use std::sync::{Arc, Barrier};
use log::error;
use vm_device::BusDevice;
/// Provides firmware debug output via I/O port controls
@@ -26,9 +27,9 @@ impl BusDevice for FwDebugDevice {
/// Upon read return the magic value to indicate that there is a debug port
fn read(&mut self, _base: u64, _offset: u64, data: &mut [u8]) {
if data.len() == 1 {
data[0] = 0xe9
data[0] = 0xe9;
} else {
error!("Invalid read size on debug port: {}", data.len())
error!("Invalid read size on debug port: {}", data.len());
}
}
@@ -36,7 +37,7 @@ impl BusDevice for FwDebugDevice {
if data.len() == 1 {
print!("{}", data[0] as char);
} else {
error!("Invalid write size on debug port: {}", data.len())
error!("Invalid write size on debug port: {}", data.len());
}
None

View File

@@ -10,6 +10,7 @@
use std::sync::{Arc, Barrier};
use std::{io, result};
use log::warn;
use serde::{Deserialize, Serialize};
use thiserror::Error;
use vm_device::BusDevice;
@@ -261,7 +262,7 @@ impl BusDevice for Gpio {
let index = ((offset - GPIO_ID_LOW) >> 2) as usize;
value = u32::from(GPIO_ID[index]);
} else if offset < OFS_DATA {
value = self.data & ((offset >> 2) as u32)
value = self.data & ((offset >> 2) as u32);
} else {
value = match offset {
GPIODIR => self.dir,
@@ -294,7 +295,7 @@ impl BusDevice for Gpio {
if data.len() <= 4 {
let value = read_le_u32(data);
if let Err(e) = self.handle_write(offset, value) {
warn!("Failed to write to GPIO PL061 device: {}", e);
warn!("Failed to write to GPIO PL061 device: {e}");
}
} else {
warn!(
@@ -323,7 +324,7 @@ impl Transportable for Gpio {}
impl Migratable for Gpio {}
#[cfg(test)]
mod tests {
mod unit_tests {
use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig};
use vmm_sys_util::eventfd::EventFd;

View File

@@ -8,6 +8,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Barrier};
use std::thread;
use log::{error, info};
use vm_device::BusDevice;
use vmm_sys_util::eventfd::EventFd;

View File

@@ -15,6 +15,7 @@ use std::result;
use std::sync::{Arc, Barrier};
use std::time::Instant;
use log::warn;
use thiserror::Error;
use vm_device::BusDevice;
@@ -201,12 +202,11 @@ impl BusDevice for Rtc {
if data.len() <= 4 {
let v = read_le_u32(data);
if let Err(e) = self.handle_write(offset, v) {
warn!("Failed to write to RTC PL031 device: {}", e);
warn!("Failed to write to RTC PL031 device: {e}");
}
} else {
warn!(
"Invalid RTC PL031 write: offset {}, data length {}",
offset,
"Invalid RTC PL031 write: offset {offset}, data length {}",
data.len()
);
}
@@ -216,7 +216,7 @@ impl BusDevice for Rtc {
}
#[cfg(test)]
mod tests {
mod unit_tests {
use super::*;
use crate::{
read_be_u16, read_be_u32, read_le_i32, read_le_u16, read_le_u64, write_be_u16,

View File

@@ -215,7 +215,7 @@ impl Serial {
fn thr_empty(&mut self) -> Result<()> {
if self.is_thr_intr_enabled() {
self.add_intr_bit(IIR_THR_BIT);
self.trigger_interrupt()?
self.trigger_interrupt()?;
}
Ok(())
}
@@ -223,7 +223,7 @@ impl Serial {
fn recv_data(&mut self) -> Result<()> {
if self.is_recv_intr_enabled() {
self.add_intr_bit(IIR_RECV_BIT);
self.trigger_interrupt()?
self.trigger_interrupt()?;
}
self.line_status |= LSR_DATA_BIT;
Ok(())
@@ -240,10 +240,10 @@ impl Serial {
fn handle_write(&mut self, offset: u8, v: u8) -> Result<()> {
match offset {
DLAB_LOW if self.is_dlab_set() => {
self.baud_divisor = (self.baud_divisor & 0xff00) | u16::from(v)
self.baud_divisor = (self.baud_divisor & 0xff00) | u16::from(v);
}
DLAB_HIGH if self.is_dlab_set() => {
self.baud_divisor = (self.baud_divisor & 0x00ff) | ((u16::from(v)) << 8)
self.baud_divisor = (self.baud_divisor & 0x00ff) | ((u16::from(v)) << 8);
}
DATA => {
if self.is_loop() {
@@ -340,7 +340,7 @@ impl Transportable for Serial {}
impl Migratable for Serial {}
#[cfg(test)]
mod tests {
mod unit_tests {
use std::sync::Mutex;
use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig};

View File

@@ -11,6 +11,7 @@ use std::sync::{Arc, Barrier};
use std::time::Instant;
use std::{io, result};
use log::{debug, warn};
use serde::{Deserialize, Serialize};
use thiserror::Error;
use vm_device::BusDevice;
@@ -322,7 +323,7 @@ impl Pl011 {
self.handle_debug();
}
off => {
debug!("PL011: Bad write offset, offset: {}", off);
debug!("PL011: Bad write offset, offset: {off}");
return Err(Error::BadWriteOffset(off));
}
}
@@ -424,12 +425,11 @@ impl BusDevice for Pl011 {
if data.len() <= 4 {
let v = read_le_u32(data);
if let Err(e) = self.handle_write(offset, v) {
warn!("Failed to write to PL011 device: {}", e);
warn!("Failed to write to PL011 device: {e}");
}
} else {
warn!(
"Invalid PL011 write: offset {}, data length {}",
offset,
"Invalid PL011 write: offset {offset}, data length {}",
data.len()
);
}
@@ -453,7 +453,7 @@ impl Transportable for Pl011 {}
impl Migratable for Pl011 {}
#[cfg(test)]
mod tests {
mod unit_tests {
use std::sync::Mutex;
use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig};

View File

@@ -7,13 +7,6 @@
//! Emulates virtual and hardware devices.
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate event_monitor;
#[macro_use]
extern crate log;
pub mod acpi;
#[cfg(target_arch = "riscv64")]
pub mod aia;
@@ -34,6 +27,8 @@ pub mod pvpanic;
#[cfg(not(target_arch = "riscv64"))]
pub mod tpm;
use bitflags::bitflags;
pub use self::acpi::{AcpiGedDevice, AcpiPmTimerDevice, AcpiShutdownDevice};
#[cfg(feature = "ivshmem")]
pub use self::ivshmem::IvshmemDevice;

View File

@@ -8,6 +8,7 @@ use std::ffi::CString;
use std::sync::{Arc, Barrier, Mutex, RwLock};
use std::{io, result};
use log::{debug, warn};
use num_enum::TryFromPrimitive;
use pci::{
BarReprogrammingParams, PciBarConfiguration, PciBarPrefetchable, PciBarRegionType,
@@ -390,7 +391,7 @@ impl PvmemcontrolDevice {
.iter()
.skip(offset as usize)
.zip(data.iter_mut())
.for_each(|(src, dest)| *dest = *src)
.for_each(|(src, dest)| *dest = *src);
}
/// can only write to transport payload
@@ -402,7 +403,7 @@ impl PvmemcontrolDevice {
.iter_mut()
.skip(offset as usize)
.zip(data.iter())
.for_each(|(dest, src)| *dest = *src)
.for_each(|(dest, src)| *dest = *src);
}
fn find_connection(&self, conn: GuestConnection) -> Option<GuestAddress> {
@@ -429,22 +430,20 @@ impl PvmemcontrolBusDevice {
/// [`range_base`, `range_base` + `range_len`) is present in the guest
fn operate_on_memory_range<F>(&self, addr: u64, length: u64, f: F) -> result::Result<(), Error>
where
F: FnOnce(*mut libc::c_void, libc::size_t) -> libc::c_int,
F: FnOnce(*mut libc::c_void, usize) -> libc::c_int,
{
let memory = self.mem.memory();
let range_base = GuestAddress(addr);
let range_len = usize::try_from(length).map_err(|_| Error::InvalidRequest)?;
// assume guest memory is not interleaved with vmm memory on the host.
if !memory.check_range(range_base, range_len) {
let Ok(slice) = memory.get_slice(range_base, range_len) else {
return Err(Error::GuestMemory(GuestMemoryError::InvalidGuestAddress(
range_base,
)));
}
let hva = memory
.get_host_address(range_base)
.map_err(Error::GuestMemory)?;
let res = f(hva as *mut libc::c_void, range_len as libc::size_t);
};
assert!(slice.len() >= range_len);
let res = f(slice.ptr_guard_mut().as_ptr() as _, slice.len());
if res != 0 {
return Err(Error::LibcFail(io::Error::last_os_error()));
}
@@ -491,7 +490,7 @@ impl PvmemcontrolBusDevice {
} else {
std::ptr::null()
};
debug!("addr {:X} length {} name {:?}", addr, length, name);
debug!("addr {addr:X} length {length} name {name:?}");
// SAFETY: [`base`, `base` + `len`) is guest memory
self.operate_on_memory_range(addr, length, |base, len| unsafe {
@@ -581,7 +580,7 @@ impl PvmemcontrolBusDevice {
..Default::default()
},
Error::GuestMemory(err) => {
warn!("{}", err);
warn!("{err}");
PvmemcontrolResp {
ret_errno: (libc::EINVAL as u32).into(),
ret_code: (func_code as u32).into(),
@@ -606,7 +605,7 @@ impl PvmemcontrolBusDevice {
let response: PvmemcontrolResp = match self.handle_request(request) {
Ok(x) => x,
Err(e) => {
warn!("cannot process request {:?} with error {}", request, e);
warn!("cannot process request {request:?} with error {e}");
return;
}
};
@@ -649,14 +648,16 @@ impl PvmemcontrolBusDevice {
.find_connection(conn)
.ok_or(Error::InvalidConnection(conn.command))
})
.map(|gpa| self.handle_pvmemcontrol_request(gpa))
.unwrap_or_else(|err| warn!("{:?}", err));
.map_or_else(
|err| warn!("{err:?}"),
|gpa| self.handle_pvmemcontrol_request(gpa),
);
}
}
}
fn handle_guest_read(&self, offset: u64, data: &mut [u8]) {
self.dev.read().unwrap().read_transport(offset, data)
self.dev.read().unwrap().read_transport(offset, data);
}
}
@@ -760,7 +761,7 @@ impl PciDevice for PvmemcontrolPciDevice {
_mmio64_allocator: &mut AddressAllocator,
) -> Result<(), PciDeviceError> {
for bar in self.bar_regions.drain(..) {
mmio32_allocator.free(GuestAddress(bar.addr()), bar.size())
mmio32_allocator.free(GuestAddress(bar.addr()), bar.size());
}
Ok(())
}
@@ -805,7 +806,7 @@ impl Migratable for PvmemcontrolPciDevice {}
impl BusDeviceSync for PvmemcontrolBusDevice {
fn read(&self, _base: u64, offset: u64, data: &mut [u8]) {
self.handle_guest_read(offset, data)
self.handle_guest_read(offset, data);
}
fn write(&self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {

View File

@@ -8,6 +8,8 @@ use std::result;
use std::sync::{Arc, Barrier, Mutex};
use anyhow::anyhow;
use event_monitor::event;
use log::{debug, info};
use pci::{
BarReprogrammingParams, PCI_CONFIGURATION_ID, PciBarConfiguration, PciBarPrefetchable,
PciBarRegionType, PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType,
@@ -64,13 +66,13 @@ pub struct PvPanicDeviceState {
}
impl PvPanicDevice {
pub fn new(id: String, snapshot: Option<Snapshot>) -> Result<Self, PvPanicError> {
let pci_configuration_state =
vm_migration::state_from_id(snapshot.as_ref(), PCI_CONFIGURATION_ID).map_err(|e| {
PvPanicError::RetrievePciConfigurationState(anyhow!(
"Failed to get PciConfigurationState from Snapshot: {e}"
))
})?;
pub fn new(id: String, snapshot: Option<&Snapshot>) -> Result<Self, PvPanicError> {
let pci_configuration_state = vm_migration::state_from_id(snapshot, PCI_CONFIGURATION_ID)
.map_err(|e| {
PvPanicError::RetrievePciConfigurationState(anyhow!(
"Failed to get PciConfigurationState from Snapshot: {e}"
))
})?;
let mut configuration = PciConfiguration::new(
PVPANIC_VENDOR_ID,
@@ -141,7 +143,7 @@ impl PvPanicDevice {
impl BusDevice for PvPanicDevice {
fn read(&mut self, base: u64, offset: u64, data: &mut [u8]) {
self.read_bar(base, offset, data)
self.read_bar(base, offset, data);
}
fn write(&mut self, _base: u64, _offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {

View File

@@ -4,6 +4,7 @@
//
use std::cmp;
use std::path::Path;
use std::sync::{Arc, Barrier};
use anyhow::anyhow;
@@ -11,6 +12,7 @@ use anyhow::anyhow;
use arch::aarch64::layout::{TPM_SIZE, TPM_START};
#[cfg(target_arch = "x86_64")]
use arch::x86_64::layout::{TPM_SIZE, TPM_START};
use log::{debug, error, warn};
use thiserror::Error;
use tpm::TPM_CRB_BUFFER_MAX;
use tpm::emulator::{BackendCmd, Emulator};
@@ -26,6 +28,7 @@ pub enum Error {
type Result<T> = anyhow::Result<T, Error>;
#[allow(dead_code)]
#[derive(Copy, Clone)]
enum LocStateFields {
TpmEstablished,
LocAssigned,
@@ -34,12 +37,14 @@ enum LocStateFields {
TpmRegValidSts,
}
#[derive(Copy, Clone)]
enum LocStsFields {
Granted,
BeenSeized,
}
#[allow(dead_code)]
#[derive(Copy, Clone)]
enum IntfIdFields {
InterfaceType,
InterfaceVersion,
@@ -57,16 +62,19 @@ enum IntfIdFields {
}
#[allow(dead_code)]
#[derive(Copy, Clone)]
enum IntfId2Fields {
Vid,
Did,
}
#[derive(Copy, Clone)]
enum CtrlStsFields {
TpmSts,
TpmIdle,
}
#[derive(Copy, Clone)]
enum CrbRegister {
LocState(LocStateFields),
LocSts(LocStsFields),
@@ -99,6 +107,7 @@ const CRB_LOC_CTRL_REQUEST_ACCESS: u32 = 1 << 0;
const CRB_LOC_CTRL_RELINQUISH: u32 = 1 << 1;
const CRB_LOC_CTRL_RESET_ESTABLISHMENT_BIT: u32 = 1 << 3;
const CRB_LOC_STS: u32 = 0x0C;
const fn get_crb_loc_sts_field(f: LocStsFields) -> (u32, u32, u32) {
let (offset, len) = match f {
LocStsFields::Granted => (0, 1),
@@ -219,7 +228,7 @@ pub struct Tpm {
}
impl Tpm {
pub fn new(path: String) -> Result<Self> {
pub fn new(path: impl AsRef<Path>) -> Result<Self> {
let emulator = Emulator::new(path)
.map_err(|e| Error::Init(anyhow!("Failed while initializing tpm Emulator: {e:?}")))?;
let mut tpm = Tpm {
@@ -531,7 +540,7 @@ impl BusDevice for Tpm {
}
#[cfg(test)]
mod tests {
mod unit_tests {
use super::*;
#[test]

View File

@@ -86,6 +86,7 @@ The Cloud Hypervisor API exposes the following actions through its endpoints:
| Restore the VM from a snapshot | `/vm.restore` | `/schemas/RestoreConfig` | N/A | The VM is created but not booted |
| Add/remove CPUs to/from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted |
| Add/remove memory from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted |
| Resize a disk attached to the VM | `/vm.resize-disk` | `/schemas/VmResizeDisk` | N/A | The VM is created |
| Add/remove memory from a zone | `/vm.resize-zone` | `/schemas/VmResizeZone` | N/A | The VM is booted |
| Dump the VM information | `/vm.info` | N/A | `/schemas/VmInfo` | The VM is created |
| Add VFIO PCI device to the VM | `/vm.add-device` | `/schemas/VmAddDevice` | `/schemas/PciDeviceInfo` | The VM is booted |

View File

@@ -18,11 +18,12 @@ struct CpusConfig {
max_phys_bits: u8,
affinity: Option<Vec<CpuAffinity>>,
features: CpuFeatures,
nested: bool,
}
```
```
--cpus boot=<boot_vcpus>,max=<max_vcpus>,topology=<threads_per_core>:<cores_per_die>:<dies_per_package>:<packages>,kvm_hyperv=on|off,max_phys_bits=<maximum_number_of_physical_bits>,affinity=<list_of_vcpus_with_their_associated_cpuset>,features=<list_of_features_to_enable>
--cpus boot=<boot_vcpus>,max=<max_vcpus>,topology=<threads_per_core>:<cores_per_die>:<dies_per_package>:<packages>,kvm_hyperv=on|off,max_phys_bits=<maximum_number_of_physical_bits>,affinity=<list_of_vcpus_with_their_associated_cpuset>,features=<list_of_features_to_enable>,nested=on|off
```
### `boot`
@@ -209,3 +210,14 @@ _Example_
```
In this example the amx CPU feature will be enabled for the VMM.
### `nested`
Enable nested virtualization (default on). Nested virtualization is needed to access hardware virtualization by this guest. This option can only be changed on x86-64.
_Example_
```
--cpus nested=on
```

View File

@@ -7,5 +7,9 @@ version = "0.1.0"
[dependencies]
flume = { workspace = true }
libc = { workspace = true }
log = { workspace = true }
serde = { workspace = true, features = ["derive", "rc"] }
serde_json = { workspace = true }
[lints]
workspace = true

View File

@@ -6,11 +6,12 @@
use std::borrow::Cow;
use std::collections::HashMap;
use std::fs::File;
use std::io;
use std::os::unix::io::AsRawFd;
use std::sync::{Arc, OnceLock};
use std::time::{Duration, Instant};
use std::{fmt, io};
use log::info;
use serde::Serialize;
static MONITOR: OnceLock<MonitorHandle> = OnceLock::new();
@@ -88,12 +89,31 @@ pub fn set_monitor(file: Option<File>) -> io::Result<Monitor> {
Ok(monitor)
}
struct PropertiesFormatter<'a>(&'a Option<&'a HashMap<Cow<'a, str>, Cow<'a, str>>>);
impl<'a> fmt::Display for PropertiesFormatter<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(map) = self.0 {
for (i, (key, value)) in map.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{key} = {value}")?;
}
}
Ok(())
}
}
pub fn event_log(source: &str, event: &str, properties: Option<&HashMap<Cow<str>, Cow<str>>>) {
// `MONITOR` is always in a valid state (None or Some), because it is set
// only once before any threads are spawned, and it's not mutated
// afterwards. This function only creates immutable references to `MONITOR`.
// Because `MONITOR.tx` is `Sync`, it's safe to share `MONITOR` across
// threads, making this function thread-safe.
info!(
"Event: source = {source} event = {event} {}",
PropertiesFormatter(&properties)
);
if let Some(monitor_handle) = MONITOR.get().as_ref() {
let event = Event {
timestamp: monitor_handle.start.elapsed(),

360
fuzz/Cargo.lock generated
View File

@@ -10,6 +10,12 @@ dependencies = [
"zerocopy",
]
[[package]]
name = "adler2"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]]
name = "anstream"
version = "0.6.21"
@@ -42,18 +48,18 @@ dependencies = [
[[package]]
name = "anstyle-query"
version = "1.1.4"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2"
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.10"
version = "3.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a"
checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
dependencies = [
"anstyle",
"once_cell_polyfill",
@@ -105,9 +111,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "bitfield-struct"
version = "0.11.0"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3ca019570363e800b05ad4fd890734f28ac7b72f563ad8a35079efb793616f8"
checksum = "8769c4854c5ada2852ddf6fd09d15cf43d4c2aaeccb4de6432f5402f08a6003b"
dependencies = [
"proc-macro2",
"quote",
@@ -122,9 +128,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.9.4"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394"
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
[[package]]
name = "block"
@@ -132,6 +138,7 @@ version = "0.1.0"
dependencies = [
"byteorder",
"crc-any",
"flate2",
"libc",
"log",
"remain",
@@ -144,6 +151,7 @@ dependencies = [
"vm-memory",
"vm-virtio",
"vmm-sys-util",
"zstd",
]
[[package]]
@@ -160,9 +168,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cc"
version = "1.2.41"
version = "1.2.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7"
checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215"
dependencies = [
"find-msvc-tools",
"jobserver",
@@ -172,24 +180,24 @@ dependencies = [
[[package]]
name = "cfg-if"
version = "1.0.3"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "clap"
version = "4.5.49"
version = "4.5.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4512b90fa68d3a9932cea5184017c5d200f5921df706d45e853537dea51508f"
checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.5.49"
version = "4.5.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0025e98baa12e766c67ba13ff4695a887a1eba19569aad00a472546795bd6730"
checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00"
dependencies = [
"anstream",
"anstyle",
@@ -254,6 +262,15 @@ dependencies = [
"debug-helper",
]
[[package]]
name = "crc32fast"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
dependencies = [
"cfg-if",
]
[[package]]
name = "darling"
version = "0.21.3"
@@ -302,7 +319,7 @@ dependencies = [
"acpi_tables",
"anyhow",
"arch",
"bitflags 2.9.4",
"bitflags 2.10.0",
"byteorder",
"event_monitor",
"hypervisor",
@@ -320,6 +337,12 @@ dependencies = [
"vmm-sys-util",
]
[[package]]
name = "either"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "enumflags2"
version = "0.7.12"
@@ -346,7 +369,7 @@ version = "4.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e74d68fe2927dbf47aa976d14d93db9b23dced457c7bb2bdc6925a16d31b736e"
dependencies = [
"bitflags 2.9.4",
"bitflags 2.10.0",
"libc",
]
@@ -362,10 +385,20 @@ version = "0.1.0"
dependencies = [
"flume",
"libc",
"log",
"serde",
"serde_json",
]
[[package]]
name = "fastrand"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
dependencies = [
"getrandom 0.2.16",
]
[[package]]
name = "fdt"
version = "0.1.5"
@@ -374,19 +407,29 @@ checksum = "784a4df722dc6267a04af36895398f59d21d07dce47232adf31ec0ff2fa45e67"
[[package]]
name = "find-msvc-tools"
version = "0.1.4"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127"
checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844"
[[package]]
name = "flate2"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]]
name = "flume"
version = "0.11.1"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095"
checksum = "5e139bc46ca777eb5efaf62df0ab8cc5fd400866427e56c68b22e414e53bd3be"
dependencies = [
"fastrand",
"futures-core",
"futures-sink",
"nanorand",
"spin",
]
@@ -414,7 +457,7 @@ version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72742d2b395902caf8a5d520d0dd3334ba6d1138938429200e58d5174e275f3f"
dependencies = [
"bitflags 2.9.4",
"bitflags 2.10.0",
"cfg-if",
"log",
"managed",
@@ -441,27 +484,27 @@ dependencies = [
"cfg-if",
"js-sys",
"libc",
"wasi 0.11.1+wasi-snapshot-preview1",
"wasi",
"wasm-bindgen",
]
[[package]]
name = "getrandom"
version = "0.3.3"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
dependencies = [
"cfg-if",
"libc",
"r-efi",
"wasi 0.14.2+wasi-0.2.4",
"wasip2",
]
[[package]]
name = "hashbrown"
version = "0.16.0"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
[[package]]
name = "hypervisor"
@@ -507,9 +550,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "indexmap"
version = "2.11.4"
version = "2.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5"
checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2"
dependencies = [
"equivalent",
"hashbrown",
@@ -517,9 +560,18 @@ dependencies = [
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
[[package]]
name = "itertools"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
dependencies = [
"either",
]
[[package]]
name = "itoa"
@@ -533,7 +585,7 @@ version = "0.1.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
dependencies = [
"getrandom 0.3.3",
"getrandom 0.3.4",
"libc",
]
@@ -564,7 +616,7 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c8f7370330b4f57981e300fa39b02088f2f2a5c2d0f1f994e8090589619c56d"
dependencies = [
"bitflags 2.9.4",
"bitflags 2.10.0",
"kvm-bindings",
"libc",
"vmm-sys-util",
@@ -572,9 +624,9 @@ dependencies = [
[[package]]
name = "landlock"
version = "0.4.3"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "affe8b77dce5b172f8e290bd801b12832a77cd1942d1ea98259916e89d5829d6"
checksum = "49fefd6652c57d68aaa32544a4c0e642929725bdc1fd929367cdeb673ab81088"
dependencies = [
"enumflags2",
"libc",
@@ -589,9 +641,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.177"
version = "0.2.178"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
[[package]]
name = "libfuzzer-sys"
@@ -623,9 +675,9 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.28"
version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
name = "managed"
@@ -649,10 +701,20 @@ dependencies = [
]
[[package]]
name = "mshv-bindings"
version = "0.6.0"
name = "miniz_oxide"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "805cf329582f770f62cc612716a04c14815276ae266b6298375a672d3c5a5184"
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
dependencies = [
"adler2",
"simd-adler32",
]
[[package]]
name = "mshv-bindings"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66f415da68542aca92b33f55ac3e93031dc30a2941952b99679258f7e0527353"
dependencies = [
"libc",
"num_enum",
@@ -662,15 +724,6 @@ dependencies = [
"zerocopy",
]
[[package]]
name = "nanorand"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3"
dependencies = [
"getrandom 0.2.16",
]
[[package]]
name = "net_gen"
version = "0.1.0"
@@ -683,7 +736,7 @@ name = "net_util"
version = "0.1.0"
dependencies = [
"epoll",
"getrandom 0.3.3",
"getrandom 0.3.4",
"libc",
"log",
"net_gen",
@@ -708,9 +761,9 @@ dependencies = [
[[package]]
name = "num_enum"
version = "0.7.4"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a"
checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c"
dependencies = [
"num_enum_derive",
"rustversion",
@@ -718,9 +771,9 @@ dependencies = [
[[package]]
name = "num_enum_derive"
version = "0.7.4"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d"
checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7"
dependencies = [
"proc-macro-crate",
"proc-macro2",
@@ -736,9 +789,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "once_cell_polyfill"
version = "1.70.1"
version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]]
name = "open-enum"
@@ -794,6 +847,12 @@ dependencies = [
"vmm-sys-util",
]
[[package]]
name = "pkg-config"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
[[package]]
name = "ppv-lite86"
version = "0.2.21"
@@ -814,18 +873,18 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.101"
version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.41"
version = "1.0.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
dependencies = [
"proc-macro2",
]
@@ -862,7 +921,7 @@ version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
dependencies = [
"getrandom 0.3.3",
"getrandom 0.3.4",
]
[[package]]
@@ -959,9 +1018,9 @@ dependencies = [
[[package]]
name = "serde_with"
version = "3.15.0"
version = "3.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6093cd8c01b25262b84927e0f7151692158fab02d961e04c979d3903eba7ecc5"
checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7"
dependencies = [
"serde_core",
"serde_with_macros",
@@ -969,9 +1028,9 @@ dependencies = [
[[package]]
name = "serde_with_macros"
version = "3.15.0"
version = "3.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7e6c180db0816026a61afa1cff5344fb7ebded7e4d3062772179f2501481c27"
checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c"
dependencies = [
"darling",
"proc-macro2",
@@ -1001,13 +1060,19 @@ dependencies = [
[[package]]
name = "signal-hook-registry"
version = "1.4.6"
version = "1.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b"
checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad"
dependencies = [
"libc",
]
[[package]]
name = "simd-adler32"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2"
[[package]]
name = "smallvec"
version = "1.15.1"
@@ -1031,9 +1096,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.106"
version = "2.0.111"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87"
dependencies = [
"proc-macro2",
"quote",
@@ -1091,9 +1156,9 @@ dependencies = [
[[package]]
name = "toml_edit"
version = "0.23.7"
version = "0.23.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d"
checksum = "5d7cbc3b4b49633d57a0509303158ca50de80ae32c265093b24c414705807832"
dependencies = [
"indexmap",
"toml_datetime",
@@ -1134,9 +1199,9 @@ dependencies = [
[[package]]
name = "unicode-ident"
version = "1.0.19"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
[[package]]
name = "utf8parse"
@@ -1146,11 +1211,11 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "uuid"
version = "1.18.1"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2"
checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a"
dependencies = [
"getrandom 0.3.3",
"getrandom 0.3.4",
"js-sys",
"rand",
"wasm-bindgen",
@@ -1188,7 +1253,7 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8db5bc783aad75202ad4cbcdc5e893cff1dd8fa24a1bcdb4de8998d3c4d169a"
dependencies = [
"bitflags 2.9.4",
"bitflags 2.10.0",
"libc",
"log",
"serde",
@@ -1206,7 +1271,7 @@ version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a4dcad85a129d97d5d4b2f3c47a4affdeedd76bdcd02094bcb5d9b76cac2d05"
dependencies = [
"bitflags 2.9.4",
"bitflags 2.10.0",
"libc",
"uuid",
"vm-memory",
@@ -1305,6 +1370,7 @@ name = "vm-migration"
version = "0.1.0"
dependencies = [
"anyhow",
"itertools",
"serde",
"serde_json",
"thiserror 2.0.17",
@@ -1326,7 +1392,7 @@ dependencies = [
"acpi_tables",
"anyhow",
"arch",
"bitflags 2.9.4",
"bitflags 2.10.0",
"block",
"cfg-if",
"clap",
@@ -1387,12 +1453,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "wasi"
version = "0.14.2+wasi-0.2.4"
name = "wasip2"
version = "1.0.1+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
dependencies = [
"wit-bindgen-rt",
"wit-bindgen",
]
[[package]]
@@ -1483,112 +1549,72 @@ checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.60.2"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.53.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link",
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
[[package]]
name = "windows_aarch64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
[[package]]
name = "windows_i686_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
[[package]]
name = "windows_i686_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
[[package]]
name = "windows_i686_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
[[package]]
name = "windows_x86_64_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
[[package]]
name = "windows_x86_64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
[[package]]
name = "winnow"
version = "0.7.13"
version = "0.7.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf"
checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829"
dependencies = [
"memchr",
]
[[package]]
name = "wit-bindgen-rt"
version = "0.39.0"
name = "wit-bindgen"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
dependencies = [
"bitflags 2.9.4",
]
checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
[[package]]
name = "zerocopy"
version = "0.8.27"
version = "0.8.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c"
checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.27"
version = "0.8.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831"
checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "zstd"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
dependencies = [
"zstd-safe",
]
[[package]]
name = "zstd-safe"
version = "7.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
dependencies = [
"zstd-sys",
]
[[package]]
name = "zstd-sys"
version = "2.0.16+zstd.1.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748"
dependencies = [
"cc",
"pkg-config",
]

View File

@@ -21,11 +21,11 @@ block = { path = "../block" }
devices = { path = "../devices" }
epoll = "4.3.3"
hypervisor = { path = "../hypervisor", features = ["mshv_emulator"] }
libc = "0.2.177"
libc = "0.2.178"
libfuzzer-sys = "0.4.10"
linux-loader = { version = "0.13.1", features = ["bzimage", "elf", "pe"] }
micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "main" }
mshv-bindings = "0.6.0"
mshv-bindings = "0.6.5"
net_util = { path = "../net_util" }
seccompiler = "0.5.0"
virtio-devices = { path = "../virtio-devices" }

Some files were not shown because too many files have changed in this diff Show More