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