Skip to content

Commit d90bf4e

Browse files
committed
Temporarily vendor imago
The "imago" crate, recently introduce to support qcow2 images with virtio-blk, is not yet packaged in Fedora, so temporarily vendor it to avoid getting the packaging blocked without updates. Signed-off-by: Sergio Lopez <[email protected]>
1 parent 7eb9753 commit d90bf4e

37 files changed

+9539
-6
lines changed

Cargo.lock

Lines changed: 1 addition & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/devices/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ utils = { path = "../utils" }
3434
polly = { path = "../polly" }
3535
rutabaga_gfx = { path = "../rutabaga_gfx", features = ["virgl_renderer", "virgl_renderer_next"], optional = true }
3636

37-
imago = { version = "0.1.2", features = ["sync-wrappers", "vm-memory"] }
37+
imago = { path = "../imago", features = ["sync-wrappers", "vm-memory"] }
3838

3939
[target.'cfg(target_os = "macos")'.dependencies]
4040
hvf = { path = "../hvf" }

src/imago/.cargo_vcs_info.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"git": {
3+
"sha1": "6d4fbca7dd85c4d740261c91f0350d3403cc6ee5"
4+
},
5+
"path_in_vcs": ""
6+
}

src/imago/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/target

src/imago/Cargo.toml

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
2+
#
3+
# When uploading crates to the registry Cargo will automatically
4+
# "normalize" Cargo.toml files for maximal compatibility
5+
# with all versions of Cargo and also rewrite `path` dependencies
6+
# to registry (e.g., crates.io) dependencies.
7+
#
8+
# If you are reading this file be aware that the original Cargo.toml
9+
# will likely look very different (and much more reasonable).
10+
# See Cargo.toml.orig for the original contents.
11+
12+
[package]
13+
edition = "2021"
14+
name = "imago"
15+
version = "0.1.3"
16+
build = "build.rs"
17+
autolib = false
18+
autobins = false
19+
autoexamples = false
20+
autotests = false
21+
autobenches = false
22+
description = "A library for accessing virtual machine disk images."
23+
readme = "README.md"
24+
license = "MIT"
25+
repository = "https://gitlab.com/hreitz/imago"
26+
27+
[package.metadata.docs.rs]
28+
all-features = true
29+
30+
[features]
31+
default = []
32+
sync-wrappers = []
33+
vm-memory = ["dep:vm-memory"]
34+
35+
[lib]
36+
name = "imago"
37+
path = "src/lib.rs"
38+
39+
[dependencies.async-trait]
40+
version = "0.1"
41+
42+
[dependencies.bincode]
43+
version = "1.3"
44+
45+
[dependencies.miniz_oxide]
46+
version = "0.8"
47+
features = ["std"]
48+
49+
[dependencies.serde]
50+
version = "1.0"
51+
features = ["derive"]
52+
53+
[dependencies.tokio]
54+
version = "1"
55+
features = [
56+
"rt",
57+
"sync",
58+
]
59+
60+
[dependencies.tracing]
61+
version = "0.1"
62+
63+
[dependencies.vm-memory]
64+
version = "0.16"
65+
optional = true
66+
67+
[build-dependencies.rustc_version]
68+
version = "0.4.0"
69+
70+
[target."cfg(unix)".dependencies.libc]
71+
version = "0.2"

src/imago/LICENSE

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Copyright (c) 2024 imago contributors
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy
4+
of this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights
6+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
copies of the Software, and to permit persons to whom the Software is
8+
furnished to do so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in all
11+
copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19+
SOFTWARE.

