1use crate::Device;
6use crate::buffer::{BufferFuture, BufferRef, MutableBufferRef};
7use crate::buffer_allocator::{BufferAllocator, BufferSource};
8use anyhow::{Error, bail, ensure};
9use async_trait::async_trait;
10use block_client::{
11 BlockClient, BlockDeviceFlag, BufferSlice, MutableBufferSlice, ReadOptions, VmoId, WriteOptions,
12};
13use std::ops::Range;
14use zx::Status;
15
16pub struct BlockDevice<T> {
18 allocator: BufferAllocator,
19 remote: T,
20 read_only: bool,
21 vmoid: VmoId,
22}
23
24const TRANSFER_VMO_SIZE: usize = 128 * 1024 * 1024;
25
26impl<T: BlockClient> BlockDevice<T> {
27 pub async fn new(remote: T, read_only: bool) -> Result<Self, Error> {
29 let buffer_source = BufferSource::new(TRANSFER_VMO_SIZE);
30 let vmoid = unsafe { remote.attach_vmo(buffer_source.vmo()) }.await?;
33 let allocator = BufferAllocator::new(remote.block_size() as usize, buffer_source);
34 Ok(Self { allocator, remote, read_only, vmoid })
35 }
36
37 async fn read_with_opts_internal(
38 &self,
39 offset: u64,
40 buffer: MutableBufferRef<'_>,
41 read_opts: ReadOptions,
42 ) -> Result<(), Error> {
43 if buffer.len() == 0 {
44 return Ok(());
45 }
46 ensure!(self.vmoid.is_valid(), Status::INVALID_ARGS);
47 ensure!(offset % (self.block_size() as u64) == 0, Status::INVALID_ARGS);
48 ensure!(buffer.range().start % (self.block_size() as usize) == 0, Status::INVALID_ARGS);
49 ensure!(buffer.range().end % (self.block_size() as usize) == 0, Status::INVALID_ARGS);
50 Ok(self
51 .remote
52 .read_at_with_opts(
53 MutableBufferSlice::new_with_vmo_id(
54 &self.vmoid,
55 buffer.range().start as u64,
56 buffer.len() as u64,
57 ),
58 offset,
59 read_opts,
60 )
61 .await?)
62 }
63
64 async fn write_with_opts_internal(
65 &self,
66 offset: u64,
67 buffer: BufferRef<'_>,
68 opts: WriteOptions,
69 ) -> Result<(), Error> {
70 if self.read_only {
71 bail!(Status::ACCESS_DENIED);
72 }
73 if buffer.len() == 0 {
74 return Ok(());
75 }
76 ensure!(self.vmoid.is_valid(), "Device is closed");
77 ensure!(offset % (self.block_size() as u64) == 0, Status::INVALID_ARGS);
78 ensure!(buffer.range().start % (self.block_size() as usize) == 0, Status::INVALID_ARGS);
79 ensure!(buffer.range().end % (self.block_size() as usize) == 0, Status::INVALID_ARGS);
80 Ok(self
81 .remote
82 .write_at_with_opts(
83 BufferSlice::new_with_vmo_id(
84 &self.vmoid,
85 buffer.range().start as u64,
86 buffer.len() as u64,
87 ),
88 offset,
89 opts,
90 )
91 .await?)
92 }
93}
94
95#[async_trait]
96impl<T: BlockClient> Device for BlockDevice<T> {
97 fn allocate_buffer(&self, size: usize) -> BufferFuture<'_> {
98 self.allocator.allocate_buffer(size)
99 }
100
101 fn clean_transfer_buffer(&self) {
102 self.allocator.clean_transfer_buffer();
103 }
104
105 fn block_size(&self) -> u32 {
106 self.remote.block_size()
107 }
108
109 fn block_count(&self) -> u64 {
110 self.remote.block_count()
111 }
112
113 async fn read_with_opts(
114 &self,
115 offset: u64,
116 mut buffer: MutableBufferRef<'_>,
117 read_opts: ReadOptions,
118 ) -> Result<(), Error> {
119 if buffer.allocator_id() != self.allocator.identifier() {
120 let mut temp_buf = self.allocator.allocate_buffer(buffer.len()).await;
122 self.read_with_opts_internal(offset, temp_buf.as_mut(), read_opts).await?;
123 buffer.as_mut_ptr_slice().copy_from_ptr_slice(temp_buf.as_ptr_slice());
124 Ok(())
125 } else {
126 self.read_with_opts_internal(offset, buffer, read_opts).await
127 }
128 }
129
130 async fn write_with_opts(
131 &self,
132 offset: u64,
133 buffer: BufferRef<'_>,
134 opts: WriteOptions,
135 ) -> Result<(), Error> {
136 if buffer.allocator_id() != self.allocator.identifier() {
137 let mut temp_buf = self.allocator.allocate_buffer(buffer.len()).await;
139 temp_buf.as_mut().as_mut_ptr_slice().copy_from_ptr_slice(buffer.as_ptr_slice());
140 self.write_with_opts_internal(offset, temp_buf.as_ref(), opts).await
141 } else {
142 self.write_with_opts_internal(offset, buffer, opts).await
143 }
144 }
145
146 async fn trim(&self, range: Range<u64>) -> Result<(), Error> {
147 if self.read_only {
148 bail!(Status::ACCESS_DENIED);
149 }
150 ensure!(range.start % (self.block_size() as u64) == 0, Status::INVALID_ARGS);
151 ensure!(range.end % (self.block_size() as u64) == 0, Status::INVALID_ARGS);
152 Ok(self.remote.trim(range).await?)
153 }
154
155 async fn close(&self) -> Result<(), Error> {
156 let _ = self.vmoid.take().into_id();
158 Ok(self.remote.close().await?)
159 }
160
161 async fn flush(&self) -> Result<(), Error> {
162 Ok(self.remote.flush().await?)
163 }
164
165 fn is_read_only(&self) -> bool {
166 self.read_only
167 }
168
169 fn supports_trim(&self) -> bool {
170 self.remote.block_flags().contains(BlockDeviceFlag::TRIM_SUPPORT)
171 }
172
173 async fn connect_mapper(
174 &self,
175 server_end: fidl::endpoints::ServerEnd<fidl_fuchsia_storage_block::MapperMarker>,
176 ) -> Result<(), Status> {
177 self.remote.connect_mapper(server_end).await
178 }
179}
180
181impl<T> Drop for BlockDevice<T> {
182 fn drop(&mut self) {
183 let _ = self.vmoid.take().into_id();
186 }
187}
188
189#[cfg(test)]
190mod tests {
191 use crate::Device;
192 use crate::block_device::BlockDevice;
193 use fake_block_client::FakeBlockClient;
194 use zx::Status;
195
196 #[fuchsia::test]
197 async fn test_lifecycle() {
198 let device =
199 BlockDevice::new(FakeBlockClient::new(1024, 1024), false).await.expect("new failed");
200
201 {
202 let _buf = device.allocate_buffer(8192).await;
203 }
204
205 device.close().await.expect("Close failed");
206 }
207
208 #[fuchsia::test]
209 async fn test_read_write_buffer() {
210 let device =
211 BlockDevice::new(FakeBlockClient::new(1024, 1024), false).await.expect("new failed");
212
213 {
214 let mut buf1 = device.allocate_buffer(8192).await;
215 let mut buf2 = device.allocate_buffer(1024).await;
216 buf1.fill(0xaa);
217 buf2.fill(0xbb);
218 device.write(65536, buf1.as_ref()).await.expect("Write failed");
219 device.write(65536 + 8192, buf2.as_ref()).await.expect("Write failed");
220 }
221 {
222 let mut buf = device.allocate_buffer(8192 + 1024).await;
223 device.read(65536, buf.as_mut()).await.expect("Read failed");
224 let mut data = vec![0u8; 8192 + 1024];
225 buf.copy_to_slice(&mut data);
226 assert_eq!(data[..8192], vec![0xaa as u8; 8192]);
227 assert_eq!(data[8192..], vec![0xbb as u8; 1024]);
228 }
229
230 device.close().await.expect("Close failed");
231 }
232
233 #[fuchsia::test]
234 async fn test_read_only() {
235 let device =
236 BlockDevice::new(FakeBlockClient::new(1024, 1024), true).await.expect("new failed");
237 let mut buf1 = device.allocate_buffer(8192).await;
238 buf1.fill(0xaa);
239 let err = device.write(65536, buf1.as_ref()).await.expect_err("Write succeeded");
240 assert_eq!(err.root_cause().downcast_ref::<Status>().unwrap(), &Status::ACCESS_DENIED);
241 }
242
243 #[fuchsia::test]
244 async fn test_unaligned_access() {
245 let device =
246 BlockDevice::new(FakeBlockClient::new(1024, 1024), false).await.expect("new failed");
247 let mut buf1 = device.allocate_buffer(device.block_size() as usize * 2).await;
248 buf1.fill(0xaa);
249
250 {
252 let err = device.write(1, buf1.as_ref()).await.expect_err("Write succeeded");
253 assert_eq!(err.root_cause().downcast_ref::<Status>().unwrap(), &Status::INVALID_ARGS);
254 }
255 {
256 let err = device
257 .write(0, buf1.subslice(1..(device.block_size() as usize + 1)))
258 .await
259 .expect_err("Write succeeded");
260 assert_eq!(err.root_cause().downcast_ref::<Status>().unwrap(), &Status::INVALID_ARGS);
261 }
262 {
263 let err = device
264 .write(0, buf1.subslice(1..device.block_size() as usize))
265 .await
266 .expect_err("Write succeeded");
267 assert_eq!(err.root_cause().downcast_ref::<Status>().unwrap(), &Status::INVALID_ARGS);
268 }
269 {
270 let err = device
271 .write(0, buf1.subslice(0..(device.block_size() as usize + 1)))
272 .await
273 .expect_err("Write succeeded");
274 assert_eq!(err.root_cause().downcast_ref::<Status>().unwrap(), &Status::INVALID_ARGS);
275 }
276
277 {
279 let err = device.read(1, buf1.as_mut()).await.expect_err("Read succeeded");
280 assert_eq!(err.root_cause().downcast_ref::<Status>().unwrap(), &Status::INVALID_ARGS);
281 }
282 {
283 let err = device
284 .read(0, buf1.subslice_mut(1..(device.block_size() as usize + 1)))
285 .await
286 .expect_err("Read succeeded");
287 assert_eq!(err.root_cause().downcast_ref::<Status>().unwrap(), &Status::INVALID_ARGS);
288 }
289 {
290 let err = device
291 .read(0, buf1.subslice_mut(1..device.block_size() as usize))
292 .await
293 .expect_err("Read succeeded");
294 assert_eq!(err.root_cause().downcast_ref::<Status>().unwrap(), &Status::INVALID_ARGS);
295 }
296 {
297 let err = device
298 .read(0, buf1.subslice_mut(0..(device.block_size() as usize + 1)))
299 .await
300 .expect_err("Read succeeded");
301 assert_eq!(err.root_cause().downcast_ref::<Status>().unwrap(), &Status::INVALID_ARGS);
302 }
303
304 {
306 let err = device.trim(1..device.block_size() as u64).await.expect_err("Read succeeded");
307 assert_eq!(err.root_cause().downcast_ref::<Status>().unwrap(), &Status::INVALID_ARGS);
308 }
309 {
310 let err =
311 device.trim(1..(device.block_size() as u64 + 1)).await.expect_err("Read succeeded");
312 assert_eq!(err.root_cause().downcast_ref::<Status>().unwrap(), &Status::INVALID_ARGS);
313 }
314 {
315 let err =
316 device.trim(0..(device.block_size() as u64 + 1)).await.expect_err("Read succeeded");
317 assert_eq!(err.root_cause().downcast_ref::<Status>().unwrap(), &Status::INVALID_ARGS);
318 }
319 }
320
321 #[fuchsia::test]
322 async fn test_foreign_buffer_read_write() {
323 let device1 =
324 BlockDevice::new(FakeBlockClient::new(1024, 1024), false).await.expect("new failed");
325 let device2 =
326 BlockDevice::new(FakeBlockClient::new(1024, 1024), false).await.expect("new failed");
327
328 let mut foreign_buf = device2.allocate_buffer(8192).await;
330 foreign_buf.fill(0xaa);
331 device1.write(0, foreign_buf.as_ref()).await.expect("Foreign write failed");
332
333 let mut foreign_read_buf = device2.allocate_buffer(8192).await;
335 device1.read(0, foreign_read_buf.as_mut()).await.expect("Foreign read failed");
336
337 let mut data = vec![0u8; 8192];
338 foreign_read_buf.copy_to_slice(&mut data);
339 assert_eq!(data, vec![0xaa; 8192]);
340 }
341}