xref: /aosp_15_r20/bootable/libbootloader/gbl/libstorage/src/lib.rs (revision 5225e6b173e52d2efc6bcf950c27374fd72adabc)
1*5225e6b1SAndroid Build Coastguard Worker // Copyright 2023, The Android Open Source Project
2*5225e6b1SAndroid Build Coastguard Worker //
3*5225e6b1SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*5225e6b1SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*5225e6b1SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*5225e6b1SAndroid Build Coastguard Worker //
7*5225e6b1SAndroid Build Coastguard Worker //     http://www.apache.org/licenses/LICENSE-2.0
8*5225e6b1SAndroid Build Coastguard Worker //
9*5225e6b1SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*5225e6b1SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*5225e6b1SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*5225e6b1SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*5225e6b1SAndroid Build Coastguard Worker // limitations under the License.
14*5225e6b1SAndroid Build Coastguard Worker 
15*5225e6b1SAndroid Build Coastguard Worker //! The library provides APIs for reading/writing with block devices with arbitrary alignment,
16*5225e6b1SAndroid Build Coastguard Worker //! ranges and parsing and manipulation GPT.
17*5225e6b1SAndroid Build Coastguard Worker 
18*5225e6b1SAndroid Build Coastguard Worker #![cfg_attr(not(test), no_std)]
19*5225e6b1SAndroid Build Coastguard Worker #![allow(async_fn_in_trait)]
20*5225e6b1SAndroid Build Coastguard Worker 
21*5225e6b1SAndroid Build Coastguard Worker use core::{
22*5225e6b1SAndroid Build Coastguard Worker     cell::RefMut,
23*5225e6b1SAndroid Build Coastguard Worker     cmp::{max, min},
24*5225e6b1SAndroid Build Coastguard Worker     mem::{size_of_val, MaybeUninit},
25*5225e6b1SAndroid Build Coastguard Worker     ops::DerefMut,
26*5225e6b1SAndroid Build Coastguard Worker     slice::SliceIndex,
27*5225e6b1SAndroid Build Coastguard Worker };
28*5225e6b1SAndroid Build Coastguard Worker use liberror::{Error, Result};
29*5225e6b1SAndroid Build Coastguard Worker use libutils::aligned_subslice;
30*5225e6b1SAndroid Build Coastguard Worker use safemath::SafeNum;
31*5225e6b1SAndroid Build Coastguard Worker 
32*5225e6b1SAndroid Build Coastguard Worker // Selective export of submodule types.
33*5225e6b1SAndroid Build Coastguard Worker mod gpt;
34*5225e6b1SAndroid Build Coastguard Worker pub use gpt::{
35*5225e6b1SAndroid Build Coastguard Worker     gpt_buffer_size, new_gpt_max, new_gpt_n, Gpt, GptBuilder, GptEntry, GptHeader, GptLoadBufferN,
36*5225e6b1SAndroid Build Coastguard Worker     GptMax, GptN, GptSyncResult, Partition, PartitionIterator, GPT_GUID_LEN, GPT_MAGIC,
37*5225e6b1SAndroid Build Coastguard Worker     GPT_NAME_LEN_U16,
38*5225e6b1SAndroid Build Coastguard Worker };
39*5225e6b1SAndroid Build Coastguard Worker 
40*5225e6b1SAndroid Build Coastguard Worker mod algorithm;
41*5225e6b1SAndroid Build Coastguard Worker pub use algorithm::{read_async, write_async};
42*5225e6b1SAndroid Build Coastguard Worker 
43*5225e6b1SAndroid Build Coastguard Worker pub mod ram_block;
44*5225e6b1SAndroid Build Coastguard Worker pub use ram_block::RamBlockIo;
45*5225e6b1SAndroid Build Coastguard Worker 
46*5225e6b1SAndroid Build Coastguard Worker /// `BlockInfo` contains information for a block device.
47*5225e6b1SAndroid Build Coastguard Worker #[derive(Clone, Copy, Debug)]
48*5225e6b1SAndroid Build Coastguard Worker pub struct BlockInfo {
49*5225e6b1SAndroid Build Coastguard Worker     /// Native block size of the block device.
50*5225e6b1SAndroid Build Coastguard Worker     pub block_size: u64,
51*5225e6b1SAndroid Build Coastguard Worker     /// Total number of blocks of the block device.
52*5225e6b1SAndroid Build Coastguard Worker     pub num_blocks: u64,
53*5225e6b1SAndroid Build Coastguard Worker     /// The alignment requirement for IO buffers. For example, many block device drivers use DMA
54*5225e6b1SAndroid Build Coastguard Worker     /// for data transfer, which typically requires that the buffer address for DMA be aligned to
55*5225e6b1SAndroid Build Coastguard Worker     /// 16/32/64 bytes etc. If the block device has no alignment requirement, it can return 1.
56*5225e6b1SAndroid Build Coastguard Worker     pub alignment: u64,
57*5225e6b1SAndroid Build Coastguard Worker }
58*5225e6b1SAndroid Build Coastguard Worker 
59*5225e6b1SAndroid Build Coastguard Worker impl BlockInfo {
60*5225e6b1SAndroid Build Coastguard Worker     /// Computes the total size in bytes of the block device.
total_size(&self) -> Result<u64>61*5225e6b1SAndroid Build Coastguard Worker     pub fn total_size(&self) -> Result<u64> {
62*5225e6b1SAndroid Build Coastguard Worker         Ok((SafeNum::from(self.block_size) * self.num_blocks).try_into()?)
63*5225e6b1SAndroid Build Coastguard Worker     }
64*5225e6b1SAndroid Build Coastguard Worker }
65*5225e6b1SAndroid Build Coastguard Worker 
66*5225e6b1SAndroid Build Coastguard Worker /// `BlockIo` provides interfaces for reading and writing block storage medium.
67*5225e6b1SAndroid Build Coastguard Worker ///
68*5225e6b1SAndroid Build Coastguard Worker /// SAFETY:
69*5225e6b1SAndroid Build Coastguard Worker /// `read_blocks` method must guarantee `out` to be fully initialized on success. Otherwise error
70*5225e6b1SAndroid Build Coastguard Worker /// must be returned.
71*5225e6b1SAndroid Build Coastguard Worker /// This is necessary because unsafe code that uses BlockIo assumes `out` to be fully initialized to
72*5225e6b1SAndroid Build Coastguard Worker /// work with it as with `&mut [u8]`.
73*5225e6b1SAndroid Build Coastguard Worker pub unsafe trait BlockIo {
74*5225e6b1SAndroid Build Coastguard Worker     /// Returns the `BlockInfo` for this block device.
info(&mut self) -> BlockInfo75*5225e6b1SAndroid Build Coastguard Worker     fn info(&mut self) -> BlockInfo;
76*5225e6b1SAndroid Build Coastguard Worker 
77*5225e6b1SAndroid Build Coastguard Worker     /// Read blocks of data from the block device
78*5225e6b1SAndroid Build Coastguard Worker     ///
79*5225e6b1SAndroid Build Coastguard Worker     /// # Args
80*5225e6b1SAndroid Build Coastguard Worker     ///
81*5225e6b1SAndroid Build Coastguard Worker     /// * `blk_offset`: Offset in number of blocks.
82*5225e6b1SAndroid Build Coastguard Worker     ///
83*5225e6b1SAndroid Build Coastguard Worker     /// * `out`: Buffer to store the read data. Callers of this method ensure that it is
84*5225e6b1SAndroid Build Coastguard Worker     ///   aligned according to alignment() and `out.len()` is multiples of `block_size()`.
85*5225e6b1SAndroid Build Coastguard Worker     ///
86*5225e6b1SAndroid Build Coastguard Worker     /// # Returns
87*5225e6b1SAndroid Build Coastguard Worker     ///
88*5225e6b1SAndroid Build Coastguard Worker     /// Returns true if exactly out.len() number of bytes are read. Otherwise false.
read_blocks( &mut self, blk_offset: u64, out: &mut (impl SliceMaybeUninit + ?Sized), ) -> Result<()>89*5225e6b1SAndroid Build Coastguard Worker     async fn read_blocks(
90*5225e6b1SAndroid Build Coastguard Worker         &mut self,
91*5225e6b1SAndroid Build Coastguard Worker         blk_offset: u64,
92*5225e6b1SAndroid Build Coastguard Worker         out: &mut (impl SliceMaybeUninit + ?Sized),
93*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<()>;
94*5225e6b1SAndroid Build Coastguard Worker 
95*5225e6b1SAndroid Build Coastguard Worker     /// Write blocks of data to the block device
96*5225e6b1SAndroid Build Coastguard Worker     ///
97*5225e6b1SAndroid Build Coastguard Worker     /// # Args
98*5225e6b1SAndroid Build Coastguard Worker     ///
99*5225e6b1SAndroid Build Coastguard Worker     /// * `blk_offset`: Offset in number of blocks.
100*5225e6b1SAndroid Build Coastguard Worker     ///
101*5225e6b1SAndroid Build Coastguard Worker     /// * `data`: Data to write. Callers of this method ensure that it is aligned according to
102*5225e6b1SAndroid Build Coastguard Worker     ///   `alignment()` and `data.len()` is multiples of `block_size()`.
103*5225e6b1SAndroid Build Coastguard Worker     ///
104*5225e6b1SAndroid Build Coastguard Worker     /// # Returns
105*5225e6b1SAndroid Build Coastguard Worker     ///
106*5225e6b1SAndroid Build Coastguard Worker     /// Returns true if exactly data.len() number of bytes are written. Otherwise false.
write_blocks(&mut self, blk_offset: u64, data: &mut [u8]) -> Result<()>107*5225e6b1SAndroid Build Coastguard Worker     async fn write_blocks(&mut self, blk_offset: u64, data: &mut [u8]) -> Result<()>;
108*5225e6b1SAndroid Build Coastguard Worker }
109*5225e6b1SAndroid Build Coastguard Worker 
110*5225e6b1SAndroid Build Coastguard Worker // SAFETY:
111*5225e6b1SAndroid Build Coastguard Worker // `read_blocks` method has same guaranties as `BlockIo` implementation of referenced type T.
112*5225e6b1SAndroid Build Coastguard Worker // Which guaranties `out` to be fully initialized on success.
113*5225e6b1SAndroid Build Coastguard Worker unsafe impl<T: DerefMut> BlockIo for T
114*5225e6b1SAndroid Build Coastguard Worker where
115*5225e6b1SAndroid Build Coastguard Worker     T::Target: BlockIo,
116*5225e6b1SAndroid Build Coastguard Worker {
info(&mut self) -> BlockInfo117*5225e6b1SAndroid Build Coastguard Worker     fn info(&mut self) -> BlockInfo {
118*5225e6b1SAndroid Build Coastguard Worker         self.deref_mut().info()
119*5225e6b1SAndroid Build Coastguard Worker     }
120*5225e6b1SAndroid Build Coastguard Worker 
read_blocks( &mut self, blk_offset: u64, out: &mut (impl SliceMaybeUninit + ?Sized), ) -> Result<()>121*5225e6b1SAndroid Build Coastguard Worker     async fn read_blocks(
122*5225e6b1SAndroid Build Coastguard Worker         &mut self,
123*5225e6b1SAndroid Build Coastguard Worker         blk_offset: u64,
124*5225e6b1SAndroid Build Coastguard Worker         out: &mut (impl SliceMaybeUninit + ?Sized),
125*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<()> {
126*5225e6b1SAndroid Build Coastguard Worker         self.deref_mut().read_blocks(blk_offset, out).await
127*5225e6b1SAndroid Build Coastguard Worker     }
128*5225e6b1SAndroid Build Coastguard Worker 
write_blocks(&mut self, blk_offset: u64, data: &mut [u8]) -> Result<()>129*5225e6b1SAndroid Build Coastguard Worker     async fn write_blocks(&mut self, blk_offset: u64, data: &mut [u8]) -> Result<()> {
130*5225e6b1SAndroid Build Coastguard Worker         self.deref_mut().write_blocks(blk_offset, data).await
131*5225e6b1SAndroid Build Coastguard Worker     }
132*5225e6b1SAndroid Build Coastguard Worker }
133*5225e6b1SAndroid Build Coastguard Worker 
134*5225e6b1SAndroid Build Coastguard Worker /// An implementation of `BlockIo` of where all required methods are `unimplemented!()`
135*5225e6b1SAndroid Build Coastguard Worker pub struct BlockIoNull {}
136*5225e6b1SAndroid Build Coastguard Worker 
137*5225e6b1SAndroid Build Coastguard Worker // SAFETY:
138*5225e6b1SAndroid Build Coastguard Worker // `read_blocks` never succeeds since it is not implemented and will panic.
139*5225e6b1SAndroid Build Coastguard Worker unsafe impl BlockIo for BlockIoNull {
info(&mut self) -> BlockInfo140*5225e6b1SAndroid Build Coastguard Worker     fn info(&mut self) -> BlockInfo {
141*5225e6b1SAndroid Build Coastguard Worker         unimplemented!();
142*5225e6b1SAndroid Build Coastguard Worker     }
143*5225e6b1SAndroid Build Coastguard Worker 
read_blocks( &mut self, _: u64, _: &mut (impl SliceMaybeUninit + ?Sized), ) -> Result<()>144*5225e6b1SAndroid Build Coastguard Worker     async fn read_blocks(
145*5225e6b1SAndroid Build Coastguard Worker         &mut self,
146*5225e6b1SAndroid Build Coastguard Worker         _: u64,
147*5225e6b1SAndroid Build Coastguard Worker         _: &mut (impl SliceMaybeUninit + ?Sized),
148*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<()> {
149*5225e6b1SAndroid Build Coastguard Worker         unimplemented!();
150*5225e6b1SAndroid Build Coastguard Worker     }
151*5225e6b1SAndroid Build Coastguard Worker 
write_blocks(&mut self, _: u64, _: &mut [u8]) -> Result<()>152*5225e6b1SAndroid Build Coastguard Worker     async fn write_blocks(&mut self, _: u64, _: &mut [u8]) -> Result<()> {
153*5225e6b1SAndroid Build Coastguard Worker         unimplemented!();
154*5225e6b1SAndroid Build Coastguard Worker     }
155*5225e6b1SAndroid Build Coastguard Worker }
156*5225e6b1SAndroid Build Coastguard Worker 
157*5225e6b1SAndroid Build Coastguard Worker /// Check if `value` is aligned to (multiples of) `alignment`
158*5225e6b1SAndroid Build Coastguard Worker /// It can fail if the remainider calculation fails overflow check.
is_aligned(value: impl Into<SafeNum>, alignment: impl Into<SafeNum>) -> Result<bool>159*5225e6b1SAndroid Build Coastguard Worker pub fn is_aligned(value: impl Into<SafeNum>, alignment: impl Into<SafeNum>) -> Result<bool> {
160*5225e6b1SAndroid Build Coastguard Worker     Ok(u64::try_from(value.into() % alignment.into())? == 0)
161*5225e6b1SAndroid Build Coastguard Worker }
162*5225e6b1SAndroid Build Coastguard Worker 
163*5225e6b1SAndroid Build Coastguard Worker /// Check if `buffer` address is aligned to `alignment`
164*5225e6b1SAndroid Build Coastguard Worker /// It can fail if the remainider calculation fails overflow check.
is_buffer_aligned<T>(buffer: &[T], alignment: u64) -> Result<bool>165*5225e6b1SAndroid Build Coastguard Worker pub fn is_buffer_aligned<T>(buffer: &[T], alignment: u64) -> Result<bool> {
166*5225e6b1SAndroid Build Coastguard Worker     is_aligned(buffer.as_ptr() as usize, alignment)
167*5225e6b1SAndroid Build Coastguard Worker }
168*5225e6b1SAndroid Build Coastguard Worker 
169*5225e6b1SAndroid Build Coastguard Worker /// Check read/write range and calculate offset in number of blocks.
check_range<T>(info: BlockInfo, offset: u64, buffer: &[T]) -> Result<SafeNum>170*5225e6b1SAndroid Build Coastguard Worker fn check_range<T>(info: BlockInfo, offset: u64, buffer: &[T]) -> Result<SafeNum> {
171*5225e6b1SAndroid Build Coastguard Worker     let offset: SafeNum = offset.into();
172*5225e6b1SAndroid Build Coastguard Worker     let block_size: SafeNum = info.block_size.into();
173*5225e6b1SAndroid Build Coastguard Worker     debug_assert!(is_aligned(offset, block_size)?, "{:?}, {:?}", offset, block_size);
174*5225e6b1SAndroid Build Coastguard Worker     debug_assert!(is_aligned(size_of_val(buffer), block_size)?);
175*5225e6b1SAndroid Build Coastguard Worker     debug_assert!(is_buffer_aligned(buffer, info.alignment)?);
176*5225e6b1SAndroid Build Coastguard Worker     let blk_offset = offset / block_size;
177*5225e6b1SAndroid Build Coastguard Worker     let blk_count = SafeNum::from(size_of_val(buffer)) / block_size;
178*5225e6b1SAndroid Build Coastguard Worker     let end: u64 = (blk_offset + blk_count).try_into()?;
179*5225e6b1SAndroid Build Coastguard Worker     match end <= info.num_blocks {
180*5225e6b1SAndroid Build Coastguard Worker         true => Ok(blk_offset),
181*5225e6b1SAndroid Build Coastguard Worker         false => Err(Error::BadIndex(end as usize)),
182*5225e6b1SAndroid Build Coastguard Worker     }
183*5225e6b1SAndroid Build Coastguard Worker }
184*5225e6b1SAndroid Build Coastguard Worker 
185*5225e6b1SAndroid Build Coastguard Worker /// Computes the required scratch size for initializing a [AsyncBlockDevice].
scratch_size(io: &mut impl BlockIo) -> Result<usize>186*5225e6b1SAndroid Build Coastguard Worker pub fn scratch_size(io: &mut impl BlockIo) -> Result<usize> {
187*5225e6b1SAndroid Build Coastguard Worker     let info = io.info();
188*5225e6b1SAndroid Build Coastguard Worker     let block_alignment = match info.block_size {
189*5225e6b1SAndroid Build Coastguard Worker         1 => 0,
190*5225e6b1SAndroid Build Coastguard Worker         v => v,
191*5225e6b1SAndroid Build Coastguard Worker     };
192*5225e6b1SAndroid Build Coastguard Worker     Ok(((SafeNum::from(info.alignment) - 1) * 2 + block_alignment).try_into()?)
193*5225e6b1SAndroid Build Coastguard Worker }
194*5225e6b1SAndroid Build Coastguard Worker 
195*5225e6b1SAndroid Build Coastguard Worker /// `Disk` contains a BlockIO and scratch buffer and provides APIs for reading/writing with
196*5225e6b1SAndroid Build Coastguard Worker /// arbitrary ranges and alignment.
197*5225e6b1SAndroid Build Coastguard Worker pub struct Disk<T, S> {
198*5225e6b1SAndroid Build Coastguard Worker     io: T,
199*5225e6b1SAndroid Build Coastguard Worker     scratch: S,
200*5225e6b1SAndroid Build Coastguard Worker }
201*5225e6b1SAndroid Build Coastguard Worker 
202*5225e6b1SAndroid Build Coastguard Worker impl<T: BlockIo, S: DerefMut<Target = [u8]>> Disk<T, S> {
203*5225e6b1SAndroid Build Coastguard Worker     /// Creates a new instance with the given IO and scratch buffer.
204*5225e6b1SAndroid Build Coastguard Worker     ///
205*5225e6b1SAndroid Build Coastguard Worker     /// * The scratch buffer is internally used for handling partial block read/write and unaligned
206*5225e6b1SAndroid Build Coastguard Worker     ///   input/output user buffers.
207*5225e6b1SAndroid Build Coastguard Worker     ///
208*5225e6b1SAndroid Build Coastguard Worker     /// * The necessary size for the scratch buffer depends on `BlockInfo::alignment`,
209*5225e6b1SAndroid Build Coastguard Worker     ///   `BlockInfo::block_size`. It can be computed using the helper API `scratch_size()`. If the
210*5225e6b1SAndroid Build Coastguard Worker     ///   block device has no alignment requirement, i.e. both alignment and block size are 1, the
211*5225e6b1SAndroid Build Coastguard Worker     ///   total required scratch size is 0.
new(mut io: T, scratch: S) -> Result<Self>212*5225e6b1SAndroid Build Coastguard Worker     pub fn new(mut io: T, scratch: S) -> Result<Self> {
213*5225e6b1SAndroid Build Coastguard Worker         let sz = scratch_size(&mut io)?;
214*5225e6b1SAndroid Build Coastguard Worker         match scratch.len() < sz {
215*5225e6b1SAndroid Build Coastguard Worker             true => Err(Error::BufferTooSmall(Some(sz))),
216*5225e6b1SAndroid Build Coastguard Worker             _ => Ok(Self { io, scratch }),
217*5225e6b1SAndroid Build Coastguard Worker         }
218*5225e6b1SAndroid Build Coastguard Worker     }
219*5225e6b1SAndroid Build Coastguard Worker 
220*5225e6b1SAndroid Build Coastguard Worker     /// Same as `Self::new()` but allocates the necessary scratch buffer.
221*5225e6b1SAndroid Build Coastguard Worker     ///
222*5225e6b1SAndroid Build Coastguard Worker     /// T must implement Extend<u8> and Default. It should typically be a vector like type.
223*5225e6b1SAndroid Build Coastguard Worker     ///
224*5225e6b1SAndroid Build Coastguard Worker     /// Allocation is done by extending T one element at a time. In most cases, we don't expect
225*5225e6b1SAndroid Build Coastguard Worker     /// block size or alignment to be large values and this is only done once. thus this should be
226*5225e6b1SAndroid Build Coastguard Worker     /// low cost. However if that is not the case, it is recommended to use `Self::new()` with
227*5225e6b1SAndroid Build Coastguard Worker     /// pre-allocated scratch buffer.
new_alloc_scratch(mut io: T) -> Result<Self> where S: Extend<u8> + Default,228*5225e6b1SAndroid Build Coastguard Worker     pub fn new_alloc_scratch(mut io: T) -> Result<Self>
229*5225e6b1SAndroid Build Coastguard Worker     where
230*5225e6b1SAndroid Build Coastguard Worker         S: Extend<u8> + Default,
231*5225e6b1SAndroid Build Coastguard Worker     {
232*5225e6b1SAndroid Build Coastguard Worker         let mut scratch = S::default();
233*5225e6b1SAndroid Build Coastguard Worker         // Extends the scratch buffer to the required size.
234*5225e6b1SAndroid Build Coastguard Worker         // Can call `extend_reserve()` first once it becomes stable.
235*5225e6b1SAndroid Build Coastguard Worker         (0..max(scratch.len(), scratch_size(&mut io)?) - scratch.len())
236*5225e6b1SAndroid Build Coastguard Worker             .for_each(|_| scratch.extend([0u8]));
237*5225e6b1SAndroid Build Coastguard Worker         Self::new(io, scratch)
238*5225e6b1SAndroid Build Coastguard Worker     }
239*5225e6b1SAndroid Build Coastguard Worker 
240*5225e6b1SAndroid Build Coastguard Worker     /// Creates a `Disk<&mut T, &mut [u8]>` instance that borrows the internal fields.
as_borrowed(&mut self) -> Disk<&mut T, &mut [u8]>241*5225e6b1SAndroid Build Coastguard Worker     pub fn as_borrowed(&mut self) -> Disk<&mut T, &mut [u8]> {
242*5225e6b1SAndroid Build Coastguard Worker         Disk::new(&mut self.io, &mut self.scratch[..]).unwrap()
243*5225e6b1SAndroid Build Coastguard Worker     }
244*5225e6b1SAndroid Build Coastguard Worker 
245*5225e6b1SAndroid Build Coastguard Worker     /// Gets the [BlockInfo]
block_info(&mut self) -> BlockInfo246*5225e6b1SAndroid Build Coastguard Worker     pub fn block_info(&mut self) -> BlockInfo {
247*5225e6b1SAndroid Build Coastguard Worker         self.io.info()
248*5225e6b1SAndroid Build Coastguard Worker     }
249*5225e6b1SAndroid Build Coastguard Worker 
250*5225e6b1SAndroid Build Coastguard Worker     /// Gets the underlying BlockIo implementation.
io(&mut self) -> &mut T251*5225e6b1SAndroid Build Coastguard Worker     pub fn io(&mut self) -> &mut T {
252*5225e6b1SAndroid Build Coastguard Worker         &mut self.io
253*5225e6b1SAndroid Build Coastguard Worker     }
254*5225e6b1SAndroid Build Coastguard Worker 
255*5225e6b1SAndroid Build Coastguard Worker     /// Reads data from the block device.
256*5225e6b1SAndroid Build Coastguard Worker     ///
257*5225e6b1SAndroid Build Coastguard Worker     /// # Args
258*5225e6b1SAndroid Build Coastguard Worker     ///
259*5225e6b1SAndroid Build Coastguard Worker     /// * `offset`: Offset in number of bytes.
260*5225e6b1SAndroid Build Coastguard Worker     /// * `out`: Buffer to store the read data.
261*5225e6b1SAndroid Build Coastguard Worker     /// * Returns success when exactly `out.len()` number of bytes are read.
read( &mut self, offset: u64, out: &mut (impl SliceMaybeUninit + ?Sized), ) -> Result<()>262*5225e6b1SAndroid Build Coastguard Worker     pub async fn read(
263*5225e6b1SAndroid Build Coastguard Worker         &mut self,
264*5225e6b1SAndroid Build Coastguard Worker         offset: u64,
265*5225e6b1SAndroid Build Coastguard Worker         out: &mut (impl SliceMaybeUninit + ?Sized),
266*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<()> {
267*5225e6b1SAndroid Build Coastguard Worker         read_async(&mut self.io, offset, out, &mut self.scratch).await
268*5225e6b1SAndroid Build Coastguard Worker     }
269*5225e6b1SAndroid Build Coastguard Worker 
270*5225e6b1SAndroid Build Coastguard Worker     /// Writes data to the device.
271*5225e6b1SAndroid Build Coastguard Worker     ///
272*5225e6b1SAndroid Build Coastguard Worker     /// # Args
273*5225e6b1SAndroid Build Coastguard Worker     ///
274*5225e6b1SAndroid Build Coastguard Worker     /// * `offset`: Offset in number of bytes.
275*5225e6b1SAndroid Build Coastguard Worker     /// * `data`: Data to write.
276*5225e6b1SAndroid Build Coastguard Worker     ///
277*5225e6b1SAndroid Build Coastguard Worker     /// # Returns
278*5225e6b1SAndroid Build Coastguard Worker     ///
279*5225e6b1SAndroid Build Coastguard Worker     /// * Returns success when exactly `data.len()` number of bytes are written.
write(&mut self, offset: u64, data: &mut [u8]) -> Result<()>280*5225e6b1SAndroid Build Coastguard Worker     pub async fn write(&mut self, offset: u64, data: &mut [u8]) -> Result<()> {
281*5225e6b1SAndroid Build Coastguard Worker         write_async(&mut self.io, offset, data, &mut self.scratch).await
282*5225e6b1SAndroid Build Coastguard Worker     }
283*5225e6b1SAndroid Build Coastguard Worker 
284*5225e6b1SAndroid Build Coastguard Worker     /// Fills a disk range with the given byte value
285*5225e6b1SAndroid Build Coastguard Worker     ///
286*5225e6b1SAndroid Build Coastguard Worker     /// # Args
287*5225e6b1SAndroid Build Coastguard Worker     ///
288*5225e6b1SAndroid Build Coastguard Worker     /// * `offset`: Offset in number of bytes.
289*5225e6b1SAndroid Build Coastguard Worker     /// * `size`: Number of bytes to fill.
290*5225e6b1SAndroid Build Coastguard Worker     /// * `val`: Fill value.
291*5225e6b1SAndroid Build Coastguard Worker     /// * `scratch`: A scratch buffer that will be used for writing `val` in batches.
292*5225e6b1SAndroid Build Coastguard Worker     ///
293*5225e6b1SAndroid Build Coastguard Worker     /// # Returns
294*5225e6b1SAndroid Build Coastguard Worker     ///
295*5225e6b1SAndroid Build Coastguard Worker     /// * Returns Err(Error::InvalidInput) if size of `scratch` is 0.
fill( &mut self, mut offset: u64, size: u64, val: u8, scratch: &mut [u8], ) -> Result<()>296*5225e6b1SAndroid Build Coastguard Worker     pub async fn fill(
297*5225e6b1SAndroid Build Coastguard Worker         &mut self,
298*5225e6b1SAndroid Build Coastguard Worker         mut offset: u64,
299*5225e6b1SAndroid Build Coastguard Worker         size: u64,
300*5225e6b1SAndroid Build Coastguard Worker         val: u8,
301*5225e6b1SAndroid Build Coastguard Worker         scratch: &mut [u8],
302*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<()> {
303*5225e6b1SAndroid Build Coastguard Worker         if scratch.is_empty() {
304*5225e6b1SAndroid Build Coastguard Worker             return Err(Error::InvalidInput);
305*5225e6b1SAndroid Build Coastguard Worker         }
306*5225e6b1SAndroid Build Coastguard Worker         let blk_sz = usize::try_from(self.block_info().block_size)?;
307*5225e6b1SAndroid Build Coastguard Worker         // Optimizes by trying to get an aligned and multi-block-size buffer.
308*5225e6b1SAndroid Build Coastguard Worker         let buf = match aligned_subslice(scratch, self.block_info().alignment) {
309*5225e6b1SAndroid Build Coastguard Worker             Ok(v) => match v.len() / blk_sz {
310*5225e6b1SAndroid Build Coastguard Worker                 b if b > 0 => &mut v[..b * blk_sz],
311*5225e6b1SAndroid Build Coastguard Worker                 _ => v,
312*5225e6b1SAndroid Build Coastguard Worker             },
313*5225e6b1SAndroid Build Coastguard Worker             _ => scratch,
314*5225e6b1SAndroid Build Coastguard Worker         };
315*5225e6b1SAndroid Build Coastguard Worker         let sz = min(size, buf.len().try_into()?);
316*5225e6b1SAndroid Build Coastguard Worker         buf[..usize::try_from(sz).unwrap()].fill(val);
317*5225e6b1SAndroid Build Coastguard Worker         let end: u64 = (SafeNum::from(offset) + size).try_into()?;
318*5225e6b1SAndroid Build Coastguard Worker         while offset < end {
319*5225e6b1SAndroid Build Coastguard Worker             let to_write = min(sz, end - offset);
320*5225e6b1SAndroid Build Coastguard Worker             self.write(offset, &mut buf[..usize::try_from(to_write).unwrap()]).await?;
321*5225e6b1SAndroid Build Coastguard Worker             offset += to_write;
322*5225e6b1SAndroid Build Coastguard Worker         }
323*5225e6b1SAndroid Build Coastguard Worker         Ok(())
324*5225e6b1SAndroid Build Coastguard Worker     }
325*5225e6b1SAndroid Build Coastguard Worker 
326*5225e6b1SAndroid Build Coastguard Worker     /// Loads and syncs GPT from a block device.
327*5225e6b1SAndroid Build Coastguard Worker     ///
328*5225e6b1SAndroid Build Coastguard Worker     /// The API validates and restores primary/secondary GPT header.
329*5225e6b1SAndroid Build Coastguard Worker     ///
330*5225e6b1SAndroid Build Coastguard Worker     /// # Returns
331*5225e6b1SAndroid Build Coastguard Worker     ///
332*5225e6b1SAndroid Build Coastguard Worker     /// * Returns Ok(sync_result) if disk IO is successful, where `sync_result` contains the GPT
333*5225e6b1SAndroid Build Coastguard Worker     ///   verification and restoration result.
334*5225e6b1SAndroid Build Coastguard Worker     /// * Returns Err() if disk IO encounters errors.
sync_gpt( &mut self, gpt: &mut Gpt<impl DerefMut<Target = [u8]>>, ) -> Result<GptSyncResult>335*5225e6b1SAndroid Build Coastguard Worker     pub async fn sync_gpt(
336*5225e6b1SAndroid Build Coastguard Worker         &mut self,
337*5225e6b1SAndroid Build Coastguard Worker         gpt: &mut Gpt<impl DerefMut<Target = [u8]>>,
338*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<GptSyncResult> {
339*5225e6b1SAndroid Build Coastguard Worker         gpt.load_and_sync(self).await
340*5225e6b1SAndroid Build Coastguard Worker     }
341*5225e6b1SAndroid Build Coastguard Worker 
342*5225e6b1SAndroid Build Coastguard Worker     /// Updates GPT to the block device and sync primary and secondary GPT.
343*5225e6b1SAndroid Build Coastguard Worker     ///
344*5225e6b1SAndroid Build Coastguard Worker     /// # Args
345*5225e6b1SAndroid Build Coastguard Worker     ///
346*5225e6b1SAndroid Build Coastguard Worker     /// * `mbr_primary`: A buffer containing the MBR block, primary GPT header and entries.
347*5225e6b1SAndroid Build Coastguard Worker     /// * `resize`: If set to true, the method updates the last partition to cover the rest of the
348*5225e6b1SAndroid Build Coastguard Worker     ///    storage.
349*5225e6b1SAndroid Build Coastguard Worker     /// * `gpt`: The GPT to update.
350*5225e6b1SAndroid Build Coastguard Worker     ///
351*5225e6b1SAndroid Build Coastguard Worker     /// # Returns
352*5225e6b1SAndroid Build Coastguard Worker     ///
353*5225e6b1SAndroid Build Coastguard Worker     /// * Return `Ok(())` if new GPT is valid and device is updated and synced successfully.
update_gpt( &mut self, mbr_primary: &mut [u8], resize: bool, gpt: &mut Gpt<impl DerefMut<Target = [u8]>>, ) -> Result<()>354*5225e6b1SAndroid Build Coastguard Worker     pub async fn update_gpt(
355*5225e6b1SAndroid Build Coastguard Worker         &mut self,
356*5225e6b1SAndroid Build Coastguard Worker         mbr_primary: &mut [u8],
357*5225e6b1SAndroid Build Coastguard Worker         resize: bool,
358*5225e6b1SAndroid Build Coastguard Worker         gpt: &mut Gpt<impl DerefMut<Target = [u8]>>,
359*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<()> {
360*5225e6b1SAndroid Build Coastguard Worker         gpt::update_gpt(self, mbr_primary, resize, gpt).await
361*5225e6b1SAndroid Build Coastguard Worker     }
362*5225e6b1SAndroid Build Coastguard Worker 
363*5225e6b1SAndroid Build Coastguard Worker     /// Erases GPT if the disk has one.
364*5225e6b1SAndroid Build Coastguard Worker     ///
365*5225e6b1SAndroid Build Coastguard Worker     /// The method will first perform a GPT sync and makes sure that all valid entries are wiped.
366*5225e6b1SAndroid Build Coastguard Worker     ///
367*5225e6b1SAndroid Build Coastguard Worker     /// # Args
368*5225e6b1SAndroid Build Coastguard Worker     ///
369*5225e6b1SAndroid Build Coastguard Worker     /// * `gpt`: An instance of GPT.
erase_gpt(&mut self, gpt: &mut Gpt<impl DerefMut<Target = [u8]>>) -> Result<()>370*5225e6b1SAndroid Build Coastguard Worker     pub async fn erase_gpt(&mut self, gpt: &mut Gpt<impl DerefMut<Target = [u8]>>) -> Result<()> {
371*5225e6b1SAndroid Build Coastguard Worker         gpt::erase_gpt(self, gpt).await
372*5225e6b1SAndroid Build Coastguard Worker     }
373*5225e6b1SAndroid Build Coastguard Worker 
374*5225e6b1SAndroid Build Coastguard Worker     /// Reads a GPT partition on a block device
375*5225e6b1SAndroid Build Coastguard Worker     ///
376*5225e6b1SAndroid Build Coastguard Worker     /// # Args
377*5225e6b1SAndroid Build Coastguard Worker     ///
378*5225e6b1SAndroid Build Coastguard Worker     /// * `gpt`: A `GptCache` initialized with `Self::sync_gpt()`.
379*5225e6b1SAndroid Build Coastguard Worker     /// * `part_name`: Name of the partition.
380*5225e6b1SAndroid Build Coastguard Worker     /// * `offset`: Offset in number of bytes into the partition.
381*5225e6b1SAndroid Build Coastguard Worker     /// * `out`: Buffer to store the read data.
382*5225e6b1SAndroid Build Coastguard Worker     ///
383*5225e6b1SAndroid Build Coastguard Worker     /// # Returns
384*5225e6b1SAndroid Build Coastguard Worker     ///
385*5225e6b1SAndroid Build Coastguard Worker     /// Returns success when exactly `out.len()` of bytes are read successfully.
read_gpt_partition( &mut self, gpt: &mut Gpt<impl DerefMut<Target = [u8]>>, part_name: &str, offset: u64, out: &mut (impl SliceMaybeUninit + ?Sized), ) -> Result<()>386*5225e6b1SAndroid Build Coastguard Worker     pub async fn read_gpt_partition(
387*5225e6b1SAndroid Build Coastguard Worker         &mut self,
388*5225e6b1SAndroid Build Coastguard Worker         gpt: &mut Gpt<impl DerefMut<Target = [u8]>>,
389*5225e6b1SAndroid Build Coastguard Worker         part_name: &str,
390*5225e6b1SAndroid Build Coastguard Worker         offset: u64,
391*5225e6b1SAndroid Build Coastguard Worker         out: &mut (impl SliceMaybeUninit + ?Sized),
392*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<()> {
393*5225e6b1SAndroid Build Coastguard Worker         let offset = gpt.check_range(part_name, offset, out.len())?;
394*5225e6b1SAndroid Build Coastguard Worker         self.read(offset, out).await
395*5225e6b1SAndroid Build Coastguard Worker     }
396*5225e6b1SAndroid Build Coastguard Worker 
397*5225e6b1SAndroid Build Coastguard Worker     /// Writes a GPT partition on a block device.
398*5225e6b1SAndroid Build Coastguard Worker     ///
399*5225e6b1SAndroid Build Coastguard Worker     ///
400*5225e6b1SAndroid Build Coastguard Worker     /// # Args
401*5225e6b1SAndroid Build Coastguard Worker     ///
402*5225e6b1SAndroid Build Coastguard Worker     /// * `gpt`: A `GptCache` initialized with `Self::sync_gpt()`.
403*5225e6b1SAndroid Build Coastguard Worker     /// * `part_name`: Name of the partition.
404*5225e6b1SAndroid Build Coastguard Worker     /// * `offset`: Offset in number of bytes into the partition.
405*5225e6b1SAndroid Build Coastguard Worker     /// * `data`: Data to write. See `data` passed to `BlockIoSync::write()` for details.
406*5225e6b1SAndroid Build Coastguard Worker     ///
407*5225e6b1SAndroid Build Coastguard Worker     /// # Returns
408*5225e6b1SAndroid Build Coastguard Worker     ///
409*5225e6b1SAndroid Build Coastguard Worker     /// Returns success when exactly `data.len()` of bytes are written successfully.
write_gpt_partition( &mut self, gpt: &mut Gpt<impl DerefMut<Target = [u8]>>, part_name: &str, offset: u64, data: &mut [u8], ) -> Result<()>410*5225e6b1SAndroid Build Coastguard Worker     pub async fn write_gpt_partition(
411*5225e6b1SAndroid Build Coastguard Worker         &mut self,
412*5225e6b1SAndroid Build Coastguard Worker         gpt: &mut Gpt<impl DerefMut<Target = [u8]>>,
413*5225e6b1SAndroid Build Coastguard Worker         part_name: &str,
414*5225e6b1SAndroid Build Coastguard Worker         offset: u64,
415*5225e6b1SAndroid Build Coastguard Worker         data: &mut [u8],
416*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<()> {
417*5225e6b1SAndroid Build Coastguard Worker         let offset = gpt.check_range(part_name, offset, data.len())?;
418*5225e6b1SAndroid Build Coastguard Worker         self.write(offset, data).await
419*5225e6b1SAndroid Build Coastguard Worker     }
420*5225e6b1SAndroid Build Coastguard Worker }
421*5225e6b1SAndroid Build Coastguard Worker 
422*5225e6b1SAndroid Build Coastguard Worker impl<'a, T: BlockIo> Disk<RefMut<'a, T>, RefMut<'a, [u8]>> {
423*5225e6b1SAndroid Build Coastguard Worker     /// Converts a `RefMut<Disk<T, S>>` to `Disk<RefMut<T>, RefMut<[u8]>>`. The scratch buffer
424*5225e6b1SAndroid Build Coastguard Worker     /// generic type is eliminated in the return.
from_ref_mut(val: RefMut<'a, Disk<T, impl DerefMut<Target = [u8]>>>) -> Self425*5225e6b1SAndroid Build Coastguard Worker     pub fn from_ref_mut(val: RefMut<'a, Disk<T, impl DerefMut<Target = [u8]>>>) -> Self {
426*5225e6b1SAndroid Build Coastguard Worker         let (io, scratch) = RefMut::map_split(val, |v| (&mut v.io, &mut v.scratch[..]));
427*5225e6b1SAndroid Build Coastguard Worker         Disk::new(io, scratch).unwrap()
428*5225e6b1SAndroid Build Coastguard Worker     }
429*5225e6b1SAndroid Build Coastguard Worker }
430*5225e6b1SAndroid Build Coastguard Worker 
431*5225e6b1SAndroid Build Coastguard Worker impl<T, S> Disk<RamBlockIo<T>, S>
432*5225e6b1SAndroid Build Coastguard Worker where
433*5225e6b1SAndroid Build Coastguard Worker     T: DerefMut<Target = [u8]>,
434*5225e6b1SAndroid Build Coastguard Worker     S: DerefMut<Target = [u8]> + Extend<u8> + Default,
435*5225e6b1SAndroid Build Coastguard Worker {
436*5225e6b1SAndroid Build Coastguard Worker     /// Creates a new ram disk instance with allocated scratch buffer.
new_ram_alloc(block_size: u64, alignment: u64, storage: T) -> Result<Self>437*5225e6b1SAndroid Build Coastguard Worker     pub fn new_ram_alloc(block_size: u64, alignment: u64, storage: T) -> Result<Self> {
438*5225e6b1SAndroid Build Coastguard Worker         let ram_blk = RamBlockIo::new(block_size, alignment, storage);
439*5225e6b1SAndroid Build Coastguard Worker         Self::new_alloc_scratch(ram_blk)
440*5225e6b1SAndroid Build Coastguard Worker     }
441*5225e6b1SAndroid Build Coastguard Worker }
442*5225e6b1SAndroid Build Coastguard Worker 
443*5225e6b1SAndroid Build Coastguard Worker /// Helper trait to implement common logic working with MaybeUninit slices.
444*5225e6b1SAndroid Build Coastguard Worker /// Implemented for [u8] and [MaybeUninit<u8>].
445*5225e6b1SAndroid Build Coastguard Worker ///
446*5225e6b1SAndroid Build Coastguard Worker /// Read functions treats buffer as not initialized using this trait.
447*5225e6b1SAndroid Build Coastguard Worker // AsRef,AsMut implementation added here. Since it is not possible to implement trait from other
448*5225e6b1SAndroid Build Coastguard Worker // crate for trait in this trait. It is possible to implement other trait for `dyn` object of local
449*5225e6b1SAndroid Build Coastguard Worker // trait. But it introduces other issues with lifetime and casting boilerplate.
450*5225e6b1SAndroid Build Coastguard Worker //
451*5225e6b1SAndroid Build Coastguard Worker // Alternatively we considered using wrapper type, which works but requires `into()` call either on
452*5225e6b1SAndroid Build Coastguard Worker // function call. Or inside functions if they accept `impl Into<Wrapper>`.
453*5225e6b1SAndroid Build Coastguard Worker // Using traits seems to be cleaner and potentially more effective.
454*5225e6b1SAndroid Build Coastguard Worker pub trait SliceMaybeUninit {
455*5225e6b1SAndroid Build Coastguard Worker     /// Get `&[MaybeUninit<u8>]` representation
as_ref(&self) -> &[MaybeUninit<u8>]456*5225e6b1SAndroid Build Coastguard Worker     fn as_ref(&self) -> &[MaybeUninit<u8>];
457*5225e6b1SAndroid Build Coastguard Worker 
458*5225e6b1SAndroid Build Coastguard Worker     // AsMut implementation
459*5225e6b1SAndroid Build Coastguard Worker     /// Get `&mut [MaybeUninit<u8>]` representation
as_mut(&mut self) -> &mut [MaybeUninit<u8>]460*5225e6b1SAndroid Build Coastguard Worker     fn as_mut(&mut self) -> &mut [MaybeUninit<u8>];
461*5225e6b1SAndroid Build Coastguard Worker 
462*5225e6b1SAndroid Build Coastguard Worker     /// Get slice length
len(&self) -> usize463*5225e6b1SAndroid Build Coastguard Worker     fn len(&self) -> usize {
464*5225e6b1SAndroid Build Coastguard Worker         self.as_ref().len()
465*5225e6b1SAndroid Build Coastguard Worker     }
466*5225e6b1SAndroid Build Coastguard Worker 
467*5225e6b1SAndroid Build Coastguard Worker     /// Returns reference to element or subslice, or Error if index is out of bounds
get<I>(&mut self, index: I) -> Result<&<I>::Output> where I: SliceIndex<[MaybeUninit<u8>]>,468*5225e6b1SAndroid Build Coastguard Worker     fn get<I>(&mut self, index: I) -> Result<&<I>::Output>
469*5225e6b1SAndroid Build Coastguard Worker     where
470*5225e6b1SAndroid Build Coastguard Worker         I: SliceIndex<[MaybeUninit<u8>]>,
471*5225e6b1SAndroid Build Coastguard Worker     {
472*5225e6b1SAndroid Build Coastguard Worker         self.as_ref().get(index).ok_or(Error::BufferTooSmall(None))
473*5225e6b1SAndroid Build Coastguard Worker     }
474*5225e6b1SAndroid Build Coastguard Worker 
475*5225e6b1SAndroid Build Coastguard Worker     /// Returns mutable reference to element or subslice, or Error if index is out of bounds
get_mut<I>(&mut self, index: I) -> Result<&mut <I>::Output> where I: SliceIndex<[MaybeUninit<u8>]>,476*5225e6b1SAndroid Build Coastguard Worker     fn get_mut<I>(&mut self, index: I) -> Result<&mut <I>::Output>
477*5225e6b1SAndroid Build Coastguard Worker     where
478*5225e6b1SAndroid Build Coastguard Worker         I: SliceIndex<[MaybeUninit<u8>]>,
479*5225e6b1SAndroid Build Coastguard Worker     {
480*5225e6b1SAndroid Build Coastguard Worker         self.as_mut().get_mut(index).ok_or(Error::BufferTooSmall(None))
481*5225e6b1SAndroid Build Coastguard Worker     }
482*5225e6b1SAndroid Build Coastguard Worker 
483*5225e6b1SAndroid Build Coastguard Worker     /// Clone from slice
clone_from_slice(&mut self, src: &[u8])484*5225e6b1SAndroid Build Coastguard Worker     fn clone_from_slice(&mut self, src: &[u8]) {
485*5225e6b1SAndroid Build Coastguard Worker         self.as_mut().clone_from_slice(as_uninit(src))
486*5225e6b1SAndroid Build Coastguard Worker     }
487*5225e6b1SAndroid Build Coastguard Worker }
488*5225e6b1SAndroid Build Coastguard Worker 
489*5225e6b1SAndroid Build Coastguard Worker impl SliceMaybeUninit for [u8] {
as_ref(&self) -> &[MaybeUninit<u8>]490*5225e6b1SAndroid Build Coastguard Worker     fn as_ref(&self) -> &[MaybeUninit<u8>] {
491*5225e6b1SAndroid Build Coastguard Worker         as_uninit(self)
492*5225e6b1SAndroid Build Coastguard Worker     }
as_mut(&mut self) -> &mut [MaybeUninit<u8>]493*5225e6b1SAndroid Build Coastguard Worker     fn as_mut(&mut self) -> &mut [MaybeUninit<u8>] {
494*5225e6b1SAndroid Build Coastguard Worker         as_uninit_mut(self)
495*5225e6b1SAndroid Build Coastguard Worker     }
496*5225e6b1SAndroid Build Coastguard Worker }
497*5225e6b1SAndroid Build Coastguard Worker 
498*5225e6b1SAndroid Build Coastguard Worker impl SliceMaybeUninit for [MaybeUninit<u8>] {
as_ref(&self) -> &[MaybeUninit<u8>]499*5225e6b1SAndroid Build Coastguard Worker     fn as_ref(&self) -> &[MaybeUninit<u8>] {
500*5225e6b1SAndroid Build Coastguard Worker         self
501*5225e6b1SAndroid Build Coastguard Worker     }
as_mut(&mut self) -> &mut [MaybeUninit<u8>]502*5225e6b1SAndroid Build Coastguard Worker     fn as_mut(&mut self) -> &mut [MaybeUninit<u8>] {
503*5225e6b1SAndroid Build Coastguard Worker         self
504*5225e6b1SAndroid Build Coastguard Worker     }
505*5225e6b1SAndroid Build Coastguard Worker }
506*5225e6b1SAndroid Build Coastguard Worker 
507*5225e6b1SAndroid Build Coastguard Worker /// Present initialized `&mut [u8]` buffer as `&mut [MaybeUninit<u8>]`
as_uninit_mut(buf: &mut [u8]) -> &mut [MaybeUninit<u8>]508*5225e6b1SAndroid Build Coastguard Worker pub fn as_uninit_mut(buf: &mut [u8]) -> &mut [MaybeUninit<u8>] {
509*5225e6b1SAndroid Build Coastguard Worker     // SAFETY:
510*5225e6b1SAndroid Build Coastguard Worker     // MaybeUninit<u8> has same size and alignment as u8.
511*5225e6b1SAndroid Build Coastguard Worker     // `data` is valid pointer to initialised u8 slice of size `buf.len()`
512*5225e6b1SAndroid Build Coastguard Worker     unsafe { core::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut MaybeUninit<u8>, buf.len()) }
513*5225e6b1SAndroid Build Coastguard Worker }
514*5225e6b1SAndroid Build Coastguard Worker 
515*5225e6b1SAndroid Build Coastguard Worker /// Present initialized `&mut [u8]` buffer as `&mut [MaybeUninit<u8>]`
as_uninit(buf: &[u8]) -> &[MaybeUninit<u8>]516*5225e6b1SAndroid Build Coastguard Worker pub fn as_uninit(buf: &[u8]) -> &[MaybeUninit<u8>] {
517*5225e6b1SAndroid Build Coastguard Worker     // SAFETY:
518*5225e6b1SAndroid Build Coastguard Worker     // MaybeUninit<u8> has same size and alignment as u8.
519*5225e6b1SAndroid Build Coastguard Worker     // `data` is valid pointer to initialised u8 slice of size `buf.len()`
520*5225e6b1SAndroid Build Coastguard Worker     unsafe { core::slice::from_raw_parts(buf.as_ptr() as *const MaybeUninit<u8>, buf.len()) }
521*5225e6b1SAndroid Build Coastguard Worker }
522*5225e6b1SAndroid Build Coastguard Worker 
523*5225e6b1SAndroid Build Coastguard Worker #[cfg(test)]
524*5225e6b1SAndroid Build Coastguard Worker mod test {
525*5225e6b1SAndroid Build Coastguard Worker     use super::*;
526*5225e6b1SAndroid Build Coastguard Worker     use gbl_async::block_on;
527*5225e6b1SAndroid Build Coastguard Worker     use safemath::SafeNum;
528*5225e6b1SAndroid Build Coastguard Worker 
529*5225e6b1SAndroid Build Coastguard Worker     #[derive(Debug)]
530*5225e6b1SAndroid Build Coastguard Worker     struct TestCase {
531*5225e6b1SAndroid Build Coastguard Worker         rw_offset: u64,
532*5225e6b1SAndroid Build Coastguard Worker         rw_size: u64,
533*5225e6b1SAndroid Build Coastguard Worker         misalignment: u64,
534*5225e6b1SAndroid Build Coastguard Worker         alignment: u64,
535*5225e6b1SAndroid Build Coastguard Worker         block_size: u64,
536*5225e6b1SAndroid Build Coastguard Worker         storage_size: u64,
537*5225e6b1SAndroid Build Coastguard Worker     }
538*5225e6b1SAndroid Build Coastguard Worker 
539*5225e6b1SAndroid Build Coastguard Worker     impl TestCase {
new( rw_offset: u64, rw_size: u64, misalignment: u64, alignment: u64, block_size: u64, storage_size: u64, ) -> Self540*5225e6b1SAndroid Build Coastguard Worker         fn new(
541*5225e6b1SAndroid Build Coastguard Worker             rw_offset: u64,
542*5225e6b1SAndroid Build Coastguard Worker             rw_size: u64,
543*5225e6b1SAndroid Build Coastguard Worker             misalignment: u64,
544*5225e6b1SAndroid Build Coastguard Worker             alignment: u64,
545*5225e6b1SAndroid Build Coastguard Worker             block_size: u64,
546*5225e6b1SAndroid Build Coastguard Worker             storage_size: u64,
547*5225e6b1SAndroid Build Coastguard Worker         ) -> Self {
548*5225e6b1SAndroid Build Coastguard Worker             Self { rw_offset, rw_size, misalignment, alignment, block_size, storage_size }
549*5225e6b1SAndroid Build Coastguard Worker         }
550*5225e6b1SAndroid Build Coastguard Worker     }
551*5225e6b1SAndroid Build Coastguard Worker 
552*5225e6b1SAndroid Build Coastguard Worker     // Helper object for allocating aligned buffer.
553*5225e6b1SAndroid Build Coastguard Worker     struct AlignedBuffer {
554*5225e6b1SAndroid Build Coastguard Worker         buffer: Vec<u8>,
555*5225e6b1SAndroid Build Coastguard Worker         alignment: u64,
556*5225e6b1SAndroid Build Coastguard Worker         size: u64,
557*5225e6b1SAndroid Build Coastguard Worker     }
558*5225e6b1SAndroid Build Coastguard Worker 
559*5225e6b1SAndroid Build Coastguard Worker     impl AlignedBuffer {
new(alignment: u64, size: u64) -> Self560*5225e6b1SAndroid Build Coastguard Worker         pub fn new(alignment: u64, size: u64) -> Self {
561*5225e6b1SAndroid Build Coastguard Worker             let aligned_size = (SafeNum::from(size) + alignment).try_into().unwrap();
562*5225e6b1SAndroid Build Coastguard Worker             let buffer = vec![0u8; aligned_size];
563*5225e6b1SAndroid Build Coastguard Worker             Self { buffer, alignment, size }
564*5225e6b1SAndroid Build Coastguard Worker         }
565*5225e6b1SAndroid Build Coastguard Worker 
get(&mut self) -> &mut [u8]566*5225e6b1SAndroid Build Coastguard Worker         pub fn get(&mut self) -> &mut [u8] {
567*5225e6b1SAndroid Build Coastguard Worker             let addr = SafeNum::from(self.buffer.as_ptr() as usize);
568*5225e6b1SAndroid Build Coastguard Worker             let aligned_start = addr.round_up(self.alignment) - addr;
569*5225e6b1SAndroid Build Coastguard Worker             &mut self.buffer
570*5225e6b1SAndroid Build Coastguard Worker                 [aligned_start.try_into().unwrap()..(aligned_start + self.size).try_into().unwrap()]
571*5225e6b1SAndroid Build Coastguard Worker         }
572*5225e6b1SAndroid Build Coastguard Worker     }
573*5225e6b1SAndroid Build Coastguard Worker 
574*5225e6b1SAndroid Build Coastguard Worker     /// Upper bound on the number of `read_blocks_async()/write_blocks_async()` calls by
575*5225e6b1SAndroid Build Coastguard Worker     /// `AsBlockDevice::read()` and `AsBlockDevice::write()`.
576*5225e6b1SAndroid Build Coastguard Worker     ///
577*5225e6b1SAndroid Build Coastguard Worker     /// * `fn read_aligned_all()`: At most 1 call to `read_blocks_async()`.
578*5225e6b1SAndroid Build Coastguard Worker     /// * `fn read_aligned_offset_and_buffer()`: At most 2 calls to `read_aligned_all()`.
579*5225e6b1SAndroid Build Coastguard Worker     /// * `fn read_aligned_buffer()`: At most 1 call to `read_aligned_offset_and_buffer()` plus 1
580*5225e6b1SAndroid Build Coastguard Worker     ///   call to `read_blocks_async()`.
581*5225e6b1SAndroid Build Coastguard Worker     /// * `fn read_async()`: At most 2 calls to `read_aligned_buffer()`.
582*5225e6b1SAndroid Build Coastguard Worker     ///
583*5225e6b1SAndroid Build Coastguard Worker     /// Analysis is similar for `fn write_async()`.
584*5225e6b1SAndroid Build Coastguard Worker     const READ_WRITE_BLOCKS_UPPER_BOUND: usize = 6;
585*5225e6b1SAndroid Build Coastguard Worker 
586*5225e6b1SAndroid Build Coastguard Worker     // Type alias of the [Disk] type used by unittests.
587*5225e6b1SAndroid Build Coastguard Worker     pub(crate) type TestDisk = Disk<RamBlockIo<Vec<u8>>, Vec<u8>>;
588*5225e6b1SAndroid Build Coastguard Worker 
read_test_helper(case: &TestCase)589*5225e6b1SAndroid Build Coastguard Worker     fn read_test_helper(case: &TestCase) {
590*5225e6b1SAndroid Build Coastguard Worker         let data = (0..case.storage_size).map(|v| v as u8).collect::<Vec<_>>();
591*5225e6b1SAndroid Build Coastguard Worker         let mut disk = TestDisk::new_ram_alloc(case.alignment, case.block_size, data).unwrap();
592*5225e6b1SAndroid Build Coastguard Worker         // Make an aligned buffer. A misaligned version is created by taking a sub slice that
593*5225e6b1SAndroid Build Coastguard Worker         // starts at an unaligned offset. Because of this we need to allocate
594*5225e6b1SAndroid Build Coastguard Worker         // `case.misalignment` more to accommodate it.
595*5225e6b1SAndroid Build Coastguard Worker         let mut aligned_buf = AlignedBuffer::new(case.alignment, case.rw_size + case.misalignment);
596*5225e6b1SAndroid Build Coastguard Worker         let misalignment = usize::try_from(case.misalignment).unwrap();
597*5225e6b1SAndroid Build Coastguard Worker         let rw_sz = usize::try_from(case.rw_size).unwrap();
598*5225e6b1SAndroid Build Coastguard Worker         let out = &mut aligned_buf.get()[misalignment..][..rw_sz];
599*5225e6b1SAndroid Build Coastguard Worker         block_on(disk.read(case.rw_offset, out)).unwrap();
600*5225e6b1SAndroid Build Coastguard Worker         let rw_off = usize::try_from(case.rw_offset).unwrap();
601*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(out, &disk.io().storage()[rw_off..][..rw_sz], "Failed. Test case {:?}", case);
602*5225e6b1SAndroid Build Coastguard Worker         assert!(disk.io().num_reads <= READ_WRITE_BLOCKS_UPPER_BOUND);
603*5225e6b1SAndroid Build Coastguard Worker     }
604*5225e6b1SAndroid Build Coastguard Worker 
write_test_helper( case: &TestCase, mut write_func: impl FnMut(&mut TestDisk, u64, &mut [u8]), )605*5225e6b1SAndroid Build Coastguard Worker     fn write_test_helper(
606*5225e6b1SAndroid Build Coastguard Worker         case: &TestCase,
607*5225e6b1SAndroid Build Coastguard Worker         mut write_func: impl FnMut(&mut TestDisk, u64, &mut [u8]),
608*5225e6b1SAndroid Build Coastguard Worker     ) {
609*5225e6b1SAndroid Build Coastguard Worker         let data = (0..case.storage_size).map(|v| v as u8).collect::<Vec<_>>();
610*5225e6b1SAndroid Build Coastguard Worker         // Write a reverse version of the current data.
611*5225e6b1SAndroid Build Coastguard Worker         let rw_off = usize::try_from(case.rw_offset).unwrap();
612*5225e6b1SAndroid Build Coastguard Worker         let rw_sz = usize::try_from(case.rw_size).unwrap();
613*5225e6b1SAndroid Build Coastguard Worker         let mut expected = data[rw_off..][..rw_sz].to_vec();
614*5225e6b1SAndroid Build Coastguard Worker         expected.reverse();
615*5225e6b1SAndroid Build Coastguard Worker         let mut disk = TestDisk::new_ram_alloc(case.alignment, case.block_size, data).unwrap();
616*5225e6b1SAndroid Build Coastguard Worker         // Make an aligned buffer. A misaligned version is created by taking a sub slice that
617*5225e6b1SAndroid Build Coastguard Worker         // starts at an unaligned offset. Because of this we need to allocate
618*5225e6b1SAndroid Build Coastguard Worker         // `case.misalignment` more to accommodate it.
619*5225e6b1SAndroid Build Coastguard Worker         let mut aligned_buf = AlignedBuffer::new(case.alignment, case.rw_size + case.misalignment);
620*5225e6b1SAndroid Build Coastguard Worker         let misalignment = usize::try_from(case.misalignment).unwrap();
621*5225e6b1SAndroid Build Coastguard Worker         let data = &mut aligned_buf.get()[misalignment..][..rw_sz];
622*5225e6b1SAndroid Build Coastguard Worker         data.clone_from_slice(&expected);
623*5225e6b1SAndroid Build Coastguard Worker         write_func(&mut disk, case.rw_offset, data);
624*5225e6b1SAndroid Build Coastguard Worker         let written = &disk.io().storage()[rw_off..][..rw_sz];
625*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(expected, written, "Failed. Test case {:?}", case);
626*5225e6b1SAndroid Build Coastguard Worker         // Check that input is not modified.
627*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(expected, data, "Input is modified. Test case {:?}", case,);
628*5225e6b1SAndroid Build Coastguard Worker     }
629*5225e6b1SAndroid Build Coastguard Worker 
630*5225e6b1SAndroid Build Coastguard Worker     macro_rules! read_write_test {
631*5225e6b1SAndroid Build Coastguard Worker         ($name:ident, $x0:expr, $x1:expr, $x2:expr, $x3:expr, $x4:expr, $x5:expr) => {
632*5225e6b1SAndroid Build Coastguard Worker             mod $name {
633*5225e6b1SAndroid Build Coastguard Worker                 use super::*;
634*5225e6b1SAndroid Build Coastguard Worker 
635*5225e6b1SAndroid Build Coastguard Worker                 #[test]
636*5225e6b1SAndroid Build Coastguard Worker                 fn read_test() {
637*5225e6b1SAndroid Build Coastguard Worker                     read_test_helper(&TestCase::new($x0, $x1, $x2, $x3, $x4, $x5));
638*5225e6b1SAndroid Build Coastguard Worker                 }
639*5225e6b1SAndroid Build Coastguard Worker 
640*5225e6b1SAndroid Build Coastguard Worker                 #[test]
641*5225e6b1SAndroid Build Coastguard Worker                 fn read_scaled_test() {
642*5225e6b1SAndroid Build Coastguard Worker                     // Scaled all parameters by double and test again.
643*5225e6b1SAndroid Build Coastguard Worker                     let (x0, x1, x2, x3, x4, x5) =
644*5225e6b1SAndroid Build Coastguard Worker                         (2 * $x0, 2 * $x1, 2 * $x2, 2 * $x3, 2 * $x4, 2 * $x5);
645*5225e6b1SAndroid Build Coastguard Worker                     read_test_helper(&TestCase::new(x0, x1, x2, x3, x4, x5));
646*5225e6b1SAndroid Build Coastguard Worker                 }
647*5225e6b1SAndroid Build Coastguard Worker 
648*5225e6b1SAndroid Build Coastguard Worker                 // Input bytes slice is a mutable reference
649*5225e6b1SAndroid Build Coastguard Worker                 #[test]
650*5225e6b1SAndroid Build Coastguard Worker                 fn write_mut_test() {
651*5225e6b1SAndroid Build Coastguard Worker                     write_test_helper(
652*5225e6b1SAndroid Build Coastguard Worker                         &TestCase::new($x0, $x1, $x2, $x3, $x4, $x5),
653*5225e6b1SAndroid Build Coastguard Worker                         |blk, offset, data| {
654*5225e6b1SAndroid Build Coastguard Worker                             block_on(blk.write(offset, data)).unwrap();
655*5225e6b1SAndroid Build Coastguard Worker                             assert!(blk.io().num_reads <= READ_WRITE_BLOCKS_UPPER_BOUND);
656*5225e6b1SAndroid Build Coastguard Worker                             assert!(blk.io().num_writes <= READ_WRITE_BLOCKS_UPPER_BOUND);
657*5225e6b1SAndroid Build Coastguard Worker                         },
658*5225e6b1SAndroid Build Coastguard Worker                     );
659*5225e6b1SAndroid Build Coastguard Worker                 }
660*5225e6b1SAndroid Build Coastguard Worker 
661*5225e6b1SAndroid Build Coastguard Worker                 #[test]
662*5225e6b1SAndroid Build Coastguard Worker                 fn write_mut_scaled_test() {
663*5225e6b1SAndroid Build Coastguard Worker                     // Scaled all parameters by double and test again.
664*5225e6b1SAndroid Build Coastguard Worker                     let (x0, x1, x2, x3, x4, x5) =
665*5225e6b1SAndroid Build Coastguard Worker                         (2 * $x0, 2 * $x1, 2 * $x2, 2 * $x3, 2 * $x4, 2 * $x5);
666*5225e6b1SAndroid Build Coastguard Worker                     write_test_helper(
667*5225e6b1SAndroid Build Coastguard Worker                         &TestCase::new(x0, x1, x2, x3, x4, x5),
668*5225e6b1SAndroid Build Coastguard Worker                         |blk, offset, data| {
669*5225e6b1SAndroid Build Coastguard Worker                             block_on(blk.write(offset, data)).unwrap();
670*5225e6b1SAndroid Build Coastguard Worker                             assert!(blk.io().num_reads <= READ_WRITE_BLOCKS_UPPER_BOUND);
671*5225e6b1SAndroid Build Coastguard Worker                             assert!(blk.io().num_writes <= READ_WRITE_BLOCKS_UPPER_BOUND);
672*5225e6b1SAndroid Build Coastguard Worker                         },
673*5225e6b1SAndroid Build Coastguard Worker                     );
674*5225e6b1SAndroid Build Coastguard Worker                 }
675*5225e6b1SAndroid Build Coastguard Worker             }
676*5225e6b1SAndroid Build Coastguard Worker         };
677*5225e6b1SAndroid Build Coastguard Worker     }
678*5225e6b1SAndroid Build Coastguard Worker 
679*5225e6b1SAndroid Build Coastguard Worker     const BLOCK_SIZE: u64 = 512;
680*5225e6b1SAndroid Build Coastguard Worker     const ALIGNMENT: u64 = 64;
681*5225e6b1SAndroid Build Coastguard Worker     const STORAGE: u64 = BLOCK_SIZE * 32;
682*5225e6b1SAndroid Build Coastguard Worker 
683*5225e6b1SAndroid Build Coastguard Worker     // Test cases for different scenarios of read/write windows w.r.t buffer/block alignmnet
684*5225e6b1SAndroid Build Coastguard Worker     // boundary.
685*5225e6b1SAndroid Build Coastguard Worker     // offset
686*5225e6b1SAndroid Build Coastguard Worker     //   |~~~~~~~~~~~~~size~~~~~~~~~~~~|
687*5225e6b1SAndroid Build Coastguard Worker     //   |---------|---------|---------|
688*5225e6b1SAndroid Build Coastguard Worker     read_write_test! {aligned_all, 0, STORAGE, 0, ALIGNMENT, BLOCK_SIZE, STORAGE
689*5225e6b1SAndroid Build Coastguard Worker     }
690*5225e6b1SAndroid Build Coastguard Worker 
691*5225e6b1SAndroid Build Coastguard Worker     // offset
692*5225e6b1SAndroid Build Coastguard Worker     //   |~~~~~~~~~size~~~~~~~~~|
693*5225e6b1SAndroid Build Coastguard Worker     //   |---------|---------|---------|
694*5225e6b1SAndroid Build Coastguard Worker     read_write_test! {
695*5225e6b1SAndroid Build Coastguard Worker         aligned_offset_uanligned_size, 0, STORAGE - 1, 0, ALIGNMENT, BLOCK_SIZE, STORAGE
696*5225e6b1SAndroid Build Coastguard Worker     }
697*5225e6b1SAndroid Build Coastguard Worker     // offset
698*5225e6b1SAndroid Build Coastguard Worker     //   |~~size~~|
699*5225e6b1SAndroid Build Coastguard Worker     //   |---------|---------|---------|
700*5225e6b1SAndroid Build Coastguard Worker     read_write_test! {
701*5225e6b1SAndroid Build Coastguard Worker         aligned_offset_intra_block, 0, BLOCK_SIZE - 1, 0, ALIGNMENT, BLOCK_SIZE, STORAGE
702*5225e6b1SAndroid Build Coastguard Worker     }
703*5225e6b1SAndroid Build Coastguard Worker     //     offset
704*5225e6b1SAndroid Build Coastguard Worker     //       |~~~~~~~~~~~size~~~~~~~~~~|
705*5225e6b1SAndroid Build Coastguard Worker     //   |---------|---------|---------|
706*5225e6b1SAndroid Build Coastguard Worker     read_write_test! {
707*5225e6b1SAndroid Build Coastguard Worker         unaligned_offset_aligned_end, 1, STORAGE - 1, 0, ALIGNMENT, BLOCK_SIZE, STORAGE
708*5225e6b1SAndroid Build Coastguard Worker     }
709*5225e6b1SAndroid Build Coastguard Worker     //     offset
710*5225e6b1SAndroid Build Coastguard Worker     //       |~~~~~~~~~size~~~~~~~~|
711*5225e6b1SAndroid Build Coastguard Worker     //   |---------|---------|---------|
712*5225e6b1SAndroid Build Coastguard Worker     read_write_test! {unaligned_offset_len, 1, STORAGE - 2, 0, ALIGNMENT, BLOCK_SIZE, STORAGE
713*5225e6b1SAndroid Build Coastguard Worker     }
714*5225e6b1SAndroid Build Coastguard Worker     //     offset
715*5225e6b1SAndroid Build Coastguard Worker     //       |~~~size~~~|
716*5225e6b1SAndroid Build Coastguard Worker     //   |---------|---------|---------|
717*5225e6b1SAndroid Build Coastguard Worker     read_write_test! {
718*5225e6b1SAndroid Build Coastguard Worker         unaligned_offset_len_partial_cross_block, 1, BLOCK_SIZE, 0, ALIGNMENT, BLOCK_SIZE, STORAGE
719*5225e6b1SAndroid Build Coastguard Worker     }
720*5225e6b1SAndroid Build Coastguard Worker     //   offset
721*5225e6b1SAndroid Build Coastguard Worker     //     |~size~|
722*5225e6b1SAndroid Build Coastguard Worker     //   |---------|---------|---------|
723*5225e6b1SAndroid Build Coastguard Worker     read_write_test! {
724*5225e6b1SAndroid Build Coastguard Worker         ualigned_offset_len_partial_intra_block,
725*5225e6b1SAndroid Build Coastguard Worker         1,
726*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE - 2,
727*5225e6b1SAndroid Build Coastguard Worker         0,
728*5225e6b1SAndroid Build Coastguard Worker         ALIGNMENT,
729*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE,
730*5225e6b1SAndroid Build Coastguard Worker         STORAGE
731*5225e6b1SAndroid Build Coastguard Worker     }
732*5225e6b1SAndroid Build Coastguard Worker 
733*5225e6b1SAndroid Build Coastguard Worker     // Same sets of test cases but with an additional block added to `rw_offset`
734*5225e6b1SAndroid Build Coastguard Worker     read_write_test! {
735*5225e6b1SAndroid Build Coastguard Worker         aligned_all_extra_offset,
736*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE,
737*5225e6b1SAndroid Build Coastguard Worker         STORAGE,
738*5225e6b1SAndroid Build Coastguard Worker         0,
739*5225e6b1SAndroid Build Coastguard Worker         ALIGNMENT,
740*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE,
741*5225e6b1SAndroid Build Coastguard Worker         STORAGE + BLOCK_SIZE
742*5225e6b1SAndroid Build Coastguard Worker     }
743*5225e6b1SAndroid Build Coastguard Worker     read_write_test! {
744*5225e6b1SAndroid Build Coastguard Worker         aligned_offset_uanligned_size_extra_offset,
745*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE,
746*5225e6b1SAndroid Build Coastguard Worker         STORAGE - 1,
747*5225e6b1SAndroid Build Coastguard Worker         0,
748*5225e6b1SAndroid Build Coastguard Worker         ALIGNMENT,
749*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE,
750*5225e6b1SAndroid Build Coastguard Worker         STORAGE + BLOCK_SIZE
751*5225e6b1SAndroid Build Coastguard Worker     }
752*5225e6b1SAndroid Build Coastguard Worker     read_write_test! {
753*5225e6b1SAndroid Build Coastguard Worker         aligned_offset_intra_block_extra_offset,
754*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE,
755*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE - 1,
756*5225e6b1SAndroid Build Coastguard Worker         0,
757*5225e6b1SAndroid Build Coastguard Worker         ALIGNMENT,
758*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE,
759*5225e6b1SAndroid Build Coastguard Worker         STORAGE + BLOCK_SIZE
760*5225e6b1SAndroid Build Coastguard Worker     }
761*5225e6b1SAndroid Build Coastguard Worker     read_write_test! {
762*5225e6b1SAndroid Build Coastguard Worker         unaligned_offset_aligned_end_extra_offset,
763*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE + 1,
764*5225e6b1SAndroid Build Coastguard Worker         STORAGE - 1,
765*5225e6b1SAndroid Build Coastguard Worker         0,
766*5225e6b1SAndroid Build Coastguard Worker         ALIGNMENT,
767*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE,
768*5225e6b1SAndroid Build Coastguard Worker         STORAGE + BLOCK_SIZE
769*5225e6b1SAndroid Build Coastguard Worker     }
770*5225e6b1SAndroid Build Coastguard Worker     read_write_test! {
771*5225e6b1SAndroid Build Coastguard Worker         unaligned_offset_len_extra_offset,
772*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE + 1,
773*5225e6b1SAndroid Build Coastguard Worker         STORAGE - 2,
774*5225e6b1SAndroid Build Coastguard Worker         0,
775*5225e6b1SAndroid Build Coastguard Worker         ALIGNMENT,
776*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE,
777*5225e6b1SAndroid Build Coastguard Worker         STORAGE + BLOCK_SIZE
778*5225e6b1SAndroid Build Coastguard Worker     }
779*5225e6b1SAndroid Build Coastguard Worker     read_write_test! {
780*5225e6b1SAndroid Build Coastguard Worker         unaligned_offset_len_partial_cross_block_extra_offset,
781*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE + 1,
782*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE,
783*5225e6b1SAndroid Build Coastguard Worker         0,
784*5225e6b1SAndroid Build Coastguard Worker         ALIGNMENT,
785*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE,
786*5225e6b1SAndroid Build Coastguard Worker         STORAGE + BLOCK_SIZE
787*5225e6b1SAndroid Build Coastguard Worker     }
788*5225e6b1SAndroid Build Coastguard Worker     read_write_test! {
789*5225e6b1SAndroid Build Coastguard Worker         ualigned_offset_len_partial_intra_block_extra_offset,
790*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE + 1,
791*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE - 2,
792*5225e6b1SAndroid Build Coastguard Worker         0,
793*5225e6b1SAndroid Build Coastguard Worker         ALIGNMENT,
794*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE,
795*5225e6b1SAndroid Build Coastguard Worker         STORAGE + BLOCK_SIZE
796*5225e6b1SAndroid Build Coastguard Worker     }
797*5225e6b1SAndroid Build Coastguard Worker 
798*5225e6b1SAndroid Build Coastguard Worker     // Same sets of test cases but with unaligned output buffer {'misALIGNMENT` != 0}
799*5225e6b1SAndroid Build Coastguard Worker     read_write_test! {
800*5225e6b1SAndroid Build Coastguard Worker         aligned_all_unaligned_buffer,
801*5225e6b1SAndroid Build Coastguard Worker         0,
802*5225e6b1SAndroid Build Coastguard Worker         STORAGE,
803*5225e6b1SAndroid Build Coastguard Worker         1,
804*5225e6b1SAndroid Build Coastguard Worker         ALIGNMENT,
805*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE,
806*5225e6b1SAndroid Build Coastguard Worker         STORAGE
807*5225e6b1SAndroid Build Coastguard Worker     }
808*5225e6b1SAndroid Build Coastguard Worker     read_write_test! {
809*5225e6b1SAndroid Build Coastguard Worker         aligned_offset_uanligned_size_unaligned_buffer,
810*5225e6b1SAndroid Build Coastguard Worker         0,
811*5225e6b1SAndroid Build Coastguard Worker         STORAGE - 1,
812*5225e6b1SAndroid Build Coastguard Worker         1,
813*5225e6b1SAndroid Build Coastguard Worker         ALIGNMENT,
814*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE,
815*5225e6b1SAndroid Build Coastguard Worker         STORAGE
816*5225e6b1SAndroid Build Coastguard Worker     }
817*5225e6b1SAndroid Build Coastguard Worker     read_write_test! {
818*5225e6b1SAndroid Build Coastguard Worker         aligned_offset_intra_block_unaligned_buffer,
819*5225e6b1SAndroid Build Coastguard Worker         0,
820*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE - 1,
821*5225e6b1SAndroid Build Coastguard Worker         1,
822*5225e6b1SAndroid Build Coastguard Worker         ALIGNMENT,
823*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE,
824*5225e6b1SAndroid Build Coastguard Worker         STORAGE
825*5225e6b1SAndroid Build Coastguard Worker     }
826*5225e6b1SAndroid Build Coastguard Worker     read_write_test! {
827*5225e6b1SAndroid Build Coastguard Worker         unaligned_offset_aligned_end_unaligned_buffer,
828*5225e6b1SAndroid Build Coastguard Worker         1,
829*5225e6b1SAndroid Build Coastguard Worker         STORAGE - 1,
830*5225e6b1SAndroid Build Coastguard Worker         1,
831*5225e6b1SAndroid Build Coastguard Worker         ALIGNMENT,
832*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE,
833*5225e6b1SAndroid Build Coastguard Worker         STORAGE
834*5225e6b1SAndroid Build Coastguard Worker     }
835*5225e6b1SAndroid Build Coastguard Worker     read_write_test! {
836*5225e6b1SAndroid Build Coastguard Worker         unaligned_offset_len_unaligned_buffer,
837*5225e6b1SAndroid Build Coastguard Worker         1,
838*5225e6b1SAndroid Build Coastguard Worker         STORAGE - 2,
839*5225e6b1SAndroid Build Coastguard Worker         1,
840*5225e6b1SAndroid Build Coastguard Worker         ALIGNMENT,
841*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE,
842*5225e6b1SAndroid Build Coastguard Worker         STORAGE
843*5225e6b1SAndroid Build Coastguard Worker     }
844*5225e6b1SAndroid Build Coastguard Worker     read_write_test! {
845*5225e6b1SAndroid Build Coastguard Worker         unaligned_offset_len_partial_cross_block_unaligned_buffer,
846*5225e6b1SAndroid Build Coastguard Worker         1,
847*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE,
848*5225e6b1SAndroid Build Coastguard Worker         1,
849*5225e6b1SAndroid Build Coastguard Worker         ALIGNMENT,
850*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE,
851*5225e6b1SAndroid Build Coastguard Worker         STORAGE
852*5225e6b1SAndroid Build Coastguard Worker     }
853*5225e6b1SAndroid Build Coastguard Worker     read_write_test! {
854*5225e6b1SAndroid Build Coastguard Worker         ualigned_offset_len_partial_intra_block_unaligned_buffer,
855*5225e6b1SAndroid Build Coastguard Worker         1,
856*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE - 2,
857*5225e6b1SAndroid Build Coastguard Worker         1,
858*5225e6b1SAndroid Build Coastguard Worker         ALIGNMENT,
859*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE,
860*5225e6b1SAndroid Build Coastguard Worker         STORAGE
861*5225e6b1SAndroid Build Coastguard Worker     }
862*5225e6b1SAndroid Build Coastguard Worker 
863*5225e6b1SAndroid Build Coastguard Worker     // Special cases where `rw_offset` is not block aligned but buffer aligned. This can
864*5225e6b1SAndroid Build Coastguard Worker     // trigger some internal optimization code path.
865*5225e6b1SAndroid Build Coastguard Worker     read_write_test! {
866*5225e6b1SAndroid Build Coastguard Worker         buffer_aligned_offset_and_len,
867*5225e6b1SAndroid Build Coastguard Worker         ALIGNMENT,
868*5225e6b1SAndroid Build Coastguard Worker         STORAGE - ALIGNMENT,
869*5225e6b1SAndroid Build Coastguard Worker         0,
870*5225e6b1SAndroid Build Coastguard Worker         ALIGNMENT,
871*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE,
872*5225e6b1SAndroid Build Coastguard Worker         STORAGE
873*5225e6b1SAndroid Build Coastguard Worker     }
874*5225e6b1SAndroid Build Coastguard Worker     read_write_test! {
875*5225e6b1SAndroid Build Coastguard Worker         buffer_aligned_offset,
876*5225e6b1SAndroid Build Coastguard Worker         ALIGNMENT,
877*5225e6b1SAndroid Build Coastguard Worker         STORAGE - ALIGNMENT - 1,
878*5225e6b1SAndroid Build Coastguard Worker         0,
879*5225e6b1SAndroid Build Coastguard Worker         ALIGNMENT,
880*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE,
881*5225e6b1SAndroid Build Coastguard Worker         STORAGE
882*5225e6b1SAndroid Build Coastguard Worker     }
883*5225e6b1SAndroid Build Coastguard Worker     read_write_test! {
884*5225e6b1SAndroid Build Coastguard Worker         buffer_aligned_offset_aligned_end,
885*5225e6b1SAndroid Build Coastguard Worker         ALIGNMENT,
886*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE,
887*5225e6b1SAndroid Build Coastguard Worker         0,
888*5225e6b1SAndroid Build Coastguard Worker         ALIGNMENT,
889*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE,
890*5225e6b1SAndroid Build Coastguard Worker         STORAGE
891*5225e6b1SAndroid Build Coastguard Worker     }
892*5225e6b1SAndroid Build Coastguard Worker     read_write_test! {
893*5225e6b1SAndroid Build Coastguard Worker         buffer_aligned_offset_intra_block,
894*5225e6b1SAndroid Build Coastguard Worker         ALIGNMENT,
895*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE - ALIGNMENT - 1,
896*5225e6b1SAndroid Build Coastguard Worker         0,
897*5225e6b1SAndroid Build Coastguard Worker         ALIGNMENT,
898*5225e6b1SAndroid Build Coastguard Worker         BLOCK_SIZE,
899*5225e6b1SAndroid Build Coastguard Worker         STORAGE
900*5225e6b1SAndroid Build Coastguard Worker     }
901*5225e6b1SAndroid Build Coastguard Worker 
902*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_no_alignment_require_zero_size_scratch()903*5225e6b1SAndroid Build Coastguard Worker     fn test_no_alignment_require_zero_size_scratch() {
904*5225e6b1SAndroid Build Coastguard Worker         let mut io = RamBlockIo::new(1, 1, vec![]);
905*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(scratch_size(&mut io).unwrap(), 0);
906*5225e6b1SAndroid Build Coastguard Worker     }
907*5225e6b1SAndroid Build Coastguard Worker 
908*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_scratch_too_small()909*5225e6b1SAndroid Build Coastguard Worker     fn test_scratch_too_small() {
910*5225e6b1SAndroid Build Coastguard Worker         let mut io = RamBlockIo::new(512, 512, vec![]);
911*5225e6b1SAndroid Build Coastguard Worker         let scratch = vec![0u8; scratch_size(&mut io).unwrap() - 1];
912*5225e6b1SAndroid Build Coastguard Worker         assert!(TestDisk::new(io, scratch).is_err());
913*5225e6b1SAndroid Build Coastguard Worker     }
914*5225e6b1SAndroid Build Coastguard Worker 
915*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_read_overflow()916*5225e6b1SAndroid Build Coastguard Worker     fn test_read_overflow() {
917*5225e6b1SAndroid Build Coastguard Worker         let mut disk = TestDisk::new_ram_alloc(512, 512, vec![0u8; 512]).unwrap();
918*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(disk.read(512, &mut vec![0u8; 1][..])).is_err());
919*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(disk.read(0, &mut vec![0u8; 513][..])).is_err());
920*5225e6b1SAndroid Build Coastguard Worker     }
921*5225e6b1SAndroid Build Coastguard Worker 
922*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_read_arithmetic_overflow()923*5225e6b1SAndroid Build Coastguard Worker     fn test_read_arithmetic_overflow() {
924*5225e6b1SAndroid Build Coastguard Worker         let mut disk = TestDisk::new_ram_alloc(512, 512, vec![0u8; 512]).unwrap();
925*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(disk.read(u64::MAX, &mut vec![0u8; 1][..])).is_err());
926*5225e6b1SAndroid Build Coastguard Worker     }
927*5225e6b1SAndroid Build Coastguard Worker 
928*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_write_overflow()929*5225e6b1SAndroid Build Coastguard Worker     fn test_write_overflow() {
930*5225e6b1SAndroid Build Coastguard Worker         let mut disk = TestDisk::new_ram_alloc(512, 512, vec![0u8; 512]).unwrap();
931*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(disk.write(512, &mut vec![0u8; 1])).is_err());
932*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(disk.write(0, &mut vec![0u8; 513])).is_err());
933*5225e6b1SAndroid Build Coastguard Worker     }
934*5225e6b1SAndroid Build Coastguard Worker 
935*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_write_arithmetic_overflow()936*5225e6b1SAndroid Build Coastguard Worker     fn test_write_arithmetic_overflow() {
937*5225e6b1SAndroid Build Coastguard Worker         let mut disk = TestDisk::new_ram_alloc(512, 512, vec![0u8; 512]).unwrap();
938*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(disk.write(u64::MAX, &mut vec![0u8; 1])).is_err());
939*5225e6b1SAndroid Build Coastguard Worker     }
940*5225e6b1SAndroid Build Coastguard Worker }
941