From 8148b9d49d7fd1dbb07399395cae0552a6da4da8 Mon Sep 17 00:00:00 2001 From: Jake Correnti Date: Wed, 20 Nov 2024 15:11:03 -0500 Subject: [PATCH 1/3] Add imago crate Adds the imago crate which is necessary to allow support for multiple disk image formats. Signed-off-by: Jake Correnti --- Cargo.lock | 132 +++++++++++++++++++++++++++++++++++++++++ src/devices/Cargo.toml | 2 + 2 files changed, 134 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index bb629c8f..547a43fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + [[package]] name = "adler2" version = "2.0.0" @@ -72,6 +81,17 @@ dependencies = [ name = "arch_gen" version = "0.1.0" +[[package]] +name = "async-trait" +version = "0.1.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "atty" version = "0.2.14" @@ -89,6 +109,21 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + [[package]] name = "base64" version = "0.22.1" @@ -316,6 +351,7 @@ dependencies = [ "crossbeam-channel", "env_logger", "hvf", + "imago", "libc", "log", "lru", @@ -509,6 +545,12 @@ dependencies = [ "wasi", ] +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + [[package]] name = "glob" version = "0.3.1" @@ -585,6 +627,25 @@ dependencies = [ "cc", ] +[[package]] +name = "imago" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301cd8e9a7de4545ed7387d5d563f4cc5adbdc44d8e658ffbb548bccb5bfe194" +dependencies = [ + "async-trait", + "bincode", + "futures", + "libc", + "miniz_oxide", + "rustc_version", + "serde", + "tokio", + "tracing", + "vm-memory", + "windows-sys 0.59.0", +] + [[package]] name = "indexmap" version = "2.6.0" @@ -868,6 +929,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "object" +version = "0.36.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.20.2" @@ -1110,12 +1180,27 @@ dependencies = [ "syn", ] +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + [[package]] name = "rustc-hash" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rutabaga_gfx" version = "0.1.2" @@ -1147,6 +1232,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + [[package]] name = "serde" version = "1.0.215" @@ -1335,6 +1426,16 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio" +version = "1.41.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" +dependencies = [ + "backtrace", + "pin-project-lite", +] + [[package]] name = "toml" version = "0.8.19" @@ -1369,6 +1470,37 @@ dependencies = [ "winnow", ] +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + [[package]] name = "unicode-ident" version = "1.0.13" diff --git a/src/devices/Cargo.toml b/src/devices/Cargo.toml index 9508ce1f..7e097f57 100644 --- a/src/devices/Cargo.toml +++ b/src/devices/Cargo.toml @@ -34,6 +34,8 @@ utils = { path = "../utils" } polly = { path = "../polly" } rutabaga_gfx = { path = "../rutabaga_gfx", features = ["virgl_renderer", "virgl_renderer_next"], optional = true } +imago = { version = "0.1.2", features = ["sync-wrappers", "vm-memory"] } + [target.'cfg(target_os = "macos")'.dependencies] hvf = { path = "../hvf" } lru = ">=0.9" From 5176a822af8f05f0adef6ef52ba242ae9b5d7c29 Mon Sep 17 00:00:00 2001 From: Jake Correnti Date: Tue, 19 Nov 2024 10:17:35 -0500 Subject: [PATCH 2/3] Use SyncFormatAccess in DiskProperties Changes the `file` attribute in `DiskProperties` to use `Arc>`. This allows libkrun to take advantage of imago's support for multiple disk image formats. Libkrun now supports the use of Raw or QCOW2 formats for disk images. Implements `FileReadWriteAtVolatile` trait on `DiskProperties` Adds an emum, `ImageType`, that describes the supported disk image variants. Signed-off-by: Jake Correnti --- src/devices/src/virtio/block/device.rs | 63 +++++++++++++++++--------- src/devices/src/virtio/block/mod.rs | 7 +++ src/devices/src/virtio/block/worker.rs | 8 ++-- src/devices/src/virtio/file_traits.rs | 43 ++++++++++++++++++ src/libkrun/src/lib.rs | 5 ++ src/vmm/src/vmm_config/block.rs | 4 +- 6 files changed, 104 insertions(+), 26 deletions(-) diff --git a/src/devices/src/virtio/block/device.rs b/src/devices/src/virtio/block/device.rs index 893e26f3..f8038a51 100644 --- a/src/devices/src/virtio/block/device.rs +++ b/src/devices/src/virtio/block/device.rs @@ -8,7 +8,7 @@ use std::cmp; use std::convert::From; use std::fs::{File, OpenOptions}; -use std::io::{self, Seek, SeekFrom, Write}; +use std::io::{self, Write}; #[cfg(target_os = "linux")] use std::os::linux::fs::MetadataExt; #[cfg(target_os = "macos")] @@ -19,6 +19,9 @@ use std::sync::atomic::AtomicUsize; use std::sync::{Arc, Mutex}; use std::thread::JoinHandle; +use imago::file::File as ImagoFile; +use imago::qcow2::Qcow2; +use imago::SyncFormatAccess; use log::{error, warn}; use utils::eventfd::{EventFd, EFD_NONBLOCK}; use virtio_bindings::{ @@ -33,7 +36,7 @@ use super::{ }; use crate::legacy::Gic; -use crate::virtio::ActivateError; +use crate::virtio::{block::ImageType, ActivateError}; /// Configuration options for disk caching. #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] @@ -51,22 +54,18 @@ pub enum CacheType { /// Helper object for setting up all `Block` fields derived from its backing file. pub(crate) struct DiskProperties { cache_type: CacheType, - pub(crate) file: File, + pub(crate) file: Arc>, nsectors: u64, image_id: Vec, } impl DiskProperties { pub fn new( - disk_image_path: String, - is_disk_read_only: bool, + disk_image: Arc>, + disk_image_id: Vec, cache_type: CacheType, ) -> io::Result { - let mut disk_image = OpenOptions::new() - .read(true) - .write(!is_disk_read_only) - .open(PathBuf::from(&disk_image_path))?; - let disk_size = disk_image.seek(SeekFrom::End(0))?; + let disk_size = disk_image.size(); // We only support disk size, which uses the first two words of the configuration space. // If the image is not a multiple of the sector size, the tail bits are not exposed. @@ -81,13 +80,13 @@ impl DiskProperties { Ok(Self { cache_type, nsectors: disk_size >> SECTOR_SHIFT, - image_id: Self::build_disk_image_id(&disk_image), + image_id: disk_image_id, file: disk_image, }) } - pub fn file_mut(&mut self) -> &mut File { - &mut self.file + pub fn file(&self) -> &SyncFormatAccess { + self.file.as_ref() } pub fn nsectors(&self) -> u64 { @@ -141,7 +140,7 @@ impl Drop for DiskProperties { error!("Failed to flush block data on drop."); } // Sync data out to physical media on host. - if self.file.sync_all().is_err() { + if self.file.sync().is_err() { error!("Failed to sync block data on drop.") } } @@ -168,8 +167,8 @@ pub struct Block { // Host file and properties. disk: Option, cache_type: CacheType, - disk_image_path: String, - is_disk_read_only: bool, + disk_image: Arc>, + disk_image_id: Vec, worker_thread: Option>, worker_stopfd: EventFd, @@ -203,10 +202,32 @@ impl Block { partuuid: Option, cache_type: CacheType, disk_image_path: String, + disk_image_format: ImageType, is_disk_read_only: bool, ) -> io::Result { + let disk_image = OpenOptions::new() + .read(true) + .write(!is_disk_read_only) + .open(PathBuf::from(&disk_image_path))?; + + let disk_image_id = DiskProperties::build_disk_image_id(&disk_image); + + let disk_image = match disk_image_format { + ImageType::Qcow2 => { + let mut qcow_disk_image = + Qcow2::::open_path_sync(disk_image_path, !is_disk_read_only)?; + qcow_disk_image.open_implicit_dependencies_sync()?; + SyncFormatAccess::new(qcow_disk_image)? + } + ImageType::Raw => { + let raw = imago::raw::Raw::open_path_sync(disk_image_path, !is_disk_read_only)?; + SyncFormatAccess::new(raw)? + } + }; + let disk_image = Arc::new(disk_image); + let disk_properties = - DiskProperties::new(disk_image_path.clone(), is_disk_read_only, cache_type)?; + DiskProperties::new(Arc::clone(&disk_image), disk_image_id.clone(), cache_type)?; let mut avail_features = (1u64 << VIRTIO_F_VERSION_1) | (1u64 << VIRTIO_BLK_F_FLUSH) @@ -234,8 +255,8 @@ impl Block { config, disk: Some(disk_properties), cache_type, - disk_image_path, - is_disk_read_only, + disk_image, + disk_image_id, avail_features, acked_features: 0u64, interrupt_status: Arc::new(AtomicUsize::new(0)), @@ -348,8 +369,8 @@ impl VirtioDevice for Block { let disk = match self.disk.take() { Some(d) => d, None => DiskProperties::new( - self.disk_image_path.clone(), - self.is_disk_read_only, + Arc::clone(&self.disk_image), + self.disk_image_id.clone(), self.cache_type, ) .map_err(|_| ActivateError::BadActivate)?, diff --git a/src/devices/src/virtio/block/mod.rs b/src/devices/src/virtio/block/mod.rs index e7f81354..7fe4fb4d 100644 --- a/src/devices/src/virtio/block/mod.rs +++ b/src/devices/src/virtio/block/mod.rs @@ -32,3 +32,10 @@ pub enum Error { /// Guest gave us a write only descriptor that protocol says to read from. UnexpectedWriteOnlyDescriptor, } + +/// Supported disk image formats +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum ImageType { + Raw, + Qcow2, +} diff --git a/src/devices/src/virtio/block/worker.rs b/src/devices/src/virtio/block/worker.rs index 1590ee13..96d14314 100644 --- a/src/devices/src/virtio/block/worker.rs +++ b/src/devices/src/virtio/block/worker.rs @@ -228,7 +228,7 @@ impl BlockWorker { Err(RequestError::InvalidDataLength) } else { writer - .write_from_at(&self.disk.file, data_len, request_header.sector * 512) + .write_from_at(&self.disk, data_len, request_header.sector * 512) .map_err(RequestError::WritingToDescriptor) } } @@ -238,15 +238,15 @@ impl BlockWorker { Err(RequestError::InvalidDataLength) } else { reader - .read_to_at(&self.disk.file, data_len, request_header.sector * 512) + .read_to_at(&self.disk, data_len, request_header.sector * 512) .map_err(RequestError::ReadingFromDescriptor) } } VIRTIO_BLK_T_FLUSH => match self.disk.cache_type() { CacheType::Writeback => { - let diskfile = self.disk.file_mut(); + let diskfile = self.disk.file(); diskfile.flush().map_err(RequestError::FlushingToDisk)?; - diskfile.sync_all().map_err(RequestError::FlushingToDisk)?; + diskfile.sync().map_err(RequestError::FlushingToDisk)?; Ok(0) } CacheType::Unsafe => Ok(0), diff --git a/src/devices/src/virtio/file_traits.rs b/src/devices/src/virtio/file_traits.rs index 00aef854..2e13eb67 100644 --- a/src/devices/src/virtio/file_traits.rs +++ b/src/devices/src/virtio/file_traits.rs @@ -6,11 +6,15 @@ use std::fs::File; use std::io::{Error, ErrorKind, Result}; use std::os::unix::io::AsRawFd; +#[cfg(feature = "blk")] +use imago::io_buffers::{IoVector, IoVectorMut}; use vm_memory::VolatileSlice; use libc::{c_int, c_void, read, readv, size_t, write, writev}; use super::bindings::{off64_t, pread64, preadv64, pwrite64, pwritev64}; +#[cfg(feature = "blk")] +use super::block::device::DiskProperties; /// A trait for setting the size of a file. /// This is equivalent to File's `set_len` method, but @@ -411,3 +415,42 @@ macro_rules! volatile_impl { } volatile_impl!(File); + +#[cfg(feature = "blk")] +impl FileReadWriteAtVolatile for DiskProperties { + fn read_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result { + self.read_vectored_at_volatile(&[slice], offset) + } + + fn read_vectored_at_volatile(&self, bufs: &[VolatileSlice], offset: u64) -> Result { + if bufs.is_empty() { + return Ok(0); + } + + let (iovec, _guard) = IoVectorMut::from_volatile_slice(bufs); + let full_length = iovec + .len() + .try_into() + .map_err(|e| Error::new(ErrorKind::InvalidData, e))?; + self.file().readv(iovec, offset)?; + Ok(full_length) + } + + fn write_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result { + self.write_vectored_at_volatile(&[slice], offset) + } + + fn write_vectored_at_volatile(&self, bufs: &[VolatileSlice], offset: u64) -> Result { + if bufs.is_empty() { + return Ok(0); + } + + let (iovec, _guard) = IoVector::from_volatile_slice(bufs); + let full_length = iovec + .len() + .try_into() + .map_err(|e| Error::new(ErrorKind::InvalidData, e))?; + self.file().writev(iovec, offset)?; + Ok(full_length) + } +} diff --git a/src/libkrun/src/lib.rs b/src/libkrun/src/lib.rs index 77c84d5d..058353fe 100644 --- a/src/libkrun/src/lib.rs +++ b/src/libkrun/src/lib.rs @@ -18,6 +18,8 @@ use std::sync::Mutex; #[cfg(target_os = "macos")] use crossbeam_channel::unbounded; +#[cfg(feature = "blk")] +use devices::virtio::block::ImageType; #[cfg(feature = "net")] use devices::virtio::net::device::VirtioNetBackend; #[cfg(feature = "blk")] @@ -521,6 +523,7 @@ pub unsafe extern "C" fn krun_add_disk( block_id: block_id.to_string(), cache_type: CacheType::Writeback, disk_image_path: disk_path.to_string(), + disk_image_format: ImageType::Raw, is_disk_read_only: read_only, }; cfg.add_block_cfg(block_device_config); @@ -547,6 +550,7 @@ pub unsafe extern "C" fn krun_set_root_disk(ctx_id: u32, c_disk_path: *const c_c block_id: "root".to_string(), cache_type: CacheType::Writeback, disk_image_path: disk_path.to_string(), + disk_image_format: ImageType::Raw, is_disk_read_only: false, }; cfg.set_root_block_cfg(block_device_config); @@ -573,6 +577,7 @@ pub unsafe extern "C" fn krun_set_data_disk(ctx_id: u32, c_disk_path: *const c_c block_id: "data".to_string(), cache_type: CacheType::Writeback, disk_image_path: disk_path.to_string(), + disk_image_format: ImageType::Raw, is_disk_read_only: false, }; cfg.set_data_block_cfg(block_device_config); diff --git a/src/vmm/src/vmm_config/block.rs b/src/vmm/src/vmm_config/block.rs index 81f31184..25bd20da 100644 --- a/src/vmm/src/vmm_config/block.rs +++ b/src/vmm/src/vmm_config/block.rs @@ -2,7 +2,7 @@ use std::collections::VecDeque; use std::fmt; use std::sync::{Arc, Mutex}; -use devices::virtio::{Block, CacheType}; +use devices::virtio::{block::ImageType, Block, CacheType}; #[derive(Debug)] pub enum BlockConfigError { @@ -26,6 +26,7 @@ pub struct BlockDeviceConfig { pub block_id: String, pub cache_type: CacheType, pub disk_image_path: String, + pub disk_image_format: ImageType, pub is_disk_read_only: bool, } @@ -53,6 +54,7 @@ impl BlockBuilder { None, config.cache_type, config.disk_image_path, + config.disk_image_format, config.is_disk_read_only, ) .map_err(BlockConfigError::CreateBlockDevice) From e7a5397719d62f0ac65095249796b590b76dda4b Mon Sep 17 00:00:00 2001 From: Jake Correnti Date: Mon, 18 Nov 2024 22:27:53 -0500 Subject: [PATCH 3/3] Add `krun_add_disk2` API Adds the `krun_add_disk2` API that requires the user to specify the format of the disk image they're providing. The following formats are supported: - KRUN_DISK_FORMAT_RAW - KRUN_DISK_FORMAT_QCOW2 Signed-off-by: Jake Correnti --- include/libkrun.h | 63 ++++++++++++++++++++++++++++++++++++++++-- src/libkrun/src/lib.rs | 47 +++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 3 deletions(-) diff --git a/include/libkrun.h b/include/libkrun.h index 16619aac..7f5ed647 100644 --- a/include/libkrun.h +++ b/include/libkrun.h @@ -95,16 +95,20 @@ int32_t krun_set_root_disk(uint32_t ctx_id, const char *disk_path); int32_t krun_set_data_disk(uint32_t ctx_id, const char *disk_path); /** - * Adds a disk image to be used as a general partition for the microVM. + * Adds a disk image to be used as a general partition for the microVM. The only supported image + * format is "raw". * * This API is mutually exclusive with the deprecated krun_set_root_disk and * krun_set_data_disk methods and must not be used together. * + * This function deliberately only handles images in the Raw format, because it doesn't allow + * specifying an image format, and probing an image's format is dangerous. For more information, + * see the security note on `krun_add_disk2`, which allows opening non-Raw images. + * * Arguments: * "ctx_id" - the configuration context ID. * "block_id" - a null-terminated string representing the partition. - * "disk_path" - a null-terminated string representing the path leading to the disk image that - * contains the root file-system. + * "disk_path" - a null-terminated string representing the path leading to the disk image. * "read_only" - whether the mount should be read-only. Required if the caller does not have * write permissions (for disk images in /usr/share). * @@ -113,6 +117,59 @@ int32_t krun_set_data_disk(uint32_t ctx_id, const char *disk_path); */ int32_t krun_add_disk(uint32_t ctx_id, const char *block_id, const char *disk_path, bool read_only); +/* Supported disk image formats */ +#define KRUN_DISK_FORMAT_RAW 0 +#define KRUN_DISK_FORMAT_QCOW2 1 +/** + * Adds a disk image to be used as a general partition for the microVM. The supported + * image formats are: "raw" and "qcow2". + * + * This API is mutually exclusive with the deprecated krun_set_root_disk and + * krun_set_data_disk methods and must not be used together. + * + * SECURITY NOTE: + * Non-Raw images can reference other files, which libkrun will automatically open, and to which the + * guest will have access. Libkrun should therefore never be asked to open an image in a non-Raw + * format when it doesn't come from a fully trustworthy source. + * + * Consequently, probing an image's format is quite dangerous and to be avoided if at all possible, + * which is why libkrun provides no facilities for doing so. If it's not clear what format an image + * has, it may also not be clear whether it can be trusted to not reference files to which the guest + * shouldn't have access. + * + * If probing absolutely can't be avoided, it must only be done on images that are fully trusted, i.e. + * before a potentially untrusted guest had write access to it. Specifically, consider that a guest has + * full access to all of a Raw image, and can therefore turn it into a file in an arbitrary format, for + * example, into a Qcow2 image, referencing and granting a malicious guest access to arbitrary files. + * To hand a Raw image to an untrusted and potentially malicious guest, and then to re-probe it after + * the guest was able to write to it (when it can no longer be trusted), would therefore be a severe + * security vulnerability. + * + * Therefore, after having probed a yet fully trusted image once, the result must be remembered so the + * image will from then on always be opened in the format that was detected originally. When adhering + * to this, a guest can write anything they want to a Raw image, it's always going to be opened as a + * Raw image, preventing the security vulnerability outlined above. + * + * However, if at all possible, the image format should be explicitly selected based on knowledge + * obtained separately from the pure image data, for example by the user. + * + * Arguments: + * "ctx_id" - the configuration context ID. + * "block_id" - a null-terminated string representing the partition. + * "disk_path" - a null-terminated string representing the path leading to the disk image. + * "disk_format" - the disk image format (i.e. KRUN_DISK_FORMAT_{RAW, QCOW2}) + * "read_only" - whether the mount should be read-only. Required if the caller does not have + * write permissions (for disk images in /usr/share). + * + * Returns: + * Zero on success or a negative error number on failure. + */ +int32_t krun_add_disk2(uint32_t ctx_id, + const char *block_id, + const char *disk_path, + uint32_t disk_format, + bool read_only); + /** * NO LONGER SUPPORTED. DO NOT USE. * diff --git a/src/libkrun/src/lib.rs b/src/libkrun/src/lib.rs index 058353fe..0f864f17 100644 --- a/src/libkrun/src/lib.rs +++ b/src/libkrun/src/lib.rs @@ -534,6 +534,53 @@ pub unsafe extern "C" fn krun_add_disk( KRUN_SUCCESS } +#[allow(clippy::missing_safety_doc)] +#[no_mangle] +#[cfg(feature = "blk")] +pub unsafe extern "C" fn krun_add_disk2( + ctx_id: u32, + c_block_id: *const c_char, + c_disk_path: *const c_char, + disk_format: u32, + read_only: bool, +) -> i32 { + let disk_path = match CStr::from_ptr(c_disk_path).to_str() { + Ok(disk) => disk, + Err(_) => return -libc::EINVAL, + }; + + let block_id = match CStr::from_ptr(c_block_id).to_str() { + Ok(block_id) => block_id, + Err(_) => return -libc::EINVAL, + }; + + let format = match disk_format { + 0 => ImageType::Raw, + 1 => ImageType::Qcow2, + _ => { + // Do not continue if the user cannot specify a valid disk format + return -libc::EINVAL; + } + }; + + match CTX_MAP.lock().unwrap().entry(ctx_id) { + Entry::Occupied(mut ctx_cfg) => { + let cfg = ctx_cfg.get_mut(); + let block_device_config = BlockDeviceConfig { + block_id: block_id.to_string(), + cache_type: CacheType::Writeback, + disk_image_path: disk_path.to_string(), + disk_image_format: format, + is_disk_read_only: read_only, + }; + cfg.add_block_cfg(block_device_config); + } + Entry::Vacant(_) => return -libc::ENOENT, + } + + KRUN_SUCCESS +} + #[allow(clippy::missing_safety_doc)] #[no_mangle] #[cfg(feature = "blk")]