Add method to create empty writable partition.
For now this is just a sparse file to be used as raw image, but in
future it will be a QCOW2 image.
Bug: 190503448
Test: vm create-partition /data/local/tmp/blah 1000000
Change-Id: Ic07cd96b1a05bfaade1fa48d75d1ed3167d32795
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl
index 7974e71..311c2e0 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl
@@ -27,6 +27,9 @@
IVirtualMachine startVm(
in VirtualMachineConfig config, in @nullable ParcelFileDescriptor logFd);
+ /** Initialise an empty partition image of the given size to be used as a writable partition. */
+ void initializeWritablePartition(in ParcelFileDescriptor imageFd, long size);
+
/**
* Get a list of all currently running VMs. This method is only intended for debug purposes,
* and as such is only permitted from the shell user.
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index c295388..7b63917 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -30,7 +30,9 @@
};
use command_fds::FdMapping;
use log::{debug, error, warn};
+use std::convert::TryInto;
use std::fs::{File, create_dir};
+use std::io::{Seek, SeekFrom, Write};
use std::os::unix::io::AsRawFd;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex, Weak};
@@ -131,6 +133,36 @@
Ok(VirtualMachine::create(instance))
}
+ /// Initialise an empty partition image of the given size to be used as a writable partition.
+ fn initializeWritablePartition(
+ &self,
+ image_fd: &ParcelFileDescriptor,
+ size: i64,
+ ) -> binder::Result<()> {
+ let size: u64 = size.try_into().map_err(|e| {
+ error!("Invalid size {}: {}", size, e);
+ StatusCode::BAD_VALUE
+ })?;
+ let mut image = clone_file(image_fd)?;
+
+ // TODO: create a QCOW2 image instead, like `crosvm create_qcow2`, once `mk_cdisk` supports
+ // it (b/189211641).
+ if size > 0 {
+ // Extend the file to the given size by seeking to the size we want and writing a single
+ // 0 byte there.
+ image.seek(SeekFrom::Start(size - 1)).map_err(|e| {
+ error!("Failed to seek to desired size of image file ({}): {}.", size, e);
+ StatusCode::UNKNOWN_ERROR
+ })?;
+ image.write_all(&[0]).map_err(|e| {
+ error!("Failed to write 0 to image file: {}.", e);
+ StatusCode::UNKNOWN_ERROR
+ })?;
+ }
+
+ Ok(())
+ }
+
/// Get a list of all currently running VMs. This method is only intended for debug purposes,
/// and as such is only permitted from the shell user.
fn debugListVms(&self) -> binder::Result<Vec<VirtualMachineDebugInfo>> {
diff --git a/vm/src/main.rs b/vm/src/main.rs
index bdb574c..e2c11a8 100644
--- a/vm/src/main.rs
+++ b/vm/src/main.rs
@@ -19,10 +19,12 @@
mod sync;
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::IVirtualizationService::IVirtualizationService;
-use android_system_virtualizationservice::binder::{wait_for_interface, ProcessState, Strong};
+use android_system_virtualizationservice::binder::{wait_for_interface, ProcessState, Strong, ParcelFileDescriptor};
use anyhow::{Context, Error};
use run::command_run;
-use std::path::PathBuf;
+use std::convert::TryInto;
+use std::fs::OpenOptions;
+use std::path::{PathBuf, Path};
use structopt::clap::AppSettings;
use structopt::StructOpt;
@@ -49,6 +51,15 @@
},
/// List running virtual machines
List,
+ /// Create a new empty partition to be used as a writable partition for a VM
+ CreatePartition {
+ /// Path at which to create the image file
+ #[structopt(parse(from_os_str))]
+ path: PathBuf,
+
+ /// The desired size of the partition, in bytes.
+ size: u64,
+ },
}
fn main() -> Result<(), Error> {
@@ -65,6 +76,7 @@
Opt::Run { config, daemonize } => command_run(service, &config, daemonize),
Opt::Stop { cid } => command_stop(service, cid),
Opt::List => command_list(service),
+ Opt::CreatePartition { path, size } => command_create_partition(service, &path, size),
}
}
@@ -83,3 +95,20 @@
println!("Running VMs: {:#?}", vms);
Ok(())
}
+
+/// Initialise an empty partition image of the given size to be used as a writable partition.
+fn command_create_partition(
+ service: Strong<dyn IVirtualizationService>,
+ image_path: &Path,
+ size: u64,
+) -> Result<(), Error> {
+ let image = OpenOptions::new()
+ .create_new(true)
+ .write(true)
+ .open(image_path)
+ .with_context(|| format!("Failed to create {:?}", image_path))?;
+ service
+ .initializeWritablePartition(&ParcelFileDescriptor::new(image), size.try_into()?)
+ .context("Failed to initialize partition with size {}, size")?;
+ Ok(())
+}