storage_device/
lib.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::buffer::{BufferFuture, BufferRef, MutableBufferRef};
6use anyhow::{bail, Error};
7use async_trait::async_trait;
8use block_protocol::WriteOptions;
9use futures::channel::oneshot::{channel, Sender};
10use std::future::Future;
11use std::mem::ManuallyDrop;
12use std::ops::{Deref, Range};
13use std::sync::{Arc, OnceLock};
14
15pub mod buffer;
16pub mod buffer_allocator;
17
18#[cfg(target_os = "fuchsia")]
19pub mod block_device;
20
21#[cfg(target_family = "unix")]
22pub mod file_backed_device;
23
24pub mod fake_device;
25
26#[async_trait]
27/// Device is an abstract representation of an underlying block device.
28pub trait Device: Send + Sync {
29    /// Allocates a transfer buffer of at least |size| bytes for doing I/O with the device.
30    /// The actual size of the buffer will be rounded up to a block-aligned size.
31    fn allocate_buffer(&self, size: usize) -> BufferFuture<'_>;
32
33    /// Returns the block size of the device. Buffers are aligned to block-aligned chunks.
34    fn block_size(&self) -> u32;
35
36    /// Returns the number of blocks of the device.
37    // TODO(jfsulliv): Should this be async and go query the underlying device?
38    fn block_count(&self) -> u64;
39
40    /// Returns the size in bytes of the device.
41    fn size(&self) -> u64 {
42        self.block_size() as u64 * self.block_count()
43    }
44
45    /// Fills |buffer| with blocks read from |offset|.
46    async fn read(&self, offset: u64, buffer: MutableBufferRef<'_>) -> Result<(), Error>;
47
48    /// Writes the contents of |buffer| to the device at |offset|.
49    async fn write(&self, offset: u64, buffer: BufferRef<'_>) -> Result<(), Error> {
50        self.write_with_opts(offset, buffer, WriteOptions::empty()).await
51    }
52
53    /// Writes the contents of |buffer| to the device at |offset|.
54    async fn write_with_opts(
55        &self,
56        offset: u64,
57        buffer: BufferRef<'_>,
58        opts: WriteOptions,
59    ) -> Result<(), Error>;
60
61    /// Trims the given device |range|.
62    async fn trim(&self, range: Range<u64>) -> Result<(), Error>;
63
64    /// Closes the block device. It is an error to continue using the device after this, but close
65    /// itself is idempotent.
66    async fn close(&self) -> Result<(), Error>;
67
68    /// Flush the device.
69    async fn flush(&self) -> Result<(), Error>;
70
71    /// Reopens the device, making it usable again. (Only implemented for testing devices.)
72    fn reopen(&self, _read_only: bool) {
73        unreachable!();
74    }
75    /// Returns whether the device is read-only.
76    fn is_read_only(&self) -> bool;
77
78    /// Returns whether the device supports trim.
79    fn supports_trim(&self) -> bool;
80
81    /// Returns a snapshot of the device.
82    fn snapshot(&self) -> Result<DeviceHolder, Error> {
83        bail!("Not supported");
84    }
85
86    /// Discards random blocks since the last flush.
87    fn discard_random_since_last_flush(&self) -> Result<(), Error> {
88        bail!("Not supported");
89    }
90
91    /// Poisons a device to panic on drop. Used to find hanging references.
92    fn poison(&self) -> Result<(), Error> {
93        bail!("Not supported");
94    }
95}
96
97// Arc<dyn Device> can easily be cloned and supports concurrent access, but sometimes exclusive
98// access is required, in which case APIs should accept DeviceHolder.  It doesn't guarantee there
99// aren't some users that hold an Arc<dyn Device> somewhere, but it does mean that something that
100// accepts a DeviceHolder won't be sharing the device with something else that accepts a
101// DeviceHolder.  For example, FxFilesystem accepts a DeviceHolder which means that you cannot
102// create two FxFilesystem instances that are both sharing the same device.
103pub struct DeviceHolder {
104    device: ManuallyDrop<Arc<dyn Device>>,
105    on_drop: OnceLock<Sender<DeviceHolder>>,
106}
107
108impl DeviceHolder {
109    pub fn new(device: impl Device + 'static) -> Self {
110        DeviceHolder { device: ManuallyDrop::new(Arc::new(device)), on_drop: OnceLock::new() }
111    }
112
113    // Ensures there are no dangling references to the device. Useful for tests to ensure orderly
114    // shutdown.
115    pub fn ensure_unique(&self) {
116        assert_eq!(Arc::strong_count(&self.device), 1);
117    }
118
119    pub fn take_when_dropped(&self) -> impl Future<Output = DeviceHolder> {
120        let (sender, receiver) = channel::<DeviceHolder>();
121        self.on_drop
122            .set(sender)
123            .unwrap_or_else(|_| panic!("take_when_dropped should only be called once"));
124        async { receiver.await.unwrap() }
125    }
126}
127
128impl Drop for DeviceHolder {
129    fn drop(&mut self) {
130        if let Some(sender) = self.on_drop.take() {
131            // SAFETY: `device` is not used again.
132            let device = ManuallyDrop::new(unsafe { ManuallyDrop::take(&mut self.device) });
133            // We don't care if this fails to send.
134            let _ = sender.send(DeviceHolder { device, on_drop: OnceLock::new() });
135        } else {
136            // SAFETY: `device` is not used again.
137            unsafe { ManuallyDrop::drop(&mut self.device) }
138        }
139    }
140}
141
142impl Deref for DeviceHolder {
143    type Target = Arc<dyn Device>;
144
145    fn deref(&self) -> &Self::Target {
146        &self.device
147    }
148}
149
150#[cfg(test)]
151mod tests {
152    use super::DeviceHolder;
153    use crate::fake_device::FakeDevice;
154
155    #[fuchsia::test]
156    async fn test_take_when_dropped() {
157        let holder = DeviceHolder::new(FakeDevice::new(1, 512));
158        let fut = holder.take_when_dropped();
159        std::mem::drop(holder);
160        fut.await.ensure_unique();
161    }
162}