Skip to main content

disk_blockdevice/
resolver.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Resolver for block device disk handles.
5
6use super::BlockDevice;
7use super::NewDeviceError;
8use async_trait::async_trait;
9use disk_backend::resolve::ResolveDiskParameters;
10use disk_backend::resolve::ResolvedDisk;
11use disk_backend_resources::BlockDeviceDiskHandle;
12use scsi_buffers::BounceBufferTracker;
13use std::fmt::Debug;
14use std::sync::Arc;
15use thiserror::Error;
16use uevent::UeventListener;
17use vm_resource::AsyncResolveResource;
18use vm_resource::ResourceResolver;
19use vm_resource::declare_static_async_resolver;
20use vm_resource::kind::DiskHandleKind;
21
22pub struct BlockDeviceResolver {
23    uevent_listener: Option<Arc<UeventListener>>,
24    bounce_buffer_tracker: Arc<BounceBufferTracker>,
25    always_bounce: bool,
26}
27
28impl BlockDeviceResolver {
29    pub fn new(
30        uevent_listener: Option<Arc<UeventListener>>,
31        bounce_buffer_tracker: Arc<BounceBufferTracker>,
32        always_bounce: bool,
33    ) -> Self {
34        Self {
35            uevent_listener,
36            bounce_buffer_tracker,
37            always_bounce,
38        }
39    }
40}
41
42#[derive(Debug, Error)]
43pub enum ResolveDiskError {
44    #[error("failed to create new device")]
45    NewDevice(#[source] NewDeviceError),
46    #[error("invalid disk")]
47    InvalidDisk(#[source] disk_backend::InvalidDisk),
48}
49
50#[async_trait]
51impl AsyncResolveResource<DiskHandleKind, BlockDeviceDiskHandle> for BlockDeviceResolver {
52    type Output = ResolvedDisk;
53    type Error = ResolveDiskError;
54
55    async fn resolve(
56        &self,
57        _resolver: &ResourceResolver,
58        rsrc: BlockDeviceDiskHandle,
59        input: ResolveDiskParameters<'_>,
60    ) -> Result<Self::Output, Self::Error> {
61        let disk = BlockDevice::new(
62            rsrc.file,
63            input.read_only,
64            input.driver_source.current(),
65            self.uevent_listener.as_deref(),
66            Some(self.bounce_buffer_tracker.clone()),
67            self.always_bounce,
68        )
69        .await
70        .map_err(ResolveDiskError::NewDevice)?;
71        ResolvedDisk::new(disk).map_err(ResolveDiskError::InvalidDisk)
72    }
73}
74
75/// A static resolver for [`BlockDeviceDiskHandle`] that does not use a
76/// shared [`BounceBufferTracker`]. Bounce buffers are allocated on demand
77/// without rate limiting.
78pub struct StaticBlockDeviceResolver;
79
80declare_static_async_resolver!(
81    StaticBlockDeviceResolver,
82    (DiskHandleKind, BlockDeviceDiskHandle),
83);
84
85#[async_trait]
86impl AsyncResolveResource<DiskHandleKind, BlockDeviceDiskHandle> for StaticBlockDeviceResolver {
87    type Output = ResolvedDisk;
88    type Error = ResolveDiskError;
89
90    async fn resolve(
91        &self,
92        _resolver: &ResourceResolver,
93        rsrc: BlockDeviceDiskHandle,
94        input: ResolveDiskParameters<'_>,
95    ) -> Result<Self::Output, Self::Error> {
96        let disk = BlockDevice::new(
97            rsrc.file,
98            input.read_only,
99            input.driver_source.current(),
100            None,
101            None,
102            false,
103        )
104        .await
105        .map_err(ResolveDiskError::NewDevice)?;
106        ResolvedDisk::new(disk).map_err(ResolveDiskError::InvalidDisk)
107    }
108}