diff --git a/Cargo.lock b/Cargo.lock index bda55c605..ec2732936 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -141,6 +141,7 @@ dependencies = [ "thiserror", "versionize", "versionize_derive", + "vhdx", "virtio-bindings", "vm-memory 0.6.0", "vm-virtio", @@ -224,6 +225,15 @@ dependencies = [ "bitflags", ] +[[package]] +name = "crc32c" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "210cdf933e6a81212bfabf90cd8762f471b5922e5f6b709547673ad8e04b9448" +dependencies = [ + "rustc_version", +] + [[package]] name = "crc64" version = "1.0.0" @@ -860,6 +870,15 @@ version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dead70b0b5e03e9c814bcb6b01e03e68f7c57a80aa48c72ec92152ab3e818d49" +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + [[package]] name = "ryu" version = "1.0.5" @@ -880,6 +899,21 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + [[package]] name = "serde" version = "1.0.127" @@ -1058,6 +1092,9 @@ name = "uuid" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom", +] [[package]] name = "vcpkg" @@ -1137,6 +1174,20 @@ dependencies = [ "vmm-sys-util", ] +[[package]] +name = "vhdx" +version = "0.1.0" +dependencies = [ + "byteorder", + "crc32c", + "libc", + "log", + "remain", + "thiserror", + "uuid", + "vmm-sys-util", +] + [[package]] name = "vhost" version = "0.1.0" @@ -1347,6 +1398,7 @@ dependencies = [ "versionize", "versionize_derive", "vfio-ioctls", + "vhdx", "virtio-devices", "vm-allocator", "vm-device", diff --git a/Cargo.toml b/Cargo.toml index 3a884932c..b1bba7340 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -78,6 +78,7 @@ members = [ "qcow", "rate_limiter", "vfio_user", + "vhdx", "vhost_user_backend", "vhost_user_block", "vhost_user_net", diff --git a/block_util/Cargo.toml b/block_util/Cargo.toml index f9145ad72..792752a8f 100644 --- a/block_util/Cargo.toml +++ b/block_util/Cargo.toml @@ -16,6 +16,7 @@ qcow = { path = "../qcow" } thiserror = "1.0.26" versionize = "0.1.6" versionize_derive = "0.1.4" +vhdx = { path = "../vhdx" } virtio-bindings = { version = "0.1.0", features = ["virtio-v5_0_0"] } vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] } vm-virtio = { path = "../vm-virtio" } diff --git a/block_util/src/lib.rs b/block_util/src/lib.rs index 3d2161886..2da33de63 100644 --- a/block_util/src/lib.rs +++ b/block_util/src/lib.rs @@ -18,6 +18,7 @@ pub mod qcow_sync; pub mod raw_async; pub mod raw_sync; pub mod vhd; +pub mod vhdx_sync; use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult, DiskFileError, DiskFileResult}; #[cfg(feature = "io_uring")] @@ -602,9 +603,11 @@ pub enum ImageType { FixedVhd, Qcow2, Raw, + Vhdx, } const QCOW_MAGIC: u32 = 0x5146_49fb; +const VHDX_SIGN: u64 = 0x656C_6966_7864_6876; /// Determine image type through file parsing. pub fn detect_image_type(f: &mut File) -> std::io::Result { @@ -623,6 +626,8 @@ pub fn detect_image_type(f: &mut File) -> std::io::Result { ImageType::Qcow2 } else if vhd::is_fixed_vhd(f)? { ImageType::FixedVhd + } else if u64::from_le_bytes(s.data[0..8].try_into().unwrap()) == VHDX_SIGN { + ImageType::Vhdx } else { ImageType::Raw }; diff --git a/block_util/src/vhdx_sync.rs b/block_util/src/vhdx_sync.rs new file mode 100644 index 000000000..1d36157fa --- /dev/null +++ b/block_util/src/vhdx_sync.rs @@ -0,0 +1,113 @@ +// Copyright © 2021 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 + +use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult}; +use crate::{fsync_sync, read_vectored_sync, write_vectored_sync}; +use std::fs::File; +use std::ops::DerefMut; +use std::sync::{Arc, Mutex}; +use vhdx::vhdx::{Result as VhdxResult, Vhdx}; +use vmm_sys_util::eventfd::EventFd; + +pub struct VhdxDiskSync { + vhdx_file: Arc>, + semaphore: Arc>, +} + +impl VhdxDiskSync { + pub fn new(f: File) -> VhdxResult { + let vhdx = Vhdx::new(f)?; + let vhdx_file = Arc::new(Mutex::new(vhdx)); + + Ok(VhdxDiskSync { + vhdx_file, + semaphore: Arc::new(Mutex::new(())), + }) + } +} + +impl DiskFile for VhdxDiskSync { + fn size(&mut self) -> DiskFileResult { + Ok(self.vhdx_file.lock().unwrap().virtual_disk_size()) + } + + fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult> { + Ok(Box::new( + VhdxSync::new(self.vhdx_file.clone(), self.semaphore.clone()) + .map_err(DiskFileError::NewAsyncIo)?, + ) as Box) + } +} + +pub struct VhdxSync { + vhdx_file: Arc>, + eventfd: EventFd, + completion_list: Vec<(u64, i32)>, + semaphore: Arc>, +} + +impl VhdxSync { + pub fn new(vhdx_file: Arc>, semaphore: Arc>) -> std::io::Result { + Ok(VhdxSync { + vhdx_file, + eventfd: EventFd::new(libc::EFD_NONBLOCK)?, + completion_list: Vec::new(), + semaphore, + }) + } +} + +impl AsyncIo for VhdxSync { + fn notifier(&self) -> &EventFd { + &self.eventfd + } + + fn read_vectored( + &mut self, + offset: libc::off_t, + iovecs: Vec, + user_data: u64, + ) -> AsyncIoResult<()> { + read_vectored_sync( + offset, + iovecs, + user_data, + self.vhdx_file.lock().unwrap().deref_mut(), + &self.eventfd, + &mut self.completion_list, + &mut self.semaphore, + ) + } + + fn write_vectored( + &mut self, + offset: libc::off_t, + iovecs: Vec, + user_data: u64, + ) -> AsyncIoResult<()> { + write_vectored_sync( + offset, + iovecs, + user_data, + self.vhdx_file.lock().unwrap().deref_mut(), + &self.eventfd, + &mut self.completion_list, + &mut self.semaphore, + ) + } + + fn fsync(&mut self, user_data: Option) -> AsyncIoResult<()> { + fsync_sync( + user_data, + self.vhdx_file.lock().unwrap().deref_mut(), + &self.eventfd, + &mut self.completion_list, + &mut self.semaphore, + ) + } + + fn complete(&mut self) -> Vec<(u64, i32)> { + self.completion_list.drain(..).collect() + } +} diff --git a/virtio-devices/src/seccomp_filters.rs b/virtio-devices/src/seccomp_filters.rs index 53e5273d0..fef6bdabf 100644 --- a/virtio-devices/src/seccomp_filters.rs +++ b/virtio-devices/src/seccomp_filters.rs @@ -111,6 +111,7 @@ fn virtio_block_thread_rules() -> Vec<(i64, Vec)> { (libc::SYS_fsync, vec![]), (libc::SYS_ftruncate, vec![]), (libc::SYS_futex, vec![]), + (libc::SYS_getrandom, vec![]), (libc::SYS_io_uring_enter, vec![]), (libc::SYS_lseek, vec![]), (libc::SYS_madvise, vec![]), diff --git a/vmm/Cargo.toml b/vmm/Cargo.toml index 171f7521c..f8b0994cf 100644 --- a/vmm/Cargo.toml +++ b/vmm/Cargo.toml @@ -45,6 +45,7 @@ uuid = "0.8.2" versionize = "0.1.6" versionize_derive = "0.1.4" vfio-ioctls = { git = "https://github.com/rust-vmm/vfio-ioctls", branch = "master", default-features = false } +vhdx = { path = "../vhdx" } virtio-devices = { path = "../virtio-devices" } vm-allocator = { path = "../vm-allocator" } vm-device = { path = "../vm-device" } diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index 00bc2fbd9..99e803dc1 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -39,7 +39,7 @@ use arch::{DeviceType, MmioDeviceInfo}; use block_util::{ async_io::DiskFile, block_io_uring_is_supported, detect_image_type, fixed_vhd_async::FixedVhdDiskAsync, fixed_vhd_sync::FixedVhdDiskSync, qcow_sync::QcowDiskSync, - raw_async::RawFileDisk, raw_sync::RawFileDiskSync, ImageType, + raw_async::RawFileDisk, raw_sync::RawFileDiskSync, vhdx_sync::VhdxDiskSync, ImageType, }; #[cfg(target_arch = "aarch64")] use devices::gic; @@ -420,6 +420,9 @@ pub enum DeviceManagerError { /// Failed to create QcowDiskSync CreateQcowDiskSync(qcow::Error), + /// Failed to create FixedVhdxDiskSync + CreateFixedVhdxDiskSync(vhdx::vhdx::VhdxError), + /// Failed adding DMA mapping handler to virtio-mem device. AddDmaMappingHandlerVirtioMem(virtio_devices::mem::Error), @@ -1944,6 +1947,13 @@ impl DeviceManager { .map_err(DeviceManagerError::CreateQcowDiskSync)?, ) as Box } + ImageType::Vhdx => { + info!("Using synchronous VHDX disk file"); + Box::new( + VhdxDiskSync::new(file) + .map_err(DeviceManagerError::CreateFixedVhdxDiskSync)?, + ) as Box + } }; let dev = Arc::new(Mutex::new(