storage_device/
block_device.rs
1use crate::buffer::{BufferFuture, BufferRef, MutableBufferRef};
6use crate::buffer_allocator::{BufferAllocator, BufferSource};
7use crate::Device;
8use anyhow::{bail, ensure, Error};
9use async_trait::async_trait;
10use block_client::{BlockClient, BlockFlags, BufferSlice, MutableBufferSlice, VmoId, WriteOptions};
11use std::ops::Range;
12use zx::Status;
13
14pub struct BlockDevice {
16 allocator: BufferAllocator,
17 remote: Box<dyn BlockClient>,
18 read_only: bool,
19 vmoid: VmoId,
20}
21
22const TRANSFER_VMO_SIZE: usize = 128 * 1024 * 1024;
23
24impl BlockDevice {
25 pub async fn new(remote: Box<dyn BlockClient>, read_only: bool) -> Result<Self, Error> {
27 let buffer_source = BufferSource::new(TRANSFER_VMO_SIZE);
28 let vmoid = remote.attach_vmo(buffer_source.vmo()).await?;
29 let allocator = BufferAllocator::new(remote.block_size() as usize, buffer_source);
30 Ok(Self { allocator, remote, read_only, vmoid })
31 }
32}
33
34#[async_trait]
35impl Device for BlockDevice {
36 fn allocate_buffer(&self, size: usize) -> BufferFuture<'_> {
37 self.allocator.allocate_buffer(size)
38 }
39
40 fn block_size(&self) -> u32 {
41 self.remote.block_size()
42 }
43
44 fn block_count(&self) -> u64 {
45 self.remote.block_count()
46 }
47
48 async fn read(&self, offset: u64, buffer: MutableBufferRef<'_>) -> Result<(), Error> {
49 if buffer.len() == 0 {
50 return Ok(());
51 }
52 ensure!(self.vmoid.is_valid(), "Device is closed");
53 assert_eq!(offset % self.block_size() as u64, 0);
54 assert_eq!(buffer.range().start % self.block_size() as usize, 0);
55 assert_eq!((offset + buffer.len() as u64) % self.block_size() as u64, 0);
56 Ok(self
57 .remote
58 .read_at(
59 MutableBufferSlice::new_with_vmo_id(
60 &self.vmoid,
61 buffer.range().start as u64,
62 buffer.len() as u64,
63 ),
64 offset,
65 )
66 .await?)
67 }
68
69 async fn write_with_opts(
70 &self,
71 offset: u64,
72 buffer: BufferRef<'_>,
73 opts: WriteOptions,
74 ) -> Result<(), Error> {
75 if self.read_only {
76 bail!(Status::ACCESS_DENIED);
77 }
78 if buffer.len() == 0 {
79 return Ok(());
80 }
81 ensure!(self.vmoid.is_valid(), "Device is closed");
82 assert_eq!(offset % self.block_size() as u64, 0);
83 assert_eq!(buffer.range().start % self.block_size() as usize, 0);
84 assert_eq!((offset + buffer.len() as u64) % self.block_size() as u64, 0);
85 Ok(self
86 .remote
87 .write_at_with_opts(
88 BufferSlice::new_with_vmo_id(
89 &self.vmoid,
90 buffer.range().start as u64,
91 buffer.len() as u64,
92 ),
93 offset,
94 opts,
95 )
96 .await?)
97 }
98
99 async fn trim(&self, range: Range<u64>) -> Result<(), Error> {
100 if self.read_only {
101 bail!(Status::ACCESS_DENIED);
102 }
103 assert_eq!(range.start % self.block_size() as u64, 0);
104 assert_eq!(range.end % self.block_size() as u64, 0);
105 Ok(self.remote.trim(range).await?)
106 }
107
108 async fn close(&self) -> Result<(), Error> {
109 let _ = self.vmoid.take().into_id();
111 Ok(self.remote.close().await?)
112 }
113
114 async fn flush(&self) -> Result<(), Error> {
115 Ok(self.remote.flush().await?)
116 }
117
118 fn is_read_only(&self) -> bool {
119 self.read_only
120 }
121
122 fn supports_trim(&self) -> bool {
123 self.remote.block_flags().contains(BlockFlags::TRIM_SUPPORT)
124 }
125}
126
127impl Drop for BlockDevice {
128 fn drop(&mut self) {
129 let _ = self.vmoid.take().into_id();
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use crate::block_device::BlockDevice;
138 use crate::Device;
139 use fake_block_client::FakeBlockClient;
140 use zx::Status;
141
142 #[fuchsia::test]
143 async fn test_lifecycle() {
144 let device = BlockDevice::new(Box::new(FakeBlockClient::new(1024, 1024)), false)
145 .await
146 .expect("new failed");
147
148 {
149 let _buf = device.allocate_buffer(8192).await;
150 }
151
152 device.close().await.expect("Close failed");
153 }
154
155 #[fuchsia::test]
156 async fn test_read_write_buffer() {
157 let device = BlockDevice::new(Box::new(FakeBlockClient::new(1024, 1024)), false)
158 .await
159 .expect("new failed");
160
161 {
162 let mut buf1 = device.allocate_buffer(8192).await;
163 let mut buf2 = device.allocate_buffer(1024).await;
164 buf1.as_mut_slice().fill(0xaa as u8);
165 buf2.as_mut_slice().fill(0xbb as u8);
166 device.write(65536, buf1.as_ref()).await.expect("Write failed");
167 device.write(65536 + 8192, buf2.as_ref()).await.expect("Write failed");
168 }
169 {
170 let mut buf = device.allocate_buffer(8192 + 1024).await;
171 device.read(65536, buf.as_mut()).await.expect("Read failed");
172 assert_eq!(buf.as_slice()[..8192], vec![0xaa as u8; 8192]);
173 assert_eq!(buf.as_slice()[8192..], vec![0xbb as u8; 1024]);
174 }
175
176 device.close().await.expect("Close failed");
177 }
178
179 #[fuchsia::test]
180 async fn test_read_only() {
181 let device = BlockDevice::new(Box::new(FakeBlockClient::new(1024, 1024)), true)
182 .await
183 .expect("new failed");
184 let mut buf1 = device.allocate_buffer(8192).await;
185 buf1.as_mut_slice().fill(0xaa as u8);
186 let err = device.write(65536, buf1.as_ref()).await.expect_err("Write succeeded");
187 assert_eq!(err.root_cause().downcast_ref::<Status>().unwrap(), &Status::ACCESS_DENIED);
188 }
189}