blob: dd00c03627145234401f02069f2f1d919703709b [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::buffer::{BufferFuture, BufferRef, MutableBufferRef};
use anyhow::{bail, Error};
use async_trait::async_trait;
use futures::channel::oneshot::{channel, Sender};
use std::future::Future;
use std::mem::ManuallyDrop;
use std::ops::{Deref, Range};
use std::sync::{Arc, OnceLock};
pub mod buffer;
pub mod buffer_allocator;
#[cfg(target_os = "fuchsia")]
pub mod block_device;
#[cfg(target_family = "unix")]
pub mod file_backed_device;
pub mod fake_device;
#[async_trait]
/// Device is an abstract representation of an underlying block device.
pub trait Device: Send + Sync {
/// Allocates a transfer buffer of at least |size| bytes for doing I/O with the device.
/// The actual size of the buffer will be rounded up to a block-aligned size.
fn allocate_buffer(&self, size: usize) -> BufferFuture<'_>;
/// Returns the block size of the device. Buffers are aligned to block-aligned chunks.
fn block_size(&self) -> u32;
/// Returns the number of blocks of the device.
// TODO(jfsulliv): Should this be async and go query the underlying device?
fn block_count(&self) -> u64;
/// Returns the size in bytes of the device.
fn size(&self) -> u64 {
self.block_size() as u64 * self.block_count()
}
/// Fills |buffer| with blocks read from |offset|.
async fn read(&self, offset: u64, buffer: MutableBufferRef<'_>) -> Result<(), Error>;
/// Writes the contents of |buffer| to the device at |offset|.
async fn write(&self, offset: u64, buffer: BufferRef<'_>) -> Result<(), Error>;
/// Trims the given device |range|.
async fn trim(&self, range: Range<u64>) -> Result<(), Error>;
/// Closes the block device. It is an error to continue using the device after this, but close
/// itself is idempotent.
async fn close(&self) -> Result<(), Error>;
/// Flush the device.
async fn flush(&self) -> Result<(), Error>;
/// Reopens the device, making it usable again. (Only implemented for testing devices.)
fn reopen(&self, _read_only: bool) {
unreachable!();
}
/// Returns whether the device is read-only.
fn is_read_only(&self) -> bool;
/// Returns whether the device supports trim.
fn supports_trim(&self) -> bool;
/// Returns a snapshot of the device.
fn snapshot(&self) -> Result<DeviceHolder, Error> {
bail!("Not supported");
}
/// Discards random blocks since the last flush.
fn discard_random_since_last_flush(&self) -> Result<(), Error> {
bail!("Not supported");
}
}
// Arc<dyn Device> can easily be cloned and supports concurrent access, but sometimes exclusive
// access is required, in which case APIs should accept DeviceHolder. It doesn't guarantee there
// aren't some users that hold an Arc<dyn Device> somewhere, but it does mean that something that
// accepts a DeviceHolder won't be sharing the device with something else that accepts a
// DeviceHolder. For example, FxFilesystem accepts a DeviceHolder which means that you cannot
// create two FxFilesystem instances that are both sharing the same device.
pub struct DeviceHolder {
device: ManuallyDrop<Arc<dyn Device>>,
on_drop: OnceLock<Sender<DeviceHolder>>,
}
impl DeviceHolder {
pub fn new(device: impl Device + 'static) -> Self {
DeviceHolder { device: ManuallyDrop::new(Arc::new(device)), on_drop: OnceLock::new() }
}
// Ensures there are no dangling references to the device. Useful for tests to ensure orderly
// shutdown.
pub fn ensure_unique(&self) {
assert_eq!(Arc::strong_count(&self.device), 1);
}
pub fn take_when_dropped(&self) -> impl Future<Output = DeviceHolder> {
let (sender, receiver) = channel::<DeviceHolder>();
self.on_drop
.set(sender)
.unwrap_or_else(|_| panic!("take_when_dropped should only be called once"));
async { receiver.await.unwrap() }
}
}
impl Drop for DeviceHolder {
fn drop(&mut self) {
if let Some(sender) = self.on_drop.take() {
// SAFETY: `device` is not used again.
let device = ManuallyDrop::new(unsafe { ManuallyDrop::take(&mut self.device) });
// We don't care if this fails to send.
let _ = sender.send(DeviceHolder { device, on_drop: OnceLock::new() });
} else {
// SAFETY: `device` is not used again.
unsafe { ManuallyDrop::drop(&mut self.device) }
}
}
}
impl Deref for DeviceHolder {
type Target = Arc<dyn Device>;
fn deref(&self) -> &Self::Target {
&self.device
}
}
#[cfg(test)]
mod tests {
use super::DeviceHolder;
use crate::fake_device::FakeDevice;
#[fuchsia::test]
async fn test_take_when_dropped() {
let holder = DeviceHolder::new(FakeDevice::new(1, 512));
let fut = holder.take_when_dropped();
std::mem::drop(holder);
fut.await.ensure_unique();
}
}