src/imago/README.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Imago
2+
3+
Provides access to VM image formats.
4+
5+
Simple example (requires the `sync-wrappers` feature):
6+
```rust
7+
use imago::file::File;
8+
use imago::qcow2::Qcow2;
9+
use imago::SyncFormatAccess;
10+
use std::fs::OpenOptions;
11+
12+
// Produce read-only qcow2 instance using purely `File` for storage
13+
let mut qcow2 = Qcow2::<File>::open_path_sync("image.qcow2", false)?;
14+
qcow2.open_implicit_dependencies_sync()?;
15+
16+
let qcow2 = SyncFormatAccess::new(qcow2)?;
17+
18+
let mut buf = vec![0u8; 512];
19+
qcow2.read(&mut buf, 0)?;
20+
```
21+
22+
Another example, using the native async interface instead of sync wrapper functions, explicitly
23+
overriding the implicit references contained in qcow2 files, and showcasing using different
24+
types of storage (specifically normal files and null storage):
25+
```rust
26+
use imago::file::File;
27+
use imago::null::Null;
28+
use imago::qcow2::Qcow2;
29+
use imago::raw::Raw;
30+
use imago::{DynStorage, FormatAccess, Storage, StorageOpenOptions};
31+
use std::sync::Arc;
32+
33+
let qcow2_file_opts = StorageOpenOptions::new()
34+
.write(true)
35+
.filename(String::from("image.qcow2"));
36+
let qcow2_file = File::open(qcow2_file_opts).await?;
37+
38+
// Produce qcow2 instance with arbitrary (and potentially mixed) storage instances
39+
let mut qcow2 =
40+
Qcow2::<Box<dyn DynStorage>, Arc<FormatAccess<_>>>::open_image(Box::new(qcow2_file), true)
41+
.await?;
42+
43+
let backing_storage: Box<dyn DynStorage> = Box::new(Null::new(0));
44+
let backing = Raw::open_image(backing_storage, false).await?;
45+
let backing = Arc::new(FormatAccess::new(backing));
46+
qcow2.set_backing(Some(Arc::clone(&backing)));
47+
48+
// Open potentially remaining dependencies (like an external data file)
49+
qcow2.open_implicit_dependencies().await?;
50+
51+
let qcow2 = FormatAccess::new(qcow2);
52+
53+
let mut buf = vec![0u8; 512];
54+
qcow2.read(&mut buf, 0).await?;
55+
56+
qcow2.flush().await?;
57+
```
58+
59+
# Flushing
60+
61+
Given that `AsyncDrop` is not stable yet (and probably will not be stable for a long time),
62+
callers must ensure that images are properly flushed before dropping them, i.e. call
63+
`.flush().await` on any image that is not read-only.
64+
65+
(The synchronous wrapper `SyncFormatAccess` does perform a synchronous flush in its `Drop`
66+
implementation.)
67+
68+
# Features
69+
70+
- `sync-wrappers`: Provide synchronous wrappers for the native `async` interface. Note that
71+
these build a `tokio` runtime in which they run the `async` functions, so using the `async`
72+
interface is definitely preferred.
73+
74+
- `vm-memory`: Provide conversion functions `IoVector::from_volatile_slice` and
75+
`IoVectorMut::from_volatile_slice` to convert the vm-memory crate’s `[VolatileSlice]` arrays into
76+
imago’s native I/O vectors.

src/imago/build.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
use rustc_version::{version_meta, Channel};
2+
3+
fn main() {
4+
println!("cargo:rustc-check-cfg=cfg(nightly)");
5+
6+
if version_meta().unwrap().channel == Channel::Nightly {
7+
println!("cargo:rustc-cfg=nightly");
8+
}
9+
}

src/imago/rustfmt.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
edition = "2021"
2+
format_code_in_doc_comments = true
3+
imports_granularity = "Module"

