2024-01-03 03:22:36 +00:00
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
|
|
2023-12-25 07:27:41 +00:00
|
|
|
|
//! The block devices of Asterinas.
|
2023-09-18 03:47:17 +00:00
|
|
|
|
//!
|
|
|
|
|
|
//!This crate provides a number of base components for block devices, including
|
|
|
|
|
|
//! an abstraction of block devices, as well as the registration and lookup of block devices.
|
|
|
|
|
|
//!
|
|
|
|
|
|
//! Block devices use a queue-based model for asynchronous I/O operations. It is necessary
|
|
|
|
|
|
//! for a block device to maintain a queue to handle I/O requests. The users (e.g., fs)
|
|
|
|
|
|
//! submit I/O requests to this queue and wait for their completion. Drivers implementing
|
|
|
|
|
|
//! block devices can create their own queues as needed, with the possibility to reorder
|
|
|
|
|
|
//! and merge requests within the queue.
|
|
|
|
|
|
//!
|
|
|
|
|
|
//! This crate also offers the `Bio` related data structures and APIs to accomplish
|
2024-06-28 10:45:16 +00:00
|
|
|
|
//! safe and convenient block I/O operations, for example:
|
2023-09-18 03:47:17 +00:00
|
|
|
|
//!
|
|
|
|
|
|
//! ```no_run
|
|
|
|
|
|
//! // Creates a bio request.
|
|
|
|
|
|
//! let bio = Bio::new(BioType::Write, sid, segments, None);
|
|
|
|
|
|
//! // Submits to the block device.
|
|
|
|
|
|
//! let bio_waiter = bio.submit(block_device)?;
|
|
|
|
|
|
//! // Waits for the the completion.
|
|
|
|
|
|
//! let Some(status) = bio_waiter.wait() else {
|
|
|
|
|
|
//! return Err(IoError);
|
|
|
|
|
|
//! };
|
|
|
|
|
|
//! assert!(status == BioStatus::Complete);
|
|
|
|
|
|
//! ```
|
|
|
|
|
|
//!
|
2023-02-27 08:18:04 +00:00
|
|
|
|
#![no_std]
|
2024-05-22 09:46:27 +00:00
|
|
|
|
#![deny(unsafe_code)]
|
2023-02-27 08:18:04 +00:00
|
|
|
|
#![feature(fn_traits)]
|
2023-09-18 03:47:17 +00:00
|
|
|
|
#![feature(step_trait)]
|
2024-06-20 15:55:36 +00:00
|
|
|
|
#![feature(trait_upcasting)]
|
2023-09-18 03:47:17 +00:00
|
|
|
|
#![allow(dead_code)]
|
2023-02-27 08:18:04 +00:00
|
|
|
|
|
|
|
|
|
|
extern crate alloc;
|
|
|
|
|
|
|
2023-09-18 03:47:17 +00:00
|
|
|
|
pub mod bio;
|
|
|
|
|
|
pub mod id;
|
|
|
|
|
|
mod impl_block_device;
|
|
|
|
|
|
mod prelude;
|
|
|
|
|
|
pub mod request_queue;
|
|
|
|
|
|
|
2024-02-25 14:09:24 +00:00
|
|
|
|
use component::{init_component, ComponentInitError};
|
2024-06-19 08:18:39 +00:00
|
|
|
|
use ostd::sync::SpinLock;
|
2023-02-27 08:18:04 +00:00
|
|
|
|
use spin::Once;
|
|
|
|
|
|
|
2024-02-25 14:09:24 +00:00
|
|
|
|
use self::{
|
|
|
|
|
|
bio::{BioEnqueueError, SubmittedBio},
|
|
|
|
|
|
prelude::*,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2024-06-19 08:18:39 +00:00
|
|
|
|
pub const BLOCK_SIZE: usize = ostd::mm::PAGE_SIZE;
|
2023-09-18 03:47:17 +00:00
|
|
|
|
pub const SECTOR_SIZE: usize = 512;
|
2023-02-27 08:18:04 +00:00
|
|
|
|
|
2023-08-28 07:03:28 +00:00
|
|
|
|
pub trait BlockDevice: Send + Sync + Any + Debug {
|
2024-01-25 07:00:19 +00:00
|
|
|
|
/// Enqueues a new `SubmittedBio` to the block device.
|
|
|
|
|
|
fn enqueue(&self, bio: SubmittedBio) -> Result<(), BioEnqueueError>;
|
2024-07-18 11:45:38 +00:00
|
|
|
|
|
|
|
|
|
|
/// Returns the metadata of the block device.
|
|
|
|
|
|
fn metadata(&self) -> BlockDeviceMeta;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Metadata for a block device.
|
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
|
|
pub struct BlockDeviceMeta {
|
|
|
|
|
|
/// The upper limit for the number of segments per bio.
|
|
|
|
|
|
pub max_nr_segments_per_bio: usize,
|
|
|
|
|
|
/// The total number of sectors of the block device.
|
|
|
|
|
|
pub nr_sectors: usize,
|
|
|
|
|
|
// Additional useful metadata can be added here in the future.
|
2023-02-27 08:18:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-09-18 03:47:17 +00:00
|
|
|
|
impl dyn BlockDevice {
|
|
|
|
|
|
pub fn downcast_ref<T: BlockDevice>(&self) -> Option<&T> {
|
|
|
|
|
|
(self as &dyn Any).downcast_ref::<T>()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-08-28 07:03:28 +00:00
|
|
|
|
pub fn register_device(name: String, device: Arc<dyn BlockDevice>) {
|
2023-11-20 12:37:51 +00:00
|
|
|
|
COMPONENT
|
|
|
|
|
|
.get()
|
|
|
|
|
|
.unwrap()
|
|
|
|
|
|
.block_device_table
|
|
|
|
|
|
.lock()
|
|
|
|
|
|
.insert(name, device);
|
2023-02-27 08:18:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-11-20 12:37:51 +00:00
|
|
|
|
pub fn get_device(str: &str) -> Option<Arc<dyn BlockDevice>> {
|
|
|
|
|
|
COMPONENT
|
|
|
|
|
|
.get()
|
|
|
|
|
|
.unwrap()
|
|
|
|
|
|
.block_device_table
|
|
|
|
|
|
.lock()
|
|
|
|
|
|
.get(str)
|
|
|
|
|
|
.cloned()
|
2023-02-27 08:18:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-08-28 07:03:28 +00:00
|
|
|
|
pub fn all_devices() -> Vec<(String, Arc<dyn BlockDevice>)> {
|
2023-11-20 12:37:51 +00:00
|
|
|
|
let block_devs = COMPONENT.get().unwrap().block_device_table.lock();
|
|
|
|
|
|
block_devs
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
.map(|(name, device)| (name.clone(), device.clone()))
|
|
|
|
|
|
.collect()
|
2023-08-28 07:03:28 +00:00
|
|
|
|
}
|
2023-02-27 08:18:04 +00:00
|
|
|
|
|
2023-08-28 07:03:28 +00:00
|
|
|
|
static COMPONENT: Once<Component> = Once::new();
|
|
|
|
|
|
|
|
|
|
|
|
#[init_component]
|
|
|
|
|
|
fn component_init() -> Result<(), ComponentInitError> {
|
|
|
|
|
|
let a = Component::init()?;
|
|
|
|
|
|
COMPONENT.call_once(|| a);
|
|
|
|
|
|
Ok(())
|
2023-02-27 08:18:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-08-28 07:03:28 +00:00
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
|
struct Component {
|
2023-11-20 12:37:51 +00:00
|
|
|
|
block_device_table: SpinLock<BTreeMap<String, Arc<dyn BlockDevice>>>,
|
2023-08-28 07:03:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl Component {
|
|
|
|
|
|
pub fn init() -> Result<Self, ComponentInitError> {
|
|
|
|
|
|
Ok(Self {
|
2023-11-20 12:37:51 +00:00
|
|
|
|
block_device_table: SpinLock::new(BTreeMap::new()),
|
2023-08-28 07:03:28 +00:00
|
|
|
|
})
|
2023-02-27 08:18:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|