1 // Copyright 2023, The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //! This module provides an implementation of [BlockIo] backed by RAM. 16 17 use crate::{is_aligned, is_buffer_aligned, BlockInfo, BlockIo, SliceMaybeUninit}; 18 use core::ops::DerefMut; 19 use gbl_async::yield_now; 20 use liberror::Error; 21 use safemath::SafeNum; 22 23 /// `RamBlockIo` implements [BlockIo] backed by user provided buffer. 24 pub struct RamBlockIo<T> { 25 /// The storage block size in bytes. 26 pub block_size: u64, 27 /// The storage access alignment in bytes. 28 pub alignment: u64, 29 /// The backing storage data. 30 pub storage: T, 31 /// The number of successful write calls. 32 pub num_writes: usize, 33 /// The number of successful read calls. 34 pub num_reads: usize, 35 /// Injected error to be returned by the next read/write IO. 36 pub error: Option<Error>, 37 } 38 39 impl<T: DerefMut<Target = [u8]>> RamBlockIo<T> { 40 /// Creates an new instance. new(block_size: u64, alignment: u64, storage: T) -> Self41 pub fn new(block_size: u64, alignment: u64, storage: T) -> Self { 42 assert_eq!( 43 storage.len() % usize::try_from(block_size).unwrap(), 44 0, 45 "storage size is not multiple of block size, {}, {}", 46 storage.len(), 47 block_size 48 ); 49 Self { block_size, alignment, storage, num_writes: 0, num_reads: 0, error: None } 50 } 51 52 /// Gets the underlying ramdisk storage. storage(&mut self) -> &mut [u8]53 pub fn storage(&mut self) -> &mut [u8] { 54 &mut self.storage[..] 55 } 56 57 /// Checks injected error, simulates async waiting, checks read/write parameters and returns the 58 /// offset in number of bytes. checks( &mut self, blk_offset: u64, buf: &(impl SliceMaybeUninit + ?Sized), ) -> Result<usize, Error>59 async fn checks( 60 &mut self, 61 blk_offset: u64, 62 buf: &(impl SliceMaybeUninit + ?Sized), 63 ) -> Result<usize, Error> { 64 assert!(is_buffer_aligned(buf.as_ref(), self.alignment).unwrap_or(false)); 65 assert!(is_aligned(buf.len(), self.block_size).unwrap_or(false)); 66 yield_now().await; 67 self.error.take().map(|e| Err(e)).unwrap_or(Ok(()))?; 68 Ok((SafeNum::from(blk_offset) * self.block_size).try_into().unwrap()) 69 } 70 } 71 72 // SAFETY: 73 // `read_blocks` clones `out.len()` bytes to output which initializes all elements in `out` 74 unsafe impl<T: DerefMut<Target = [u8]>> BlockIo for RamBlockIo<T> { info(&mut self) -> BlockInfo75 fn info(&mut self) -> BlockInfo { 76 BlockInfo { 77 block_size: self.block_size, 78 num_blocks: u64::try_from(self.storage.len()).unwrap() / self.block_size, 79 alignment: self.alignment, 80 } 81 } 82 read_blocks( &mut self, blk_offset: u64, out: &mut (impl SliceMaybeUninit + ?Sized), ) -> Result<(), Error>83 async fn read_blocks( 84 &mut self, 85 blk_offset: u64, 86 out: &mut (impl SliceMaybeUninit + ?Sized), 87 ) -> Result<(), Error> { 88 let offset = self.checks(blk_offset, out).await?; 89 let out_len = out.len(); 90 Ok(out.clone_from_slice(&self.storage[offset..][..out_len])) 91 } 92 write_blocks(&mut self, blk_offset: u64, data: &mut [u8]) -> Result<(), Error>93 async fn write_blocks(&mut self, blk_offset: u64, data: &mut [u8]) -> Result<(), Error> { 94 let offset = self.checks(blk_offset, &mut *data).await?; 95 Ok(self.storage[offset..][..data.len()].clone_from_slice(data)) 96 } 97 } 98