1use super::InvalidLayeredDisk;
7use super::LayerConfiguration;
8use super::LayeredDisk;
9use super::resolve::ResolveDiskLayerParameters;
10use super::resolve::ResolvedDiskLayer;
11use crate::DiskLayer;
12use async_trait::async_trait;
13use disk_backend::InvalidDisk;
14use disk_backend::resolve::ResolveDiskParameters;
15use disk_backend::resolve::ResolvedDisk;
16use disk_backend_resources::LayeredDiskHandle;
17use disk_backend_resources::layer::DiskLayerHandle;
18use futures::future::TryJoinAll;
19use thiserror::Error;
20use vm_resource::AsyncResolveResource;
21use vm_resource::ResolveError;
22use vm_resource::ResourceResolver;
23use vm_resource::declare_static_async_resolver;
24use vm_resource::kind::DiskHandleKind;
25use vm_resource::kind::DiskLayerHandleKind;
26
27declare_static_async_resolver! {
28 LayeredDiskResolver,
29 (DiskHandleKind, LayeredDiskHandle),
30 (DiskLayerHandleKind, DiskLayerHandle)
31}
32
33pub struct LayeredDiskResolver;
35
36#[derive(Debug, Error)]
38pub enum ResolveLayeredDiskError {
39 #[error("failed to resolve layer {0}")]
41 ResolveLayer(usize, #[source] ResolveError),
42 #[error("failed to create layered disk")]
44 CreateDisk(#[source] InvalidLayeredDisk),
45 #[error("invalid disk")]
47 InvalidDisk(#[source] InvalidDisk),
48}
49
50#[async_trait]
51impl AsyncResolveResource<DiskHandleKind, LayeredDiskHandle> for LayeredDiskResolver {
52 type Output = ResolvedDisk;
53 type Error = ResolveLayeredDiskError;
54
55 async fn resolve(
56 &self,
57 resolver: &ResourceResolver,
58 resource: LayeredDiskHandle,
59 input: ResolveDiskParameters<'_>,
60 ) -> Result<Self::Output, Self::Error> {
61 let mut read_only = input.read_only;
62 let layers = resource
63 .layers
64 .into_iter()
65 .enumerate()
66 .map(|(i, desc)| {
67 let this_read_only = read_only && !desc.read_cache;
68 if !desc.write_through {
69 read_only = true;
70 }
71 async move {
72 let layer = resolver
73 .resolve(
74 desc.layer,
75 ResolveDiskLayerParameters {
76 read_only: this_read_only,
77 _async_trait_workaround: &(),
78 },
79 )
80 .await
81 .map_err(|err| ResolveLayeredDiskError::ResolveLayer(i, err))?;
82
83 Ok(LayerConfiguration {
84 layer: layer.0,
85 write_through: desc.write_through,
86 read_cache: desc.read_cache,
87 })
88 }
89 })
90 .collect::<TryJoinAll<_>>()
91 .await?;
92
93 let disk = LayeredDisk::new(input.read_only, layers)
94 .await
95 .map_err(ResolveLayeredDiskError::CreateDisk)?;
96
97 ResolvedDisk::new(disk).map_err(ResolveLayeredDiskError::InvalidDisk)
98 }
99}
100
101#[async_trait]
102impl AsyncResolveResource<DiskLayerHandleKind, DiskLayerHandle> for LayeredDiskResolver {
103 type Output = ResolvedDiskLayer;
104 type Error = ResolveError;
105
106 async fn resolve(
107 &self,
108 resolver: &ResourceResolver,
109 resource: DiskLayerHandle,
110 input: ResolveDiskLayerParameters<'_>,
111 ) -> Result<Self::Output, Self::Error> {
112 let disk = resolver
113 .resolve(
114 resource.0,
115 ResolveDiskParameters {
116 read_only: input.read_only,
117 _async_trait_workaround: &(),
118 },
119 )
120 .await?;
121
122 Ok(ResolvedDiskLayer(DiskLayer::from_disk(disk.0)))
123 }
124}