use crate::BLOCK_DEVICES;
use alloc::vec;
use alloc::vec::Vec;
use lazy_static::lazy_static;
use spin::Mutex;
const BLOCK_SIZE: usize = 512;
const POOL_SIZE: usize = 16;
struct BufferPool {
buffers: Vec<Vec<u8>>,
}
impl BufferPool {
fn new() -> Self {
let mut buffers = Vec::with_capacity(POOL_SIZE);
for _ in 0..POOL_SIZE {
buffers.push(vec![0u8; BLOCK_SIZE]);
}
Self { buffers }
}
fn acquire(&mut self) -> Vec<u8> {
self.buffers.pop().unwrap_or_else(|| vec![0u8; BLOCK_SIZE])
}
fn release(&mut self, mut buf: Vec<u8>) {
if self.buffers.len() < POOL_SIZE && buf.len() == BLOCK_SIZE {
buf.fill(0);
self.buffers.push(buf);
}
}
}
lazy_static! {
static ref BUFFER_POOL: Mutex<BufferPool> = Mutex::new(BufferPool::new());
}
#[inline]
fn acquire_buffer() -> Vec<u8> {
BUFFER_POOL.lock().acquire()
}
#[inline]
fn release_buffer(buf: Vec<u8>) {
BUFFER_POOL.lock().release(buf);
}
#[inline]
fn xor_blocks(a: &[u8], b: &[u8], out: &mut [u8]) {
debug_assert_eq!(a.len(), b.len());
debug_assert_eq!(a.len(), out.len());
let len = a.len();
let chunks = len / 8;
for i in 0..chunks {
let offset = i * 8;
let a_chunk = u64::from_ne_bytes([
a[offset],
a[offset + 1],
a[offset + 2],
a[offset + 3],
a[offset + 4],
a[offset + 5],
a[offset + 6],
a[offset + 7],
]);
let b_chunk = u64::from_ne_bytes([
b[offset],
b[offset + 1],
b[offset + 2],
b[offset + 3],
b[offset + 4],
b[offset + 5],
b[offset + 6],
b[offset + 7],
]);
let result = (a_chunk ^ b_chunk).to_ne_bytes();
out[offset..offset + 8].copy_from_slice(&result);
}
let remainder_start = chunks * 8;
for i in remainder_start..len {
out[i] = a[i] ^ b[i];
}
}
pub struct LcpfsController {
data_disks: [usize; 2],
parity_disk: usize,
}
impl LcpfsController {
pub fn new(disk0: usize, disk1: usize, disk2: usize) -> Self {
Self {
data_disks: [disk0, disk1],
parity_disk: disk2,
}
}
fn reconstruct(&self, good_data: &[u8], parity: &[u8]) -> Vec<u8> {
let mut recovered = vec![0u8; 512];
xor_blocks(good_data, parity, &mut recovered);
recovered
}
pub fn read_stripe(&self, stripe_index: usize) -> Result<Vec<u8>, &'static str> {
let mut devices = BLOCK_DEVICES.lock();
let mut d0 = acquire_buffer();
let mut d1 = acquire_buffer();
let mut p = acquire_buffer();
let r0: Option<Result<(), &'static str>> = devices
.get_mut(self.data_disks[0])
.map(|d| d.read_block(stripe_index, &mut d0));
let r1: Option<Result<(), &'static str>> = devices
.get_mut(self.data_disks[1])
.map(|d| d.read_block(stripe_index, &mut d1));
let rp: Option<Result<(), &'static str>> = devices
.get_mut(self.parity_disk)
.map(|d| d.read_block(stripe_index, &mut p));
let d0_ok = matches!(r0, Some(Ok(_)));
let d1_ok = matches!(r1, Some(Ok(_)));
let p_ok = matches!(rp, Some(Ok(_)));
if !d0_ok && !d1_ok {
return Err("DATA LOSS: Critical Stripe Failure");
}
if !d0_ok && d1_ok && p_ok {
crate::lcpfs_println!("[ ZFS ] BIT ROT DETECTED on Disk 0. Healing...");
d0 = self.reconstruct(&d1, &p);
if let Some(dev) = devices.get_mut(self.data_disks[0]) {
let _: Result<(), &'static str> = dev.write_block(stripe_index, &d0); crate::lcpfs_println!("[ ZFS ] Disk 0 Repaired.");
}
}
if d0_ok && !d1_ok && p_ok {
crate::lcpfs_println!("[ ZFS ] BIT ROT DETECTED on Disk 1. Healing...");
d1 = self.reconstruct(&d0, &p);
if let Some(dev) = devices.get_mut(self.data_disks[1]) {
let _: Result<(), &'static str> = dev.write_block(stripe_index, &d1); crate::lcpfs_println!("[ ZFS ] Disk 1 Repaired.");
}
}
let mut result = Vec::with_capacity(1024);
result.extend_from_slice(&d0);
result.extend_from_slice(&d1);
release_buffer(d0);
release_buffer(d1);
release_buffer(p);
Ok(result)
}
pub fn read_stripe_with_healing(&self, stripe_index: usize) -> Result<Vec<u8>, &'static str> {
use crate::integrity::checksum::Checksum;
let mut devices = BLOCK_DEVICES.lock();
let mut d0 = acquire_buffer();
let mut d1 = acquire_buffer();
let mut p = acquire_buffer();
let r0 = devices
.get_mut(self.data_disks[0])
.map(|d| d.read_block(stripe_index, &mut d0));
let r1 = devices
.get_mut(self.data_disks[1])
.map(|d| d.read_block(stripe_index, &mut d1));
let rp = devices
.get_mut(self.parity_disk)
.map(|d| d.read_block(stripe_index, &mut p));
let d0_read_ok = r0.map(|r| r.is_ok()).unwrap_or(false);
let d1_read_ok = r1.map(|r| r.is_ok()).unwrap_or(false);
let p_read_ok = rp.map(|r| r.is_ok()).unwrap_or(false);
let mut computed_p = acquire_buffer();
xor_blocks(&d0, &d1, &mut computed_p);
let parity_matches = computed_p == p;
if !parity_matches {
let ck_d0 = Checksum::calculate(&d0);
let ck_d1 = Checksum::calculate(&d1);
let ck_p = Checksum::calculate(&p);
let d0_candidate = self.reconstruct(&d1, &p);
let ck_d0_candidate = Checksum::calculate(&d0_candidate);
let d1_candidate = self.reconstruct(&d0, &p);
let ck_d1_candidate = Checksum::calculate(&d1_candidate);
let d0_diff = (ck_d0.first() ^ ck_d0_candidate.first()).count_ones()
+ (ck_d0.second() ^ ck_d0_candidate.second()).count_ones();
let d1_diff = (ck_d1.first() ^ ck_d1_candidate.first()).count_ones()
+ (ck_d1.second() ^ ck_d1_candidate.second()).count_ones();
if !d0_read_ok || d0_diff > d1_diff {
crate::lcpfs_println!(
"[ ZFS ] Corruption detected on Disk 0 (diff={}). Healing...",
d0_diff
);
d0 = d0_candidate;
if let Some(dev) = devices.get_mut(self.data_disks[0]) {
match dev.write_block(stripe_index, &d0) {
Ok(_) => crate::lcpfs_println!("[ ZFS ] Disk 0 repaired."),
Err(e) => crate::lcpfs_println!(
"[ ZFS ] ERROR: Disk 0 repair FAILED: {:?}. Corruption persists!",
e
),
}
}
} else if !d1_read_ok || d1_diff > d0_diff {
crate::lcpfs_println!(
"[ ZFS ] Corruption detected on Disk 1 (diff={}). Healing...",
d1_diff
);
d1 = d1_candidate;
if let Some(dev) = devices.get_mut(self.data_disks[1]) {
match dev.write_block(stripe_index, &d1) {
Ok(_) => crate::lcpfs_println!("[ ZFS ] Disk 1 repaired."),
Err(e) => crate::lcpfs_println!(
"[ ZFS ] ERROR: Disk 1 repair FAILED: {:?}. Corruption persists!",
e
),
}
}
} else if !p_read_ok {
crate::lcpfs_println!("[ ZFS ] Parity disk read failure. Recalculating parity...");
core::mem::swap(&mut p, &mut computed_p);
if let Some(dev) = devices.get_mut(self.parity_disk) {
match dev.write_block(stripe_index, &p) {
Ok(_) => crate::lcpfs_println!("[ ZFS ] Parity repaired."),
Err(e) => crate::lcpfs_println!(
"[ ZFS ] ERROR: Parity repair FAILED: {:?}. Parity inconsistent!",
e
),
}
}
} else {
crate::lcpfs_println!("[ ZFS ] Parity inconsistency. Recalculating parity...");
if let Some(dev) = devices.get_mut(self.parity_disk) {
if let Err(e) = dev.write_block(stripe_index, &computed_p) {
crate::lcpfs_println!(
"[ ZFS ] ERROR: Parity update FAILED: {:?}. Parity inconsistent!",
e
);
}
}
}
}
let mut result = Vec::with_capacity(1024);
result.extend_from_slice(&d0);
result.extend_from_slice(&d1);
release_buffer(d0);
release_buffer(d1);
release_buffer(p);
release_buffer(computed_p);
Ok(result)
}
pub fn write_stripe(&self, stripe_index: usize, data: &[u8]) -> Result<(), &'static str> {
if data.len() != 1024 {
return Err("Invalid Stripe Size");
}
let d0 = &data[0..512];
let d1 = &data[512..1024];
let mut p = acquire_buffer();
xor_blocks(d0, d1, &mut p);
let mut devices = BLOCK_DEVICES.lock();
if let Some(dev) = devices.get_mut(self.data_disks[0]) {
dev.write_block(stripe_index, d0)?;
} else {
return Err("Data disk 0 not found");
}
if let Some(dev) = devices.get_mut(self.data_disks[1]) {
dev.write_block(stripe_index, d1)?;
} else {
return Err("Data disk 1 not found");
}
if let Some(dev) = devices.get_mut(self.parity_disk) {
dev.write_block(stripe_index, &p)?;
} else {
release_buffer(p);
return Err("Parity disk not found");
}
release_buffer(p);
Ok(())
}
pub fn write_data(&self, offset: u64, data: &[u8]) -> Result<(), &'static str> {
let stripe_size = 1024usize; let start_stripe = (offset / stripe_size as u64) as usize;
let mut pos = 0;
let mut stripe_idx = start_stripe;
while pos < data.len() {
let remaining = data.len() - pos;
let chunk_size = core::cmp::min(stripe_size, remaining);
let mut stripe_buf = vec![0u8; stripe_size];
stripe_buf[..chunk_size].copy_from_slice(&data[pos..pos + chunk_size]);
self.write_stripe(stripe_idx, &stripe_buf)?;
pos += chunk_size;
stripe_idx += 1;
}
Ok(())
}
}