storage_device/
ranged_device.rs1use crate::buffer::{BufferRef, MutableBufferRef};
6use crate::buffer_allocator::BufferFuture;
7use crate::{Device, ReadOptions, WriteOptions};
8use anyhow::{Error, anyhow, bail, ensure};
9use async_trait::async_trait;
10use std::ops::Range;
11use std::sync::Arc;
12
13pub struct RangedDevice {
15 source: Arc<dyn Device>,
17 range: Range<u64>,
19}
20
21impl RangedDevice {
22 pub fn new(source: Arc<dyn Device>, range: Range<u64>) -> Result<Self, Error> {
25 let block_size = source.block_size() as u64;
26 ensure!(range.start % block_size == 0, "range.start must be block aligned");
27 ensure!(range.end % block_size == 0, "range.end must be block aligned");
28 ensure!(
29 range.end <= source.block_count() * block_size,
30 "failed to create RangedDevice (out of range)"
31 );
32 ensure!(range.end > range.start, "failed to create RangedDevice (no size)");
33 Ok(Self { source: source.clone(), range })
34 }
35
36 fn num_blocks(&self) -> u64 {
37 (self.range.end - self.range.start) / self.block_size() as u64
38 }
39}
40
41#[async_trait]
42impl Device for RangedDevice {
43 fn allocate_buffer(&self, size: usize) -> BufferFuture<'_> {
44 self.source.allocate_buffer(size)
45 }
46
47 fn block_size(&self) -> u32 {
48 self.source.block_size()
49 }
50
51 fn block_count(&self) -> u64 {
52 self.num_blocks()
53 }
54
55 async fn read_with_opts(
56 &self,
57 offset: u64,
58 buffer: MutableBufferRef<'_>,
59 _read_opts: ReadOptions,
60 ) -> Result<(), Error> {
61 let adjusted_offset = self
62 .range
63 .start
64 .checked_add(offset)
65 .ok_or_else(|| anyhow!("arithmetic overflow calculating offset"))?;
66 ensure!(
67 adjusted_offset + buffer.len() as u64 <= self.range.end,
68 "reading past end of device"
69 );
70 self.source.read(adjusted_offset, buffer).await
71 }
72
73 async fn write_with_opts(
74 &self,
75 offset: u64,
76 buffer: BufferRef<'_>,
77 opts: WriteOptions,
78 ) -> Result<(), Error> {
79 let adjusted_offset = self
80 .range
81 .start
82 .checked_add(offset)
83 .ok_or_else(|| anyhow!("arithmetic overflow calculating offset"))?;
84 ensure!(
85 adjusted_offset + buffer.len() as u64 <= self.range.end,
86 "writing past end of device"
87 );
88 self.source.write_with_opts(adjusted_offset, buffer, opts).await
89 }
90
91 async fn trim(&self, _range: Range<u64>) -> Result<(), Error> {
92 bail!("RangedDevice does not support trim");
93 }
94
95 async fn close(&self) -> Result<(), Error> {
96 self.source.close().await
97 }
98
99 async fn flush(&self) -> Result<(), Error> {
100 self.source.flush().await
101 }
102
103 fn is_read_only(&self) -> bool {
104 self.source.is_read_only()
105 }
106
107 fn supports_trim(&self) -> bool {
108 false
109 }
110
111 fn reopen(&self, read_only: bool) {
112 self.source.reopen(read_only)
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::RangedDevice;
119 use crate::Device;
120 use crate::fake_device::FakeDevice;
121 use std::sync::Arc;
122
123 #[fuchsia::test]
124 async fn test_ranged_device_reads() {
125 const BLOCK_SIZE: usize = 512;
126 let device = Arc::new(FakeDevice::new(8, BLOCK_SIZE as u32));
127
128 let mut buffer = device.allocate_buffer(BLOCK_SIZE).await;
129 buffer.fill(1);
130 device.write(BLOCK_SIZE as u64, buffer.as_ref()).await.expect("failed to write to device");
131
132 buffer.fill(2);
133 device
134 .write(2 * BLOCK_SIZE as u64, buffer.as_ref())
135 .await
136 .expect("failed to write to device");
137
138 let sub_device =
140 RangedDevice::new(device.clone(), BLOCK_SIZE as u64..4 * BLOCK_SIZE as u64)
141 .expect("failed to create new RangedDevice");
142
143 let mut ranged_device_buffer = sub_device.allocate_buffer(BLOCK_SIZE).await;
145 sub_device
146 .read(0, ranged_device_buffer.as_mut())
147 .await
148 .expect("failed to read from RangedDevice");
149 let mut data = [0u8; 512];
150 ranged_device_buffer.copy_to_slice(&mut data);
151 assert_eq!(data, [1; 512]);
152
153 sub_device
154 .read(BLOCK_SIZE as u64, ranged_device_buffer.as_mut())
155 .await
156 .expect("failed to read from RangedDevice");
157 let mut data = [0u8; 512];
158 ranged_device_buffer.copy_to_slice(&mut data);
159 assert_eq!(data, [2; 512]);
160
161 sub_device
162 .read(2 * BLOCK_SIZE as u64, ranged_device_buffer.as_mut())
163 .await
164 .expect("failed to read from RangedDevice");
165 let mut data = [0u8; 512];
166 ranged_device_buffer.copy_to_slice(&mut data);
167 assert_eq!(data, [0; 512]);
168
169 sub_device
170 .read(3 * BLOCK_SIZE as u64, ranged_device_buffer.as_mut())
171 .await
172 .expect_err("unexepectedly passed reading out of range of RangedDevice");
173 }
174
175 #[fuchsia::test]
176 async fn test_ranged_device_writes() {
177 const BLOCK_SIZE: usize = 512;
178 let device = Arc::new(FakeDevice::new(8, BLOCK_SIZE as u32));
179
180 let block_offset = 1;
182 let sub_device = RangedDevice::new(
183 device.clone(),
184 block_offset * BLOCK_SIZE as u64..(block_offset + 3) * BLOCK_SIZE as u64,
185 )
186 .expect("failed to create new RangedDevice");
187
188 let mut invalid_buffer = sub_device.allocate_buffer(4 * BLOCK_SIZE).await;
189 invalid_buffer.fill(3);
190 sub_device
191 .write(0, invalid_buffer.as_ref())
192 .await
193 .expect_err("unexpectedly passed writing a buffer that is too big");
194
195 let mut write_buffer = sub_device.allocate_buffer(BLOCK_SIZE).await;
196 write_buffer.fill(3);
197 let write_block_offset = 2;
198 sub_device
199 .write(write_block_offset * BLOCK_SIZE as u64, write_buffer.as_ref())
200 .await
201 .expect("failed to write to RangedDevice");
202
203 let mut read_buffer = device.allocate_buffer(BLOCK_SIZE).await;
205 device
206 .read((block_offset + write_block_offset) * BLOCK_SIZE as u64, read_buffer.as_mut())
207 .await
208 .expect("failed to read from device");
209 let mut data = [0u8; 512];
210 read_buffer.copy_to_slice(&mut data);
211 assert_eq!(data, [3; 512]);
212 }
213}