use crate::util::alloc::METASLAB;
use crate::{BlockDevice, get_block_device};
use alloc::boxed::Box;
use alloc::vec::Vec;
use lazy_static::lazy_static;
use spin::Mutex;
pub struct Vdev {
pub id: usize,
pub device: Box<dyn BlockDevice + Send>,
pub offset_start: u64, pub size: u64,
}
pub struct PoolTopology {
pub vdevs: Vec<Vdev>,
pub total_size: u64,
}
lazy_static! {
pub static ref POOL_TOPOLOGY: Mutex<PoolTopology> =
Mutex::new(PoolTopology::new());
}
impl Default for PoolTopology {
fn default() -> Self {
Self::new()
}
}
impl PoolTopology {
pub const fn new() -> Self {
Self {
vdevs: Vec::new(),
total_size: 0,
}
}
#[cfg(test)]
pub fn reset_for_testing(&mut self) {
self.vdevs.clear();
self.total_size = 0;
}
pub fn add_vdev(&mut self, dev_id: usize) -> Result<(), &'static str> {
let dev = get_block_device(dev_id).ok_or("Device not found")?;
let size = dev.size().unwrap_or(0);
if size == 0 {
return Err("Empty Device");
}
let vdev = Vdev {
id: dev_id,
device: dev,
offset_start: self.total_size,
size,
};
crate::lcpfs_println!(
"[ TOPO ] Added VDEV {} ({} GB) at logical offset 0x{:x}",
dev_id,
size / 1024 / 1024 / 1024,
self.total_size
);
self.vdevs.push(vdev);
self.total_size += size;
let mut alloc = METASLAB.lock();
alloc.grow_pool(self.total_size);
Ok(())
}
pub fn translate(
&mut self,
logical_offset: u64,
) -> Option<(&mut Box<dyn BlockDevice + Send>, u64)> {
for vdev in &mut self.vdevs {
if logical_offset >= vdev.offset_start
&& logical_offset < (vdev.offset_start + vdev.size)
{
let phys_offset = logical_offset - vdev.offset_start;
return Some((&mut vdev.device, phys_offset));
}
}
None
}
}