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