1use crate::buffer::{BufferFuture, BufferRef, MutableBufferRef};
15use anyhow::{Error, bail};
16use async_trait::async_trait;
17pub use block_protocol::{InlineCryptoOptions, ReadOptions, WriteFlags, WriteOptions};
19use futures::channel::oneshot::{Sender, channel};
20use std::future::Future;
21use std::mem::ManuallyDrop;
22use std::ops::{Deref, Range};
23use std::pin::Pin;
24use std::sync::{Arc, OnceLock};
25
26pub mod buffer;
27pub mod buffer_allocator;
28pub mod splittable_buffer;
29
30pub use splittable_buffer::{SplittableBuffer, SubHandle};
31
32#[cfg(target_os = "fuchsia")]
33pub mod block_device;
34#[cfg(target_os = "fuchsia")]
35pub mod pinned_buffer_allocator;
36
37#[cfg(target_family = "unix")]
38pub mod file_backed_device;
39
40pub mod fake_device;
41
42pub mod ranged_device;
43
44#[async_trait]
45pub trait Device: Send + Sync {
47 fn allocate_buffer(&self, size: usize) -> BufferFuture<'_>;
51
52 fn clean_transfer_buffer(&self) {}
54
55 fn block_size(&self) -> u32;
57
58 fn block_count(&self) -> u64;
60
61 fn size(&self) -> u64 {
63 self.block_size() as u64 * self.block_count()
64 }
65
66 fn read<'a>(
68 &'a self,
69 offset: u64,
70 buffer: MutableBufferRef<'a>,
71 ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'a>> {
72 self.read_with_opts(offset, buffer, ReadOptions::default())
73 }
74
75 async fn read_with_opts(
77 &self,
78 offset: u64,
79 buffer: MutableBufferRef<'_>,
80 read_opts: ReadOptions,
81 ) -> Result<(), Error>;
82
83 fn write<'a>(
85 &'a self,
86 offset: u64,
87 buffer: BufferRef<'a>,
88 ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'a>> {
89 self.write_with_opts(offset, buffer, WriteOptions::default())
90 }
91
92 async fn write_with_opts(
94 &self,
95 offset: u64,
96 buffer: BufferRef<'_>,
97 write_opts: WriteOptions,
98 ) -> Result<(), Error>;
99
100 async fn trim(&self, range: Range<u64>) -> Result<(), Error>;
102
103 async fn close(&self) -> Result<(), Error>;
106
107 async fn flush(&self) -> Result<(), Error>;
109
110 fn reopen(&self, _read_only: bool) {
112 unreachable!();
113 }
114 fn is_read_only(&self) -> bool;
116
117 fn supports_trim(&self) -> bool;
119
120 fn snapshot(&self) -> Result<DeviceHolder, Error> {
122 bail!("Not supported");
123 }
124
125 fn discard_random_since_last_flush(&self) -> Result<(), Error> {
127 bail!("Not supported");
128 }
129
130 fn poison(&self) -> Result<(), Error> {
132 bail!("Not supported");
133 }
134
135 #[cfg(target_os = "fuchsia")]
137 async fn connect_mapper(
138 &self,
139 server_end: fidl::endpoints::ServerEnd<fidl_fuchsia_storage_block::MapperMarker>,
140 ) -> Result<(), zx::Status> {
141 let _ = server_end.close_with_epitaph(zx::Status::NOT_SUPPORTED);
142 Err(zx::Status::NOT_SUPPORTED)
143 }
144}
145
146pub struct DeviceHolder {
153 device: ManuallyDrop<Arc<dyn Device>>,
154 on_drop: OnceLock<Sender<DeviceHolder>>,
155}
156
157impl DeviceHolder {
158 pub fn new(device: impl Device + 'static) -> Self {
159 DeviceHolder { device: ManuallyDrop::new(Arc::new(device)), on_drop: OnceLock::new() }
160 }
161
162 pub fn ensure_unique(&self) {
165 assert_eq!(Arc::strong_count(&self.device), 1);
166 }
167
168 pub fn take_when_dropped(&self) -> impl Future<Output = DeviceHolder> + use<> {
169 let (sender, receiver) = channel::<DeviceHolder>();
170 self.on_drop
171 .set(sender)
172 .unwrap_or_else(|_| panic!("take_when_dropped should only be called once"));
173 async { receiver.await.unwrap() }
174 }
175}
176
177impl Drop for DeviceHolder {
178 fn drop(&mut self) {
179 if let Some(sender) = self.on_drop.take() {
180 let device = ManuallyDrop::new(unsafe { ManuallyDrop::take(&mut self.device) });
182 let _ = sender.send(DeviceHolder { device, on_drop: OnceLock::new() });
184 } else {
185 unsafe { ManuallyDrop::drop(&mut self.device) }
187 }
188 }
189}
190
191impl Deref for DeviceHolder {
192 type Target = Arc<dyn Device>;
193
194 fn deref(&self) -> &Self::Target {
195 &self.device
196 }
197}
198
199#[cfg(test)]
200mod tests {
201 use super::DeviceHolder;
202 use crate::fake_device::FakeDevice;
203
204 #[fuchsia::test]
205 async fn test_take_when_dropped() {
206 let holder = DeviceHolder::new(FakeDevice::new(1, 512));
207 let fut = holder.take_when_dropped();
208 std::mem::drop(holder);
209 fut.await.ensure_unique();
210 }
211}