src/imago/src/annotated.rs

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
//! Annotating wrapper around storage objects.
2+
//!
3+
//! Wraps other storage objects, adding an arbitrary tag to them.
4+
//!
5+
//! This may be useful when using the “mapping” interface, to identify the storage objects returned
6+
//! in raw mappings.
7+
//!
8+
//! Example:
9+
//! ```
10+
//! # use imago::{FormatAccess, Mapping};
11+
//! # use imago::annotated::Annotated;
12+
//! # use imago::null::Null;
13+
//! # use imago::raw::Raw;
14+
//! # tokio::runtime::Builder::new_current_thread()
15+
//! # .build()
16+
//! # .unwrap()
17+
//! # .block_on(async move {
18+
//! #
19+
//! const TEST_TAG: u32 = 42;
20+
//!
21+
//! let disk_size = 16 << 30;
22+
//! let test_offset = 1 << 30;
23+
//!
24+
//! let inner_storage = Null::new(disk_size);
25+
//! let annotated_storage = Annotated::new(inner_storage, TEST_TAG);
26+
//! let image = Raw::open_image(annotated_storage, false).await?;
27+
//! let image = FormatAccess::new(image);
28+
//!
29+
//! let mapping = image.get_mapping(test_offset, 1).await?.0;
30+
//! let Mapping::Raw {
31+
//! storage,
32+
//! offset,
33+
//! writable,
34+
//! } = mapping
35+
//! else {
36+
//! panic!("Raw mapping expected");
37+
//! };
38+
//! assert_eq!(*storage.tag(), TEST_TAG);
39+
//! assert_eq!(offset, test_offset);
40+
//! #
41+
//! # Ok::<(), std::io::Error>(())
42+
//! # }).unwrap()
43+
//! ```
44+
45+
use crate::io_buffers::{IoVector, IoVectorMut};
46+
use crate::storage::drivers::CommonStorageHelper;
47+
use crate::{Storage, StorageOpenOptions};
48+
use std::fmt::{self, Debug, Display, Formatter};
49+
use std::io;
50+
use std::ops::{Deref, DerefMut};
51+
use std::path::{Path, PathBuf};
52+
53+
/// Annotating wrapper around storage objects.
54+
///
55+
/// Wraps other storage objects, adding an arbitrary tag to them.
56+
// TODO: Remove the `Default` requirement. We want to implement `Storage::open()` if `Default` is
57+
// implemented, though, but return an error if it is not. Doing that probably requires
58+
// specialization, though.
59+
#[derive(Debug)]
60+
pub struct Annotated<Tag: Debug + Default + Display + Send + Sync, S: Storage> {
61+
/// Wrapped storage object.
62+
inner: S,
63+
64+
/// Tag.
65+
tag: Tag,
66+
}
67+
68+
impl<T: Debug + Default + Display + Send + Sync, S: Storage> Annotated<T, S> {
69+
/// Wrap `storage`, adding the tag `tag`.
70+
pub fn new(storage: S, tag: T) -> Self {
71+
Annotated {
72+
inner: storage,
73+
tag,
74+
}
75+
}
76+
77+
/// Get the tag.
78+
pub fn tag(&self) -> &T {
79+
&self.tag
80+
}
81+
82+
/// Allow modifying or changing the tag.
83+
pub fn tag_mut(&mut self) -> &mut T {
84+
&mut self.tag
85+
}
86+
}
87+
88+
impl<T: Debug + Default + Display + Send + Sync, S: Storage> From<S> for Annotated<T, S> {
89+
fn from(storage: S) -> Self {
90+
Self::new(storage, T::default())
91+
}
92+
}
93+
94+
impl<T: Debug + Default + Display + Send + Sync, S: Storage> Storage for Annotated<T, S> {
95+
async fn open(opts: StorageOpenOptions) -> io::Result<Self> {
96+
Ok(S::open(opts).await?.into())
97+
}
98+
99+
#[cfg(feature = "sync-wrappers")]
100+
fn open_sync(opts: StorageOpenOptions) -> io::Result<Self> {
101+
Ok(S::open_sync(opts)?.into())
102+
}
103+
104+
fn mem_align(&self) -> usize {
105+
self.inner.mem_align()
106+
}
107+
108+
fn req_align(&self) -> usize {
109+
self.inner.req_align()
110+
}
111+
112+
fn size(&self) -> io::Result<u64> {
113+
self.inner.size()
114+
}
115+
116+
fn resolve_relative_path<P: AsRef<Path>>(&self, relative: P) -> io::Result<PathBuf> {
117+
self.inner.resolve_relative_path(relative)
118+
}
119+
120+
async unsafe fn pure_readv(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()> {
121+
// Caller guarantees safety
122+
unsafe { self.inner.pure_readv(bufv, offset) }.await
123+
}
124+
125+
async unsafe fn pure_writev(&self, bufv: IoVector<'_>, offset: u64) -> io::Result<()> {
126+
// Caller guarantees safety
127+
unsafe { self.inner.pure_writev(bufv, offset) }.await
128+
}
129+
130+
async unsafe fn pure_write_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
131+
// Caller guarantees safety
132+
unsafe { self.inner.pure_write_zeroes(offset, length) }.await
133+
}
134+
135+
async unsafe fn pure_discard(&self, offset: u64, length: u64) -> io::Result<()> {
136+
// Caller guarantees safety
137+
unsafe { self.inner.pure_discard(offset, length) }.await
138+
}
139+
140+
async fn flush(&self) -> io::Result<()> {
141+
self.inner.flush().await
142+
}
143+
144+
async fn sync(&self) -> io::Result<()> {
145+
self.inner.sync().await
146+
}
147+
148+
fn get_storage_helper(&self) -> &CommonStorageHelper {
149+
// Share storage helper from inner (to e.g. get same request serialization)
150+
self.inner.get_storage_helper()
151+
}
152+
}
153+
154+
impl<T: Debug + Default + Display + Send + Sync, S: Storage> Deref for Annotated<T, S> {
155+
type Target = S;
156+
157+
fn deref(&self) -> &S {
158+
&self.inner
159+
}
160+
}
161+
162+
impl<T: Debug + Default + Display + Send + Sync, S: Storage> DerefMut for Annotated<T, S> {
163+
fn deref_mut(&mut self) -> &mut S {
164+
&mut self.inner
165+
}
166+
}
167+
168+
impl<T: Debug + Default + Display + Send + Sync, S: Storage> Display for Annotated<T, S> {
169+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
170+
write!(f, "annotated({})[{}]", self.tag, self.inner)
171+
}
172+
}

0 commit comments

Comments
 (0)