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 barrier(&self) {
166 self.remote.barrier()
167 }
168
169 fn is_read_only(&self) -> bool {
170 self.read_only
171 }
172
173 fn supports_trim(&self) -> bool {
174 self.remote.block_flags().contains(BlockDeviceFlag::TRIM_SUPPORT)
175 }
176}
177
178impl<T> Drop for BlockDevice<T> {
179 fn drop(&mut self) {
180 let _ = self.vmoid.take().into_id();
183 }
184}
185
186#[cfg(test)]
187mod tests {
188 use crate::Device;
189 use crate::block_device::BlockDevice;
190 use fake_block_client::FakeBlockClient;
191 use zx::Status;
192
193 #[fuchsia::test]
194 async fn test_lifecycle() {
195 let device =
196 BlockDevice::new(FakeBlockClient::new(1024, 1024), false).await.expect("new failed");
197
198 {
199 let _buf = device.allocate_buffer(8192).await;
200 }
201
202 device.close().await.expect("Close failed");
203 }
204
205 #[fuchsia::test]
206 async fn test_read_write_buffer() {
207 let device =
208 BlockDevice::new(FakeBlockClient::new(1024, 1024), false).await.expect("new failed");
209
210 {
211 let mut buf1 = device.allocate_buffer(8192).await;
212 let mut buf2 = device.allocate_buffer(1024).await;
213 buf1.fill(0xaa);
214 buf2.fill(0xbb);
215 device.write(65536, buf1.as_ref()).await.expect("Write failed");
216 device.write(65536 + 8192, buf2.as_ref()).await.expect("Write failed");
217 }
218 {
219 let mut buf = device.allocate_buffer(8192 + 1024).await;
220 device.read(65536, buf.as_mut()).await.expect("Read failed");
221 let mut data = vec![0u8; 8192 + 1024];
222 buf.copy_to_slice(&mut data);
223 assert_eq!(data[..8192], vec![0xaa as u8; 8192]);
224 assert_eq!(data[8192..], vec![0xbb as u8; 1024]);
225 }
226
227 device.close().await.expect("Close failed");
228 }
229
230 #[fuchsia::test]
231 async fn test_read_only() {
232 let device =
233 BlockDevice::new(FakeBlockClient::new(1024, 1024), true).await.expect("new failed");
234 let mut buf1 = device.allocate_buffer(8192).await;
235 buf1.fill(0xaa);
236 let err = device.write(65536, buf1.as_ref()).await.expect_err("Write succeeded");
237 assert_eq!(err.root_cause().downcast_ref::<Status>().unwrap(), &Status::ACCESS_DENIED);
238 }
239
240 #[fuchsia::test]
241 async fn test_unaligned_access() {
242 let device =
243 BlockDevice::new(FakeBlockClient::new(1024, 1024), false).await.expect("new failed");
244 let mut buf1 = device.allocate_buffer(device.block_size() as usize * 2).await;
245 buf1.fill(0xaa);
246
247 {
249 let err = device.write(1, buf1.as_ref()).await.expect_err("Write succeeded");
250 assert_eq!(err.root_cause().downcast_ref::<Status>().unwrap(), &Status::INVALID_ARGS);
251 }
252 {
253 let err = device
254 .write(0, buf1.subslice(1..(device.block_size() as usize + 1)))
255 .await
256 .expect_err("Write succeeded");
257 assert_eq!(err.root_cause().downcast_ref::<Status>().unwrap(), &Status::INVALID_ARGS);
258 }
259 {
260 let err = device
261 .write(0, buf1.subslice(1..device.block_size() as usize))
262 .await
263 .expect_err("Write succeeded");
264 assert_eq!(err.root_cause().downcast_ref::<Status>().unwrap(), &Status::INVALID_ARGS);
265 }
266 {
267 let err = device
268 .write(0, buf1.subslice(0..(device.block_size() as usize + 1)))
269 .await
270 .expect_err("Write succeeded");
271 assert_eq!(err.root_cause().downcast_ref::<Status>().unwrap(), &Status::INVALID_ARGS);
272 }
273
274 {
276 let err = device.read(1, buf1.as_mut()).await.expect_err("Read succeeded");
277 assert_eq!(err.root_cause().downcast_ref::<Status>().unwrap(), &Status::INVALID_ARGS);
278 }
279 {
280 let err = device
281 .read(0, buf1.subslice_mut(1..(device.block_size() as usize + 1)))
282 .await
283 .expect_err("Read succeeded");
284 assert_eq!(err.root_cause().downcast_ref::<Status>().unwrap(), &Status::INVALID_ARGS);
285 }
286 {
287 let err = device
288 .read(0, buf1.subslice_mut(1..device.block_size() as usize))
289 .await
290 .expect_err("Read succeeded");
291 assert_eq!(err.root_cause().downcast_ref::<Status>().unwrap(), &Status::INVALID_ARGS);
292 }
293 {
294 let err = device
295 .read(0, buf1.subslice_mut(0..(device.block_size() as usize + 1)))
296 .await
297 .expect_err("Read succeeded");
298 assert_eq!(err.root_cause().downcast_ref::<Status>().unwrap(), &Status::INVALID_ARGS);
299 }
300
301 {
303 let err = device.trim(1..device.block_size() as u64).await.expect_err("Read succeeded");
304 assert_eq!(err.root_cause().downcast_ref::<Status>().unwrap(), &Status::INVALID_ARGS);
305 }
306 {
307 let err =
308 device.trim(1..(device.block_size() as u64 + 1)).await.expect_err("Read succeeded");
309 assert_eq!(err.root_cause().downcast_ref::<Status>().unwrap(), &Status::INVALID_ARGS);
310 }
311 {
312 let err =
313 device.trim(0..(device.block_size() as u64 + 1)).await.expect_err("Read succeeded");
314 assert_eq!(err.root_cause().downcast_ref::<Status>().unwrap(), &Status::INVALID_ARGS);
315 }
316 }
317
318 #[fuchsia::test]
319 async fn test_foreign_buffer_read_write() {
320 let device1 =
321 BlockDevice::new(FakeBlockClient::new(1024, 1024), false).await.expect("new failed");
322 let device2 =
323 BlockDevice::new(FakeBlockClient::new(1024, 1024), false).await.expect("new failed");
324
325 let mut foreign_buf = device2.allocate_buffer(8192).await;
327 foreign_buf.fill(0xaa);
328 device1.write(0, foreign_buf.as_ref()).await.expect("Foreign write failed");
329
330 let mut foreign_read_buf = device2.allocate_buffer(8192).await;
332 device1.read(0, foreign_read_buf.as_mut()).await.expect("Foreign read failed");
333
334 let mut data = vec![0u8; 8192];
335 foreign_read_buf.copy_to_slice(&mut data);
336 assert_eq!(data, vec![0xaa; 8192]);
337 }
338}