diff --git a/Cargo.lock b/Cargo.lock index de011b07a1d..4b8441f50bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -260,9 +260,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.10" +version = "1.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" +checksum = "e4730490333d58093109dc02c23174c3f4d490998c3fed3cc8e82d57afedb9cf" dependencies = [ "jobserver", "libc", @@ -396,9 +396,9 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.52" +version = "0.1.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c682c223677e0e5b6b7f63a64b9351844c3f1b1678a68b7ee617e30fb082620e" +checksum = "e24a03c8b52922d68a1589ad61032f2c1aa5a8158d2aa0d93c6e9534944bbad6" dependencies = [ "cc", ] @@ -1166,9 +1166,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" [[package]] name = "same-file" @@ -1224,9 +1224,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.137" +version = "1.0.138" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" +checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" dependencies = [ "itoa", "memchr", @@ -1288,9 +1288,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.96" +version = "2.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" dependencies = [ "proc-macro2", "quote", @@ -1379,9 +1379,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.22" +version = "0.22.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +checksum = "02a8b472d1a3d7c18e2d61a489aee3453fd9031c33e4f55bd533f4a7adca1bee" dependencies = [ "indexmap", "serde", @@ -1404,9 +1404,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11cd88e12b17c6494200a9c1b683a04fcac9573ed74cd1b62aeb2727c5592243" +checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" [[package]] name = "unicode-xid" @@ -1737,9 +1737,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.24" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" +checksum = "7e49d2d35d3fad69b39b94139037ecfb4f359f08958b9c11e7315ce770462419" dependencies = [ "memchr", ] diff --git a/docs/snapshotting/snapshot-support.md b/docs/snapshotting/snapshot-support.md index 910dde94ce7..e1294e1ac7d 100644 --- a/docs/snapshotting/snapshot-support.md +++ b/docs/snapshotting/snapshot-support.md @@ -25,6 +25,8 @@ - [Secure and insecure usage examples](#usage-examples) - [Reusing snapshotted states securely](#reusing-snapshotted-states-securely) - [Vsock device limitation](#vsock-device-limitation) +- [VMGenID device limitation](#vmgenid-device-limitation) +- [Where can I resume my snapshots?](#where-can-i-resume-my-snapshots) ## About microVM snapshotting @@ -638,28 +640,19 @@ might not be able to handle the injected notification and crash. We suggest to users that they take snapshots only after the guest kernel has completed booting, to avoid this issue. -## Snapshot compatibility across kernel versions +## Where can I resume my snapshots? -We have a mechanism in place to experiment with snapshot compatibility across -supported host kernel versions by generating snapshot artifacts through -[this test](../../tests/integration_tests/functional/test_snapshot_phase1.py) -and checking devices' functionality using -[this test](../../tests/integration_tests/functional/test_snapshot_restore_cross_kernel.py). -The test restores the snapshot and ensures that all the devices set-up (network -devices, disk, vsock, balloon and MMDS) are operational post-load. +Snapshots must be resumed on an software and hardware configuration which is +identical to what they were generated on. However, in limited cases, snapshots +can be resumed on identical hardware instances where they were taken on, but +using newer host kernel versions. While we do not provide any guarantees on this +setup (and do not recommend doing this in production), we are currently aware of +the compatibility table reported below: -In those tests the instance is fixed, except some combinations where we also -test across the same CPU family (Intel x86, Gravitons). In general cross-CPU -snapshots [are not supported](./versioning.md#cpu-model) +| .metal instance type | taken on host kernel | restored on host kernel | +| -------------------- | -------------------- | ----------------------- | +| {c5n,m5n,m6i,m6a} | 5.10 | 6.1 | -The tables below reflect the snapshot compatibility observed on the AWS -instances we support. - -**all** means all currently supported Intel/AMD/ARM metal instances (m6g, m7g, -m5n, c5n, m6i, m6a). It does not mean cross-instance, i.e. a snapshot taken on -m6i won't work on an m6g instance. - -| *CPU family* | *taken on host kernel* | *restored on host kernel* | *working?* | -| ------------ | ---------------------- | ------------------------- | ---------- | -| **x86_64** | 5.10 | 6.1 | Y | -| **x86_64** | 6.1 | 5.10 | N | +For example, a snapshot taken on a m6i.metal host running a 5.10 host kernel can +be restored on a different m6i.metal host running a 6.1 host kernel (but not +vice versa), but could not be restored on a c5n.metal host. diff --git a/src/clippy-tracing/Cargo.toml b/src/clippy-tracing/Cargo.toml index 4539472c68f..69fa3a24fce 100644 --- a/src/clippy-tracing/Cargo.toml +++ b/src/clippy-tracing/Cargo.toml @@ -14,7 +14,7 @@ clap = { version = "4.5.27", features = ["derive"] } itertools = "0.14.0" proc-macro2 = { version = "1.0.93", features = ["span-locations"] } quote = "1.0.38" -syn = { version = "2.0.96", features = ["full", "extra-traits", "visit", "visit-mut", "printing"] } +syn = { version = "2.0.98", features = ["full", "extra-traits", "visit", "visit-mut", "printing"] } walkdir = "2.5.0" [dev-dependencies] diff --git a/src/cpu-template-helper/Cargo.toml b/src/cpu-template-helper/Cargo.toml index ad6d370aafc..fc88b3c122f 100644 --- a/src/cpu-template-helper/Cargo.toml +++ b/src/cpu-template-helper/Cargo.toml @@ -15,7 +15,7 @@ displaydoc = "0.2.5" libc = "0.2.169" log-instrument = { path = "../log-instrument", optional = true } serde = { version = "1.0.217", features = ["derive"] } -serde_json = "1.0.137" +serde_json = "1.0.138" thiserror = "2.0.11" vmm = { path = "../vmm" } diff --git a/src/firecracker/Cargo.toml b/src/firecracker/Cargo.toml index cdb89d174d3..43ecc1e9dbe 100644 --- a/src/firecracker/Cargo.toml +++ b/src/firecracker/Cargo.toml @@ -24,7 +24,7 @@ micro_http = { git = "https://github.com/firecracker-microvm/micro-http" } serde = { version = "1.0.217", features = ["derive"] } serde_derive = "1.0.136" -serde_json = "1.0.137" +serde_json = "1.0.138" thiserror = "2.0.11" timerfd = "1.6.0" utils = { path = "../utils" } @@ -43,7 +43,7 @@ userfaultfd = "0.8.1" [build-dependencies] seccompiler = { path = "../seccompiler" } serde = { version = "1.0.217" } -serde_json = "1.0.137" +serde_json = "1.0.138" [features] tracing = ["log-instrument", "utils/tracing", "vmm/tracing"] diff --git a/src/log-instrument-macros/Cargo.toml b/src/log-instrument-macros/Cargo.toml index 471b4b66159..3126679cfba 100644 --- a/src/log-instrument-macros/Cargo.toml +++ b/src/log-instrument-macros/Cargo.toml @@ -13,7 +13,7 @@ bench = false [dependencies] proc-macro2 = "1.0.93" quote = "1.0.38" -syn = { version = "2.0.96", features = ["full", "extra-traits"] } +syn = { version = "2.0.98", features = ["full", "extra-traits"] } [lints] workspace = true diff --git a/src/seccompiler/Cargo.toml b/src/seccompiler/Cargo.toml index 86c8f2e4177..8e465ce3563 100644 --- a/src/seccompiler/Cargo.toml +++ b/src/seccompiler/Cargo.toml @@ -21,7 +21,7 @@ clap = { version = "4.5.27", features = ["derive", "string"] } displaydoc = "0.2.5" libc = "0.2.169" serde = { version = "1.0.217", features = ["derive"] } -serde_json = "1.0.137" +serde_json = "1.0.138" thiserror = "2.0.11" zerocopy = { version = "0.8.14" } diff --git a/src/vmm/Cargo.toml b/src/vmm/Cargo.toml index 4bbb146ca18..0c15b57ef12 100644 --- a/src/vmm/Cargo.toml +++ b/src/vmm/Cargo.toml @@ -33,7 +33,7 @@ micro_http = { git = "https://github.com/firecracker-microvm/micro-http" } semver = { version = "1.0.25", features = ["serde"] } serde = { version = "1.0.217", features = ["derive", "rc"] } -serde_json = "1.0.137" +serde_json = "1.0.138" slab = "0.4.7" thiserror = "2.0.11" timerfd = "1.5.0" diff --git a/src/vmm/src/devices/virtio/block/virtio/device.rs b/src/vmm/src/devices/virtio/block/virtio/device.rs index fd352fe2539..5854fd8598f 100644 --- a/src/vmm/src/devices/virtio/block/virtio/device.rs +++ b/src/vmm/src/devices/virtio/block/virtio/device.rs @@ -8,21 +8,19 @@ use std::cmp; use std::convert::From; use std::fs::{File, OpenOptions}; -use std::io::{Seek, SeekFrom, Write}; +use std::io::{Seek, SeekFrom}; use std::os::linux::fs::MetadataExt; use std::path::PathBuf; use std::sync::Arc; use block_io::FileEngine; use serde::{Deserialize, Serialize}; +use vm_memory::ByteValued; use vmm_sys_util::eventfd::EventFd; use super::io::async_io; use super::request::*; -use super::{ - io as block_io, VirtioBlockError, BLOCK_CONFIG_SPACE_SIZE, BLOCK_QUEUE_SIZES, SECTOR_SHIFT, - SECTOR_SIZE, -}; +use super::{io as block_io, VirtioBlockError, BLOCK_QUEUE_SIZES, SECTOR_SHIFT, SECTOR_SIZE}; use crate::devices::virtio::block::virtio::metrics::{BlockDeviceMetrics, BlockMetricsPerDevice}; use crate::devices::virtio::block::CacheType; use crate::devices::virtio::device::{DeviceState, IrqTrigger, IrqType, VirtioDevice}; @@ -155,20 +153,17 @@ impl DiskProperties { } default_id } +} - /// Provides vec containing the virtio block configuration space - /// buffer. The config space is populated with the disk size based - /// on the backing file size. - pub fn virtio_block_config_space(&self) -> Vec { - // The config space is little endian. - let mut config = Vec::with_capacity(BLOCK_CONFIG_SPACE_SIZE); - for i in 0..BLOCK_CONFIG_SPACE_SIZE { - config.push(((self.nsectors >> (8 * i)) & 0xff) as u8); - } - config - } +#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)] +#[repr(C)] +pub struct ConfigSpace { + pub capacity: u64, } +// SAFETY: `ConfigSpace` contains only PODs in `repr(C)` or `repr(transparent)`, without padding. +unsafe impl ByteValued for ConfigSpace {} + /// Use this structure to set up the Block Device before booting the kernel. #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)] #[serde(deny_unknown_fields)] @@ -246,7 +241,7 @@ pub struct VirtioBlock { // Virtio fields. pub avail_features: u64, pub acked_features: u64, - pub config_space: Vec, + pub config_space: ConfigSpace, pub activate_evt: EventFd, // Transport related fields. @@ -313,10 +308,14 @@ impl VirtioBlock { let queues = BLOCK_QUEUE_SIZES.iter().map(|&s| Queue::new(s)).collect(); + let config_space = ConfigSpace { + capacity: disk_properties.nsectors.to_le(), + }; + Ok(VirtioBlock { avail_features, acked_features: 0u64, - config_space: disk_properties.virtio_block_config_space(), + config_space, activate_evt: EventFd::new(libc::EFD_NONBLOCK).map_err(VirtioBlockError::EventFd)?, queues, @@ -524,7 +523,7 @@ impl VirtioBlock { /// Update the backing file and the config space of the block device. pub fn update_disk_image(&mut self, disk_image_path: String) -> Result<(), VirtioBlockError> { self.disk.update(disk_image_path, self.read_only)?; - self.config_space = self.disk.virtio_block_config_space(); + self.config_space.capacity = self.disk.nsectors.to_le(); // virtio_block_config_space(); // Kick the driver to pick up the changes. self.irq_trigger.trigger_irq(IrqType::Config).unwrap(); @@ -598,28 +597,23 @@ impl VirtioDevice for VirtioBlock { &self.irq_trigger } - fn read_config(&self, offset: u64, mut data: &mut [u8]) { - let config_len = self.config_space.len() as u64; - if offset >= config_len { + fn read_config(&self, offset: u64, data: &mut [u8]) { + if let Some(config_space_bytes) = self.config_space.as_slice().get(u64_to_usize(offset)..) { + let len = config_space_bytes.len().min(data.len()); + data[..len].copy_from_slice(&config_space_bytes[..len]); + } else { error!("Failed to read config space"); self.metrics.cfg_fails.inc(); - return; - } - if let Some(end) = offset.checked_add(data.len() as u64) { - // This write can't fail, offset and end are checked against config_len. - data.write_all( - &self.config_space[u64_to_usize(offset)..u64_to_usize(cmp::min(end, config_len))], - ) - .unwrap(); } } fn write_config(&mut self, offset: u64, data: &[u8]) { + let config_space_bytes = self.config_space.as_mut_slice(); let start = usize::try_from(offset).ok(); let end = start.and_then(|s| s.checked_add(data.len())); let Some(dst) = start .zip(end) - .and_then(|(start, end)| self.config_space.get_mut(start..end)) + .and_then(|(start, end)| config_space_bytes.get_mut(start..end)) else { error!("Failed to write config space"); self.metrics.cfg_fails.inc(); @@ -673,7 +667,7 @@ impl Drop for VirtioBlock { #[cfg(test)] mod tests { use std::fs::metadata; - use std::io::Read; + use std::io::{Read, Write}; use std::os::unix::ffi::OsStrExt; use std::thread; use std::time::Duration; @@ -755,11 +749,6 @@ mod tests { assert_eq!(size, u64::from(SECTOR_SIZE) * num_sectors); assert_eq!(disk_properties.nsectors, num_sectors); - let cfg = disk_properties.virtio_block_config_space(); - assert_eq!(cfg.len(), BLOCK_CONFIG_SPACE_SIZE); - for (i, byte) in cfg.iter().enumerate() { - assert_eq!(*byte, ((num_sectors >> (8 * i)) & 0xff) as u8); - } // Testing `backing_file.virtio_block_disk_image_id()` implies // duplicating that logic in tests, so skipping it. @@ -803,20 +792,21 @@ mod tests { for engine in [FileEngineType::Sync, FileEngineType::Async] { let block = default_block(engine); - let mut actual_config_space = [0u8; BLOCK_CONFIG_SPACE_SIZE]; - block.read_config(0, &mut actual_config_space); + let mut actual_config_space = ConfigSpace::default(); + block.read_config(0, actual_config_space.as_mut_slice()); // This will read the number of sectors. // The block's backing file size is 0x1000, so there are 8 (4096/512) sectors. // The config space is little endian. - let expected_config_space: [u8; BLOCK_CONFIG_SPACE_SIZE] = - [0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; + let expected_config_space = ConfigSpace { capacity: 8 }; assert_eq!(actual_config_space, expected_config_space); // Invalid read. - let expected_config_space: [u8; BLOCK_CONFIG_SPACE_SIZE] = - [0xd, 0xe, 0xa, 0xd, 0xb, 0xe, 0xe, 0xf]; + let expected_config_space = ConfigSpace { capacity: 696969 }; actual_config_space = expected_config_space; - block.read_config(BLOCK_CONFIG_SPACE_SIZE as u64 + 1, &mut actual_config_space); + block.read_config( + std::mem::size_of::() as u64 + 1, + actual_config_space.as_mut_slice(), + ); // Validate read failed (the config space was not updated). assert_eq!(actual_config_space, expected_config_space); @@ -828,33 +818,37 @@ mod tests { for engine in [FileEngineType::Sync, FileEngineType::Async] { let mut block = default_block(engine); - let expected_config_space: [u8; BLOCK_CONFIG_SPACE_SIZE] = - [0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - block.write_config(0, &expected_config_space); + let expected_config_space = ConfigSpace { capacity: 696969 }; + block.write_config(0, expected_config_space.as_slice()); - let mut actual_config_space = [0u8; BLOCK_CONFIG_SPACE_SIZE]; - block.read_config(0, &mut actual_config_space); + let mut actual_config_space = ConfigSpace::default(); + block.read_config(0, actual_config_space.as_mut_slice()); assert_eq!(actual_config_space, expected_config_space); // If priviledged user writes to `/dev/mem`, in block config space - byte by byte. - let expected_config_space = [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x00, 0x11]; - for i in 0..expected_config_space.len() { - block.write_config(i as u64, &expected_config_space[i..=i]); + let expected_config_space = ConfigSpace { + capacity: 0x1122334455667788, + }; + let expected_config_space_slice = expected_config_space.as_slice(); + for (i, b) in expected_config_space_slice.iter().enumerate() { + block.write_config(i as u64, &[*b]); } - block.read_config(0, &mut actual_config_space); + block.read_config(0, actual_config_space.as_mut_slice()); assert_eq!(actual_config_space, expected_config_space); // Invalid write. - let new_config_space = [0xd, 0xe, 0xa, 0xd, 0xb, 0xe, 0xe, 0xf]; - block.write_config(5, &new_config_space); + let new_config_space = ConfigSpace { + capacity: 0xDEADBEEF, + }; + block.write_config(5, new_config_space.as_slice()); // Make sure nothing got written. - block.read_config(0, &mut actual_config_space); + block.read_config(0, actual_config_space.as_mut_slice()); assert_eq!(actual_config_space, expected_config_space); // Large offset that may cause an overflow. - block.write_config(u64::MAX, &new_config_space); + block.write_config(u64::MAX, new_config_space.as_slice()); // Make sure nothing got written. - block.read_config(0, &mut actual_config_space); + block.read_config(0, actual_config_space.as_mut_slice()); assert_eq!(actual_config_space, expected_config_space); } } diff --git a/src/vmm/src/devices/virtio/block/virtio/mod.rs b/src/vmm/src/devices/virtio/block/virtio/mod.rs index 8a2045f19e5..8ea59a5aba4 100644 --- a/src/vmm/src/devices/virtio/block/virtio/mod.rs +++ b/src/vmm/src/devices/virtio/block/virtio/mod.rs @@ -18,8 +18,6 @@ pub use self::request::*; pub use crate::devices::virtio::block::CacheType; use crate::devices::virtio::queue::FIRECRACKER_MAX_QUEUE_SIZE; -/// Size of config space for block device. -pub const BLOCK_CONFIG_SPACE_SIZE: usize = 8; /// Sector shift for block device. pub const SECTOR_SHIFT: u8 = 9; /// Size of block sector. diff --git a/src/vmm/src/devices/virtio/block/virtio/persist.rs b/src/vmm/src/devices/virtio/block/virtio/persist.rs index 61bffbeaa40..caab2c13a5f 100644 --- a/src/vmm/src/devices/virtio/block/virtio/persist.rs +++ b/src/vmm/src/devices/virtio/block/virtio/persist.rs @@ -6,6 +6,7 @@ use std::sync::atomic::AtomicU32; use std::sync::Arc; +use device::ConfigSpace; use serde::{Deserialize, Serialize}; use vmm_sys_util::eventfd::EventFd; @@ -122,10 +123,14 @@ impl Persist<'_> for VirtioBlock { DeviceState::Inactive }; + let config_space = ConfigSpace { + capacity: disk_properties.nsectors.to_le(), + }; + Ok(VirtioBlock { avail_features, acked_features, - config_space: disk_properties.virtio_block_config_space(), + config_space, activate_evt: EventFd::new(libc::EFD_NONBLOCK).map_err(VirtioBlockError::EventFd)?, queues, diff --git a/src/vmm/src/resources.rs b/src/vmm/src/resources.rs index d6c5fb31a5a..024f8833b78 100644 --- a/src/vmm/src/resources.rs +++ b/src/vmm/src/resources.rs @@ -63,29 +63,20 @@ pub enum ResourcesError { /// Used for configuring a vmm from one single json passed to the Firecracker process. #[derive(Debug, Default, PartialEq, Eq, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] pub struct VmmConfig { - #[serde(rename = "balloon")] - balloon_device: Option, - #[serde(rename = "drives")] - block_devices: Vec, - #[serde(rename = "boot-source")] + balloon: Option, + drives: Vec, boot_source: BootSourceConfig, - #[serde(rename = "cpu-config")] cpu_config: Option, - #[serde(rename = "logger")] logger: Option, - #[serde(rename = "machine-config")] machine_config: Option, - #[serde(rename = "metrics")] metrics: Option, - #[serde(rename = "mmds-config")] mmds_config: Option, - #[serde(rename = "network-interfaces", default)] - net_devices: Vec, - #[serde(rename = "vsock")] - vsock_device: Option, - #[serde(rename = "entropy")] - entropy_device: Option, + #[serde(default)] + network_interfaces: Vec, + vsock: Option, + entropy: Option, } /// A data structure that encapsulates the device configurations @@ -152,19 +143,19 @@ impl VmResources { resources.build_boot_source(vmm_config.boot_source)?; - for drive_config in vmm_config.block_devices.into_iter() { + for drive_config in vmm_config.drives.into_iter() { resources.set_block_device(drive_config)?; } - for net_config in vmm_config.net_devices.into_iter() { + for net_config in vmm_config.network_interfaces.into_iter() { resources.build_net_device(net_config)?; } - if let Some(vsock_config) = vmm_config.vsock_device { + if let Some(vsock_config) = vmm_config.vsock { resources.set_vsock_device(vsock_config)?; } - if let Some(balloon_config) = vmm_config.balloon_device { + if let Some(balloon_config) = vmm_config.balloon { resources.set_balloon_device(balloon_config)?; } @@ -180,7 +171,7 @@ impl VmResources { resources.set_mmds_config(mmds_config, &instance_info.id)?; } - if let Some(entropy_device_config) = vmm_config.entropy_device { + if let Some(entropy_device_config) = vmm_config.entropy { resources.build_entropy_device(entropy_device_config)?; } @@ -484,17 +475,17 @@ impl VmResources { impl From<&VmResources> for VmmConfig { fn from(resources: &VmResources) -> Self { VmmConfig { - balloon_device: resources.balloon.get_config().ok(), - block_devices: resources.block.configs(), + balloon: resources.balloon.get_config().ok(), + drives: resources.block.configs(), boot_source: resources.boot_source.config.clone(), cpu_config: None, logger: None, machine_config: Some(resources.machine_config.clone()), metrics: None, mmds_config: resources.mmds_config(), - net_devices: resources.net_builder.configs(), - vsock_device: resources.vsock.config(), - entropy_device: resources.entropy.config(), + network_interfaces: resources.net_builder.configs(), + vsock: resources.vsock.config(), + entropy: resources.entropy.config(), } } } diff --git a/src/vmm/src/vstate/memory.rs b/src/vmm/src/vstate/memory.rs index 9579e67c09f..5585c51cc9e 100644 --- a/src/vmm/src/vstate/memory.rs +++ b/src/vmm/src/vstate/memory.rs @@ -7,6 +7,7 @@ use std::fs::File; use std::io::SeekFrom; +use std::sync::Arc; use libc::c_int; use serde::{Deserialize, Serialize}; @@ -35,8 +36,6 @@ pub type GuestMmapRegion = vm_memory::MmapRegion>; /// Errors associated with dumping guest memory to file. #[derive(Debug, thiserror::Error, displaydoc::Display)] pub enum MemoryError { - /// Cannot access file: {0} - FileError(std::io::Error), /// Cannot create memory: {0} CreateMemory(VmMemoryError), /// Cannot create memory region: {0} @@ -178,6 +177,7 @@ impl GuestMemoryExtension for GuestMemoryMmap { track_dirty_pages: bool, ) -> Result { let mut offset = 0; + let file = file.map(Arc::new); let regions = regions .map(|(start, size)| { let mut builder = MmapRegionBuilder::new_with_bitmap( @@ -188,8 +188,7 @@ impl GuestMemoryExtension for GuestMemoryMmap { .with_mmap_flags(libc::MAP_NORESERVE | mmap_flags); if let Some(ref file) = file { - let file_offset = - FileOffset::new(file.try_clone().map_err(MemoryError::FileError)?, offset); + let file_offset = FileOffset::from_arc(Arc::clone(file), offset); builder = builder.with_file_offset(file_offset); } diff --git a/tests/integration_tests/functional/test_pause_resume.py b/tests/integration_tests/functional/test_pause_resume.py index 34b9a9a7229..ca2bb6936b3 100644 --- a/tests/integration_tests/functional/test_pause_resume.py +++ b/tests/integration_tests/functional/test_pause_resume.py @@ -141,7 +141,12 @@ def test_kvmclock_ctrl(uvm_plain_any): microvm = uvm_plain_any microvm.help.enable_console() microvm.spawn() - microvm.basic_config() + + # With 2 vCPUs under certain conditions soft lockup warnings can rarely be in dmesg causing this test to fail. + # Example of the warning: `watchdog: BUG: soft lockup - CPU#0 stuck for (x)s! [(udev-worker):758]` + # With 1 vCPU this intermittent issue doesn't occur. If the KVM_CLOCK_CTRL IOCTL is not made + # the test will fail with 1 vCPU, so we can assert the call to the IOCTL is made. + microvm.basic_config(vcpu_count=1) microvm.add_net_iface() microvm.start() diff --git a/tools/ab_test.py b/tools/ab_test.py index 2d03d9591a1..7349adcb862 100755 --- a/tools/ab_test.py +++ b/tools/ab_test.py @@ -44,13 +44,6 @@ IGNORED = [ # Network throughput on m6a.metal {"instance": "m6a.metal", "performance_test": "test_network_tcp_throughput"}, - # Block throughput for 1 vcpu on m6g.metal/5.10 - { - "performance_test": "test_block_performance", - "instance": "m6g.metal", - "host_kernel": "linux-5.10", - "vcpus": "1", - }, ]