xref: /aosp_15_r20/external/crosvm/disk/src/asynchronous.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2022 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker //! Asynchronous disk image helpers.
6*bb4ee6a4SAndroid Build Coastguard Worker 
7*bb4ee6a4SAndroid Build Coastguard Worker use std::io;
8*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Duration;
10*bb4ee6a4SAndroid Build Coastguard Worker 
11*bb4ee6a4SAndroid Build Coastguard Worker use async_trait::async_trait;
12*bb4ee6a4SAndroid Build Coastguard Worker use base::AsRawDescriptors;
13*bb4ee6a4SAndroid Build Coastguard Worker use base::FileAllocate;
14*bb4ee6a4SAndroid Build Coastguard Worker use base::FileSetLen;
15*bb4ee6a4SAndroid Build Coastguard Worker use base::FileSync;
16*bb4ee6a4SAndroid Build Coastguard Worker use base::PunchHole;
17*bb4ee6a4SAndroid Build Coastguard Worker use base::RawDescriptor;
18*bb4ee6a4SAndroid Build Coastguard Worker use base::WriteZeroesAt;
19*bb4ee6a4SAndroid Build Coastguard Worker use cros_async::BackingMemory;
20*bb4ee6a4SAndroid Build Coastguard Worker use cros_async::BlockingPool;
21*bb4ee6a4SAndroid Build Coastguard Worker use cros_async::Executor;
22*bb4ee6a4SAndroid Build Coastguard Worker 
23*bb4ee6a4SAndroid Build Coastguard Worker use crate::AsyncDisk;
24*bb4ee6a4SAndroid Build Coastguard Worker use crate::DiskFile;
25*bb4ee6a4SAndroid Build Coastguard Worker use crate::DiskGetLen;
26*bb4ee6a4SAndroid Build Coastguard Worker use crate::Error;
27*bb4ee6a4SAndroid Build Coastguard Worker use crate::Result;
28*bb4ee6a4SAndroid Build Coastguard Worker 
29*bb4ee6a4SAndroid Build Coastguard Worker /// Async wrapper around a non-async `DiskFile` using a `BlockingPool`.
30*bb4ee6a4SAndroid Build Coastguard Worker ///
31*bb4ee6a4SAndroid Build Coastguard Worker /// This is meant to be a transitional type, not a long-term solution for async disk support. Disk
32*bb4ee6a4SAndroid Build Coastguard Worker /// formats should be migrated to support async instead (b/219595052).
33*bb4ee6a4SAndroid Build Coastguard Worker pub struct AsyncDiskFileWrapper<T: DiskFile + Send> {
34*bb4ee6a4SAndroid Build Coastguard Worker     blocking_pool: BlockingPool,
35*bb4ee6a4SAndroid Build Coastguard Worker     inner: Arc<T>,
36*bb4ee6a4SAndroid Build Coastguard Worker }
37*bb4ee6a4SAndroid Build Coastguard Worker 
38*bb4ee6a4SAndroid Build Coastguard Worker impl<T: DiskFile + Send> AsyncDiskFileWrapper<T> {
39*bb4ee6a4SAndroid Build Coastguard Worker     #[allow(dead_code)] // Only used if qcow or android-sparse features are enabled
new(disk_file: T, _ex: &Executor) -> Self40*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(disk_file: T, _ex: &Executor) -> Self {
41*bb4ee6a4SAndroid Build Coastguard Worker         Self {
42*bb4ee6a4SAndroid Build Coastguard Worker             blocking_pool: BlockingPool::new(1, Duration::from_secs(10)),
43*bb4ee6a4SAndroid Build Coastguard Worker             inner: Arc::new(disk_file),
44*bb4ee6a4SAndroid Build Coastguard Worker         }
45*bb4ee6a4SAndroid Build Coastguard Worker     }
46*bb4ee6a4SAndroid Build Coastguard Worker }
47*bb4ee6a4SAndroid Build Coastguard Worker 
48*bb4ee6a4SAndroid Build Coastguard Worker impl<T: DiskFile + Send> DiskGetLen for AsyncDiskFileWrapper<T> {
get_len(&self) -> io::Result<u64>49*bb4ee6a4SAndroid Build Coastguard Worker     fn get_len(&self) -> io::Result<u64> {
50*bb4ee6a4SAndroid Build Coastguard Worker         self.inner.get_len()
51*bb4ee6a4SAndroid Build Coastguard Worker     }
52*bb4ee6a4SAndroid Build Coastguard Worker }
53*bb4ee6a4SAndroid Build Coastguard Worker 
54*bb4ee6a4SAndroid Build Coastguard Worker impl<T: DiskFile + Send + FileSetLen> FileSetLen for AsyncDiskFileWrapper<T> {
set_len(&self, len: u64) -> io::Result<()>55*bb4ee6a4SAndroid Build Coastguard Worker     fn set_len(&self, len: u64) -> io::Result<()> {
56*bb4ee6a4SAndroid Build Coastguard Worker         self.inner.set_len(len)
57*bb4ee6a4SAndroid Build Coastguard Worker     }
58*bb4ee6a4SAndroid Build Coastguard Worker }
59*bb4ee6a4SAndroid Build Coastguard Worker 
60*bb4ee6a4SAndroid Build Coastguard Worker impl<T: DiskFile + Send + FileAllocate> FileAllocate for AsyncDiskFileWrapper<T> {
allocate(&self, offset: u64, len: u64) -> io::Result<()>61*bb4ee6a4SAndroid Build Coastguard Worker     fn allocate(&self, offset: u64, len: u64) -> io::Result<()> {
62*bb4ee6a4SAndroid Build Coastguard Worker         self.inner.allocate(offset, len)
63*bb4ee6a4SAndroid Build Coastguard Worker     }
64*bb4ee6a4SAndroid Build Coastguard Worker }
65*bb4ee6a4SAndroid Build Coastguard Worker 
66*bb4ee6a4SAndroid Build Coastguard Worker impl<T: DiskFile + Send> AsRawDescriptors for AsyncDiskFileWrapper<T> {
as_raw_descriptors(&self) -> Vec<RawDescriptor>67*bb4ee6a4SAndroid Build Coastguard Worker     fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
68*bb4ee6a4SAndroid Build Coastguard Worker         self.inner.as_raw_descriptors()
69*bb4ee6a4SAndroid Build Coastguard Worker     }
70*bb4ee6a4SAndroid Build Coastguard Worker }
71*bb4ee6a4SAndroid Build Coastguard Worker 
72*bb4ee6a4SAndroid Build Coastguard Worker pub trait DiskFlush {
73*bb4ee6a4SAndroid Build Coastguard Worker     /// Flush intermediary buffers and/or dirty state to file. fsync not required.
flush(&self) -> io::Result<()>74*bb4ee6a4SAndroid Build Coastguard Worker     fn flush(&self) -> io::Result<()>;
75*bb4ee6a4SAndroid Build Coastguard Worker }
76*bb4ee6a4SAndroid Build Coastguard Worker 
77*bb4ee6a4SAndroid Build Coastguard Worker #[async_trait(?Send)]
78*bb4ee6a4SAndroid Build Coastguard Worker impl<
79*bb4ee6a4SAndroid Build Coastguard Worker         T: 'static
80*bb4ee6a4SAndroid Build Coastguard Worker             + DiskFile
81*bb4ee6a4SAndroid Build Coastguard Worker             + DiskFlush
82*bb4ee6a4SAndroid Build Coastguard Worker             + Send
83*bb4ee6a4SAndroid Build Coastguard Worker             + Sync
84*bb4ee6a4SAndroid Build Coastguard Worker             + FileAllocate
85*bb4ee6a4SAndroid Build Coastguard Worker             + FileSetLen
86*bb4ee6a4SAndroid Build Coastguard Worker             + FileSync
87*bb4ee6a4SAndroid Build Coastguard Worker             + PunchHole
88*bb4ee6a4SAndroid Build Coastguard Worker             + WriteZeroesAt,
89*bb4ee6a4SAndroid Build Coastguard Worker     > AsyncDisk for AsyncDiskFileWrapper<T>
90*bb4ee6a4SAndroid Build Coastguard Worker {
flush(&self) -> Result<()>91*bb4ee6a4SAndroid Build Coastguard Worker     async fn flush(&self) -> Result<()> {
92*bb4ee6a4SAndroid Build Coastguard Worker         let inner_clone = self.inner.clone();
93*bb4ee6a4SAndroid Build Coastguard Worker         self.blocking_pool
94*bb4ee6a4SAndroid Build Coastguard Worker             .spawn(move || inner_clone.flush().map_err(Error::IoFlush))
95*bb4ee6a4SAndroid Build Coastguard Worker             .await
96*bb4ee6a4SAndroid Build Coastguard Worker     }
97*bb4ee6a4SAndroid Build Coastguard Worker 
fsync(&self) -> Result<()>98*bb4ee6a4SAndroid Build Coastguard Worker     async fn fsync(&self) -> Result<()> {
99*bb4ee6a4SAndroid Build Coastguard Worker         let inner_clone = self.inner.clone();
100*bb4ee6a4SAndroid Build Coastguard Worker         self.blocking_pool
101*bb4ee6a4SAndroid Build Coastguard Worker             .spawn(move || inner_clone.fsync().map_err(Error::IoFsync))
102*bb4ee6a4SAndroid Build Coastguard Worker             .await
103*bb4ee6a4SAndroid Build Coastguard Worker     }
104*bb4ee6a4SAndroid Build Coastguard Worker 
fdatasync(&self) -> Result<()>105*bb4ee6a4SAndroid Build Coastguard Worker     async fn fdatasync(&self) -> Result<()> {
106*bb4ee6a4SAndroid Build Coastguard Worker         let inner_clone = self.inner.clone();
107*bb4ee6a4SAndroid Build Coastguard Worker         self.blocking_pool
108*bb4ee6a4SAndroid Build Coastguard Worker             .spawn(move || inner_clone.fdatasync().map_err(Error::IoFdatasync))
109*bb4ee6a4SAndroid Build Coastguard Worker             .await
110*bb4ee6a4SAndroid Build Coastguard Worker     }
111*bb4ee6a4SAndroid Build Coastguard Worker 
read_to_mem<'a>( &'a self, mut file_offset: u64, mem: Arc<dyn BackingMemory + Send + Sync>, mem_offsets: cros_async::MemRegionIter<'a>, ) -> Result<usize>112*bb4ee6a4SAndroid Build Coastguard Worker     async fn read_to_mem<'a>(
113*bb4ee6a4SAndroid Build Coastguard Worker         &'a self,
114*bb4ee6a4SAndroid Build Coastguard Worker         mut file_offset: u64,
115*bb4ee6a4SAndroid Build Coastguard Worker         mem: Arc<dyn BackingMemory + Send + Sync>,
116*bb4ee6a4SAndroid Build Coastguard Worker         mem_offsets: cros_async::MemRegionIter<'a>,
117*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<usize> {
118*bb4ee6a4SAndroid Build Coastguard Worker         let inner_clone = self.inner.clone();
119*bb4ee6a4SAndroid Build Coastguard Worker         let mem_offsets: Vec<cros_async::MemRegion> = mem_offsets.collect();
120*bb4ee6a4SAndroid Build Coastguard Worker         self.blocking_pool
121*bb4ee6a4SAndroid Build Coastguard Worker             .spawn(move || {
122*bb4ee6a4SAndroid Build Coastguard Worker                 let mut size = 0;
123*bb4ee6a4SAndroid Build Coastguard Worker                 for region in mem_offsets {
124*bb4ee6a4SAndroid Build Coastguard Worker                     let mem_slice = mem.get_volatile_slice(region).unwrap();
125*bb4ee6a4SAndroid Build Coastguard Worker                     let bytes_read = inner_clone
126*bb4ee6a4SAndroid Build Coastguard Worker                         .read_at_volatile(mem_slice, file_offset)
127*bb4ee6a4SAndroid Build Coastguard Worker                         .map_err(Error::ReadingData)?;
128*bb4ee6a4SAndroid Build Coastguard Worker                     size += bytes_read;
129*bb4ee6a4SAndroid Build Coastguard Worker                     if bytes_read < mem_slice.size() {
130*bb4ee6a4SAndroid Build Coastguard Worker                         break;
131*bb4ee6a4SAndroid Build Coastguard Worker                     }
132*bb4ee6a4SAndroid Build Coastguard Worker                     file_offset += bytes_read as u64;
133*bb4ee6a4SAndroid Build Coastguard Worker                 }
134*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(size)
135*bb4ee6a4SAndroid Build Coastguard Worker             })
136*bb4ee6a4SAndroid Build Coastguard Worker             .await
137*bb4ee6a4SAndroid Build Coastguard Worker     }
138*bb4ee6a4SAndroid Build Coastguard Worker 
write_from_mem<'a>( &'a self, mut file_offset: u64, mem: Arc<dyn BackingMemory + Send + Sync>, mem_offsets: cros_async::MemRegionIter<'a>, ) -> Result<usize>139*bb4ee6a4SAndroid Build Coastguard Worker     async fn write_from_mem<'a>(
140*bb4ee6a4SAndroid Build Coastguard Worker         &'a self,
141*bb4ee6a4SAndroid Build Coastguard Worker         mut file_offset: u64,
142*bb4ee6a4SAndroid Build Coastguard Worker         mem: Arc<dyn BackingMemory + Send + Sync>,
143*bb4ee6a4SAndroid Build Coastguard Worker         mem_offsets: cros_async::MemRegionIter<'a>,
144*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<usize> {
145*bb4ee6a4SAndroid Build Coastguard Worker         let inner_clone = self.inner.clone();
146*bb4ee6a4SAndroid Build Coastguard Worker         let mem_offsets: Vec<cros_async::MemRegion> = mem_offsets.collect();
147*bb4ee6a4SAndroid Build Coastguard Worker         self.blocking_pool
148*bb4ee6a4SAndroid Build Coastguard Worker             .spawn(move || {
149*bb4ee6a4SAndroid Build Coastguard Worker                 let mut size = 0;
150*bb4ee6a4SAndroid Build Coastguard Worker                 for region in mem_offsets {
151*bb4ee6a4SAndroid Build Coastguard Worker                     let mem_slice = mem.get_volatile_slice(region).unwrap();
152*bb4ee6a4SAndroid Build Coastguard Worker                     let bytes_written = inner_clone
153*bb4ee6a4SAndroid Build Coastguard Worker                         .write_at_volatile(mem_slice, file_offset)
154*bb4ee6a4SAndroid Build Coastguard Worker                         .map_err(Error::ReadingData)?;
155*bb4ee6a4SAndroid Build Coastguard Worker                     size += bytes_written;
156*bb4ee6a4SAndroid Build Coastguard Worker                     if bytes_written < mem_slice.size() {
157*bb4ee6a4SAndroid Build Coastguard Worker                         break;
158*bb4ee6a4SAndroid Build Coastguard Worker                     }
159*bb4ee6a4SAndroid Build Coastguard Worker                     file_offset += bytes_written as u64;
160*bb4ee6a4SAndroid Build Coastguard Worker                 }
161*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(size)
162*bb4ee6a4SAndroid Build Coastguard Worker             })
163*bb4ee6a4SAndroid Build Coastguard Worker             .await
164*bb4ee6a4SAndroid Build Coastguard Worker     }
165*bb4ee6a4SAndroid Build Coastguard Worker 
punch_hole(&self, file_offset: u64, length: u64) -> Result<()>166*bb4ee6a4SAndroid Build Coastguard Worker     async fn punch_hole(&self, file_offset: u64, length: u64) -> Result<()> {
167*bb4ee6a4SAndroid Build Coastguard Worker         let inner_clone = self.inner.clone();
168*bb4ee6a4SAndroid Build Coastguard Worker         self.blocking_pool
169*bb4ee6a4SAndroid Build Coastguard Worker             .spawn(move || {
170*bb4ee6a4SAndroid Build Coastguard Worker                 inner_clone
171*bb4ee6a4SAndroid Build Coastguard Worker                     .punch_hole(file_offset, length)
172*bb4ee6a4SAndroid Build Coastguard Worker                     .map_err(Error::IoPunchHole)
173*bb4ee6a4SAndroid Build Coastguard Worker             })
174*bb4ee6a4SAndroid Build Coastguard Worker             .await
175*bb4ee6a4SAndroid Build Coastguard Worker     }
176*bb4ee6a4SAndroid Build Coastguard Worker 
write_zeroes_at(&self, file_offset: u64, length: u64) -> Result<()>177*bb4ee6a4SAndroid Build Coastguard Worker     async fn write_zeroes_at(&self, file_offset: u64, length: u64) -> Result<()> {
178*bb4ee6a4SAndroid Build Coastguard Worker         let inner_clone = self.inner.clone();
179*bb4ee6a4SAndroid Build Coastguard Worker         self.blocking_pool
180*bb4ee6a4SAndroid Build Coastguard Worker             .spawn(move || {
181*bb4ee6a4SAndroid Build Coastguard Worker                 inner_clone
182*bb4ee6a4SAndroid Build Coastguard Worker                     .write_zeroes_all_at(file_offset, length as usize)
183*bb4ee6a4SAndroid Build Coastguard Worker                     .map_err(Error::WriteZeroes)
184*bb4ee6a4SAndroid Build Coastguard Worker             })
185*bb4ee6a4SAndroid Build Coastguard Worker             .await
186*bb4ee6a4SAndroid Build Coastguard Worker     }
187*bb4ee6a4SAndroid Build Coastguard Worker }
188