mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2024-11-24 12:34:31 +00:00
qcow: Turn QCOW support into a feature
This change allows to turn off support for QCOW. This is useful for projects that do not need/want it. A follow-up change (if this one is merged) will do the same for Android sparse disk images. BUG=none TEST=./tools/presubmit Change-Id: I69083c4c2e21d504db89eff47f4c86c6f61d67e9 Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/3864926 Tested-by: Christian Blichmann <cblichmann@google.com> Reviewed-by: Daniel Verkamp <dverkamp@chromium.org> Commit-Queue: Christian Blichmann <cblichmann@google.com>
This commit is contained in:
parent
9dc9210d3d
commit
8847de2725
7 changed files with 56 additions and 28 deletions
|
@ -125,7 +125,7 @@ balloon = ["devices/balloon", "vm_control/balloon"]
|
|||
chromeos = ["base/chromeos", "audio_cras", "devices/chromeos"]
|
||||
composite-disk = ["protos/composite-disk", "protobuf", "disk/composite-disk"]
|
||||
crash-report = []
|
||||
default = ["audio", "balloon", "gpu", "usb"]
|
||||
default = ["audio", "balloon", "gpu", "qcow", "usb"]
|
||||
default-no-sandbox = []
|
||||
direct = ["balloon", "devices/direct", "arch/direct", "x86_64/direct"]
|
||||
ffmpeg = ["devices/ffmpeg"]
|
||||
|
@ -147,6 +147,7 @@ linux-aarch64 = ["all-linux"]
|
|||
plugin = ["protos/plugin", "crosvm_plugin", "kvm", "kvm_sys", "protobuf"]
|
||||
plugin-render-server = []
|
||||
power-monitor-powerd = ["arch/power-monitor-powerd"]
|
||||
qcow = ["disk/qcow"]
|
||||
slirp = ["devices/slirp"]
|
||||
tpm = ["devices/tpm"]
|
||||
usb = ["devices/usb"]
|
||||
|
|
|
@ -9,6 +9,7 @@ path = "src/disk.rs"
|
|||
|
||||
[features]
|
||||
composite-disk = ["crc32fast", "protos", "protobuf", "uuid"]
|
||||
qcow = []
|
||||
|
||||
[dependencies]
|
||||
async-trait = "*"
|
||||
|
|
|
@ -32,8 +32,11 @@ use thiserror::Error as ThisError;
|
|||
|
||||
mod asynchronous;
|
||||
pub(crate) use asynchronous::AsyncDiskFileWrapper;
|
||||
#[cfg(feature = "qcow")]
|
||||
mod qcow;
|
||||
#[cfg(feature = "qcow")]
|
||||
pub use qcow::QcowFile;
|
||||
#[cfg(feature = "qcow")]
|
||||
pub use qcow::QCOW_MAGIC;
|
||||
mod sys;
|
||||
|
||||
|
@ -92,6 +95,7 @@ pub enum Error {
|
|||
MaxNestingDepthExceeded,
|
||||
#[error("failure to punch hole: {0}")]
|
||||
PunchHole(io::Error),
|
||||
#[cfg(feature = "qcow")]
|
||||
#[error("failure in qcow: {0}")]
|
||||
QcowError(qcow::Error),
|
||||
#[error("failed to read data: {0}")]
|
||||
|
@ -237,9 +241,11 @@ pub fn detect_image_type(file: &File) -> Result<ImageType> {
|
|||
}
|
||||
|
||||
if let Some(magic4) = magic.data.get(0..4) {
|
||||
#[cfg(feature = "qcow")]
|
||||
if magic4 == QCOW_MAGIC.to_be_bytes() {
|
||||
return Ok(ImageType::Qcow2);
|
||||
} else if magic4 == SPARSE_HEADER_MAGIC.to_le_bytes() {
|
||||
}
|
||||
if magic4 == SPARSE_HEADER_MAGIC.to_le_bytes() {
|
||||
return Ok(ImageType::AndroidSparse);
|
||||
}
|
||||
}
|
||||
|
@ -271,14 +277,18 @@ pub fn create_async_disk_file(raw_image: File) -> Result<Box<dyn ToAsyncDisk>> {
|
|||
pub fn create_disk_file(
|
||||
raw_image: File,
|
||||
is_sparse_file: bool,
|
||||
mut max_nesting_depth: u32,
|
||||
// max_nesting_depth is only used if the composite-disk or qcow features are enabled.
|
||||
#[allow(unused_variables)] mut max_nesting_depth: u32,
|
||||
// image_path is only used if the composite-disk feature is enabled.
|
||||
#[allow(unused_variables)] image_path: &Path,
|
||||
) -> Result<Box<dyn DiskFile>> {
|
||||
if max_nesting_depth == 0 {
|
||||
return Err(Error::MaxNestingDepthExceeded);
|
||||
}
|
||||
max_nesting_depth -= 1;
|
||||
#[allow(unused_assignments)]
|
||||
{
|
||||
max_nesting_depth -= 1;
|
||||
}
|
||||
|
||||
let image_type = detect_image_type(&raw_image)?;
|
||||
Ok(match image_type {
|
||||
|
@ -286,6 +296,7 @@ pub fn create_disk_file(
|
|||
sys::apply_raw_disk_file_options(&raw_image, is_sparse_file)?;
|
||||
Box::new(raw_image) as Box<dyn DiskFile>
|
||||
}
|
||||
#[cfg(feature = "qcow")]
|
||||
ImageType::Qcow2 => {
|
||||
Box::new(QcowFile::from(raw_image, max_nesting_depth).map_err(Error::QcowError)?)
|
||||
as Box<dyn DiskFile>
|
||||
|
@ -303,12 +314,12 @@ pub fn create_disk_file(
|
|||
.map_err(Error::CreateCompositeDisk)?,
|
||||
) as Box<dyn DiskFile>
|
||||
}
|
||||
#[cfg(not(feature = "composite-disk"))]
|
||||
ImageType::CompositeDisk => return Err(Error::UnknownType),
|
||||
ImageType::AndroidSparse => {
|
||||
Box::new(AndroidSparse::from_file(raw_image).map_err(Error::CreateAndroidSparseDisk)?)
|
||||
as Box<dyn DiskFile>
|
||||
}
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => return Err(Error::UnknownType),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -67,6 +67,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "qcow")]
|
||||
fn detect_image_type_qcow2() {
|
||||
let mut t = tempfile::tempfile().unwrap();
|
||||
// Write the qcow2 magic signature. The rest of the header is not filled in, so if
|
||||
|
|
|
@ -13,38 +13,45 @@ use base::flock;
|
|||
use base::FlockOperation;
|
||||
use disk::DiskFile;
|
||||
use disk::ImageType;
|
||||
#[cfg(feature = "qcow")]
|
||||
use disk::QcowFile;
|
||||
use libc::EINVAL;
|
||||
use libc::EIO;
|
||||
use libc::ENOSYS;
|
||||
|
||||
#[no_mangle]
|
||||
#[allow(unused_variables)] // If the qcow feature is disabled, this function becomes an empty stub.
|
||||
pub unsafe extern "C" fn create_qcow_with_size(path: *const c_char, virtual_size: u64) -> c_int {
|
||||
// NULL pointers are checked, but this will access any other invalid pointer passed from C
|
||||
// code. It's the caller's responsibility to pass a valid pointer.
|
||||
if path.is_null() {
|
||||
return -EINVAL;
|
||||
}
|
||||
let c_str = CStr::from_ptr(path);
|
||||
let file_path = match c_str.to_str() {
|
||||
Ok(s) => s,
|
||||
Err(_) => return -EINVAL,
|
||||
};
|
||||
|
||||
let file = match OpenOptions::new()
|
||||
.create(true)
|
||||
.read(true)
|
||||
.write(true)
|
||||
.open(file_path)
|
||||
#[cfg(feature = "qcow")]
|
||||
{
|
||||
Ok(f) => f,
|
||||
Err(_) => return -1,
|
||||
};
|
||||
// NULL pointers are checked, but this will access any other invalid pointer passed from C
|
||||
// code. It's the caller's responsibility to pass a valid pointer.
|
||||
if path.is_null() {
|
||||
return -EINVAL;
|
||||
}
|
||||
let c_str = CStr::from_ptr(path);
|
||||
let file_path = match c_str.to_str() {
|
||||
Ok(s) => s,
|
||||
Err(_) => return -EINVAL,
|
||||
};
|
||||
|
||||
match QcowFile::new(file, virtual_size) {
|
||||
Ok(_) => 0,
|
||||
Err(_) => -1,
|
||||
let file = match OpenOptions::new()
|
||||
.create(true)
|
||||
.read(true)
|
||||
.write(true)
|
||||
.open(file_path)
|
||||
{
|
||||
Ok(f) => f,
|
||||
Err(_) => return -1,
|
||||
};
|
||||
|
||||
match QcowFile::new(file, virtual_size) {
|
||||
Ok(_) => 0,
|
||||
Err(_) => -1,
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "qcow"))]
|
||||
-ENOSYS // Not implemented
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -77,6 +84,7 @@ pub unsafe extern "C" fn expand_disk_image(path: *const c_char, virtual_size: u6
|
|||
|
||||
let disk_image: Box<dyn DiskFile> = match image_type {
|
||||
ImageType::Raw => Box::new(raw_image),
|
||||
#[cfg(feature = "qcow")]
|
||||
ImageType::Qcow2 => match QcowFile::from(raw_image, disk::MAX_NESTING_DEPTH) {
|
||||
Ok(f) => Box::new(f),
|
||||
Err(_) => return -EINVAL,
|
||||
|
|
|
@ -121,6 +121,7 @@ pub enum CrossPlatformCommands {
|
|||
Battery(BatteryCommand),
|
||||
#[cfg(feature = "composite-disk")]
|
||||
CreateComposite(CreateCompositeCommand),
|
||||
#[cfg(feature = "qcow")]
|
||||
CreateQcow2(CreateQcow2Command),
|
||||
Device(DeviceCommand),
|
||||
Disk(DiskCommand),
|
||||
|
@ -198,6 +199,7 @@ pub struct CreateCompositeCommand {
|
|||
pub partitions: Vec<String>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "qcow")]
|
||||
#[derive(FromArgs)]
|
||||
#[argh(subcommand, name = "create_qcow2")]
|
||||
/// Create Qcow2 image given path and size
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
//! Runs a virtual machine
|
||||
|
||||
#[cfg(any(feature = "composite-disk", feature = "qcow"))]
|
||||
use std::fs::OpenOptions;
|
||||
use std::path::Path;
|
||||
|
||||
|
@ -34,6 +35,7 @@ use disk::create_zero_filler;
|
|||
use disk::ImagePartitionType;
|
||||
#[cfg(feature = "composite-disk")]
|
||||
use disk::PartitionInfo;
|
||||
#[cfg(feature = "qcow")]
|
||||
use disk::QcowFile;
|
||||
mod sys;
|
||||
use crosvm::cmdline::Command;
|
||||
|
@ -338,6 +340,7 @@ fn create_composite(cmd: cmdline::CreateCompositeCommand) -> std::result::Result
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "qcow")]
|
||||
fn create_qcow2(cmd: cmdline::CreateQcow2Command) -> std::result::Result<(), ()> {
|
||||
if !(cmd.size.is_some() ^ cmd.backing_file.is_some()) {
|
||||
println!(
|
||||
|
@ -563,6 +566,7 @@ fn crosvm_main() -> Result<CommandStatus> {
|
|||
#[cfg(feature = "composite-disk")]
|
||||
CrossPlatformCommands::CreateComposite(cmd) => create_composite(cmd)
|
||||
.map_err(|_| anyhow!("create_composite subcommand failed")),
|
||||
#[cfg(feature = "qcow")]
|
||||
CrossPlatformCommands::CreateQcow2(cmd) => {
|
||||
create_qcow2(cmd).map_err(|_| anyhow!("create_qcow2 subcommand failed"))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue