disk: add try_clone method to DiskFile trait
Introduce `try_clone` method to `DiskFile` trait. This allows callers to
create DiskFile instances which share the same underlying file
descriptors, which enables you to manipulate them in multiple threads in
parallel. virtio-blk requires this change to run multiple worker threads
in parallel.
Note `try_clone` is introduced as a method of `DiskFile`, not as a
standalone `TryClone`, since such `TryClone` trait is not an object-safe
and thus cannot be defined actually.
BUG=b:267716786
TEST=build passes
Change-Id: I8aae4ee08992de2649b7157b8dfe7328751208b5
Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/4281742
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Reviewed-by: Keiichi Watanabe <keiichiw@chromium.org>
Commit-Queue: Takaya Saeki <takayas@chromium.org>
diff --git a/disk/src/android_sparse.rs b/disk/src/android_sparse.rs
index 5511b97..9e00612 100644
--- a/disk/src/android_sparse.rs
+++ b/disk/src/android_sparse.rs
@@ -308,6 +308,9 @@
}
}
+// TODO(b/271381851): implement `try_clone`. It allows virtio-blk to run multiple workers.
+impl DiskFile for AndroidSparse {}
+
/// An Android Sparse disk that implements `AsyncDisk` for access.
pub struct AsyncAndroidSparse {
inner: Box<dyn IoSourceExt<File>>,
diff --git a/disk/src/composite.rs b/disk/src/composite.rs
index a70cafc..704d558 100644
--- a/disk/src/composite.rs
+++ b/disk/src/composite.rs
@@ -142,6 +142,9 @@
component_disks: Vec<ComponentDiskPart>,
}
+// TODO(b/271381851): implement `try_clone`. It allows virtio-blk to run multiple workers.
+impl DiskFile for CompositeDiskFile {}
+
fn ranges_overlap(a: &Range<u64>, b: &Range<u64>) -> bool {
range_intersection(a, b).is_some()
}
diff --git a/disk/src/disk.rs b/disk/src/disk.rs
index 481ddfe..249a55c 100644
--- a/disk/src/disk.rs
+++ b/disk/src/disk.rs
@@ -163,17 +163,18 @@
pub trait DiskFile:
FileSetLen + DiskGetLen + FileReadWriteAtVolatile + ToAsyncDisk + Send + AsRawDescriptors + Debug
{
-}
-impl<
- D: FileSetLen
- + DiskGetLen
- + FileReadWriteAtVolatile
- + ToAsyncDisk
- + Send
- + AsRawDescriptors
- + Debug,
- > DiskFile for D
-{
+ /// Creates a new DiskFile instance that shares the same underlying disk file image. IO
+ /// operations to a DiskFile should affect all DiskFile instances with the same underlying disk
+ /// file image.
+ ///
+ /// `try_clone()` returns [`io::ErrorKind::Unsupported`] Error if a DiskFile does not support
+ /// creating an instance with the same underlying disk file image.
+ fn try_clone(&self) -> io::Result<Box<dyn DiskFile>> {
+ Err(io::Error::new(
+ io::ErrorKind::Unsupported,
+ "unsupported operation",
+ ))
+ }
}
/// A `DiskFile` that can be converted for asychronous access.
@@ -260,6 +261,12 @@
Ok(ImageType::Raw)
}
+impl DiskFile for File {
+ fn try_clone(&self) -> io::Result<Box<dyn DiskFile>> {
+ Ok(Box::new(self.try_clone()?))
+ }
+}
+
/// Inspect the image file type and create an appropriate disk file to match it.
pub fn create_disk_file(
raw_image: File,
diff --git a/disk/src/qcow/mod.rs b/disk/src/qcow/mod.rs
index 7b8d763..db09f30 100644
--- a/disk/src/qcow/mod.rs
+++ b/disk/src/qcow/mod.rs
@@ -426,6 +426,8 @@
backing_file: Option<Box<dyn DiskFile>>,
}
+impl DiskFile for QcowFile {}
+
impl QcowFile {
/// Creates a QcowFile from `file`. File must be a valid qcow2 image.
pub fn from(mut file: File, max_nesting_depth: u32) -> Result<QcowFile> {