DirectIO is working! Also a bit more cleanup.

This commit is contained in:
Cutieguwu
2026-01-01 23:22:26 -05:00
parent 1607f7ebfa
commit 53d773e2ea
5 changed files with 30 additions and 34 deletions

View File

@@ -20,39 +20,12 @@ pub fn get_stream_length<S: Seek>(stream: &mut S) -> io::Result<u64> {
len len
} }
/*
* IO Error Poisoning:
*
*
* Attempt 1:
*
* Wrap C calls w/ `ffi`. Most importantly, execute the `close()` through C.
*
*
* Attempt 2:
*
* Return to using safe-on-the-surface Rust, but attempt to execute the reads
* via a separate thread, hoping that the observed poisoning goes away with the
* thread being closed and doesn't affect the main thread.
*
* May need `mpsc` to transfer data without spawning a thread on every read.
*/
pub fn load_input() -> anyhow::Result<File> { pub fn load_input() -> anyhow::Result<File> {
OpenOptions::new() OpenOptions::new()
.read(true) .read(true)
.custom_flags(libc::O_DIRECT) .custom_flags(libc::O_DIRECT)
.open(&CONFIG.input) .open(&CONFIG.input)
.with_context(|| format!("Failed to open input file: {}", &CONFIG.input.display())) .with_context(|| format!("Failed to open input file: {}", &CONFIG.input.display()))
/*
use std::ffi::CString;
use std::os::fd::FromRawFd;
let path = CString::new(CONFIG.input.to_str().unwrap().to_owned()).unwrap();
let flags = libc::O_DIRECT | libc::O_RDONLY;
let f = unsafe { File::from_raw_fd(libc::open(path.as_ptr(), flags)) };
*/
} }
pub fn load_output() -> anyhow::Result<File> { pub fn load_output() -> anyhow::Result<File> {
@@ -88,3 +61,18 @@ pub fn load_map_write() -> anyhow::Result<File> {
) )
}) })
} }
#[repr(C, align(512))]
pub struct DirectIOBuffer(pub [u8; crate::MAX_BUFFER_SIZE]);
impl Default for DirectIOBuffer {
fn default() -> Self {
Self([crate::FB_NULL_VALUE; _])
}
}
impl From<[u8; crate::MAX_BUFFER_SIZE]> for DirectIOBuffer {
fn from(value: [u8; crate::MAX_BUFFER_SIZE]) -> Self {
Self(value)
}
}

View File

@@ -11,6 +11,8 @@ use anyhow;
const FB_SECTOR_SIZE: usize = 2048; const FB_SECTOR_SIZE: usize = 2048;
const FB_NULL_VALUE: u8 = 0; const FB_NULL_VALUE: u8 = 0;
const MAX_BUFFER_SIZE: usize = FB_SECTOR_SIZE * 16;
fn main() -> anyhow::Result<()> { fn main() -> anyhow::Result<()> {
let mut recover_tool = Recover::new()?; let mut recover_tool = Recover::new()?;
recover_tool.run()?; recover_tool.run()?;

View File

@@ -21,6 +21,7 @@ impl Default for Cluster {
impl Cluster { impl Cluster {
/// Breaks apart into a vec of clusters, /// Breaks apart into a vec of clusters,
/// each of cluster_size, excepting last. /// each of cluster_size, excepting last.
#[allow(dead_code)]
pub fn subdivide(&mut self, cluster_len: usize) -> Vec<Cluster> { pub fn subdivide(&mut self, cluster_len: usize) -> Vec<Cluster> {
let domain_len = self.domain.len(); let domain_len = self.domain.len();
let mut start = self.domain.start; let mut start = self.domain.start;
@@ -49,6 +50,8 @@ impl Cluster {
clusters clusters
} }
// This is used in unit tests at present. Ideally it probably shouldn't exist.
#[allow(dead_code)]
pub fn set_stage(&mut self, stage: Stage) -> &mut Self { pub fn set_stage(&mut self, stage: Stage) -> &mut Self {
self.stage = stage; self.stage = stage;
self self

View File

@@ -16,6 +16,7 @@ impl Default for Domain {
impl Domain { impl Domain {
/// Return length of domain in sectors. /// Return length of domain in sectors.
#[allow(dead_code)]
pub fn len(self) -> usize { pub fn len(self) -> usize {
self.end - self.start self.end - self.start
} }

View File

@@ -2,13 +2,13 @@ use std::fs::File;
use std::io::{BufWriter, Read, Seek, SeekFrom, Write}; use std::io::{BufWriter, Read, Seek, SeekFrom, Write};
use std::usize; use std::usize;
use anyhow::{Context, anyhow}; use anyhow::Context;
use crate::cli::CONFIG; use crate::cli::CONFIG;
use crate::io::DirectIOBuffer;
use crate::mapping::prelude::*; use crate::mapping::prelude::*;
#[derive(Debug)] #[derive(Debug)]
#[allow(dead_code)]
pub struct Recover { pub struct Recover {
input: File, input: File,
output: BufWriter<File>, output: BufWriter<File>,
@@ -90,11 +90,12 @@ impl Recover {
/// Attempt to copy all untested blocks. /// Attempt to copy all untested blocks.
fn copy_untested(&mut self) -> anyhow::Result<()> { fn copy_untested(&mut self) -> anyhow::Result<()> {
let mut buf = DirectIOBuffer::default();
for untested in self.map.get_clusters(Stage::Untested) { for untested in self.map.get_clusters(Stage::Untested) {
// Caching. // Caching.
let mut read_position: usize; let mut read_position: usize;
let mut cluster: Cluster; let mut cluster: Cluster;
let mut buf: Vec<u8>;
let mut buf_capacity = self.get_buf_capacity() as usize; let mut buf_capacity = self.get_buf_capacity() as usize;
dbg!(untested.domain); dbg!(untested.domain);
@@ -104,7 +105,6 @@ impl Recover {
dbg!(read_position); dbg!(read_position);
buf_capacity = buf_capacity.min(untested.domain.end - read_position); buf_capacity = buf_capacity.min(untested.domain.end - read_position);
buf = vec![crate::FB_NULL_VALUE; buf_capacity];
cluster = Cluster { cluster = Cluster {
domain: Domain { domain: Domain {
@@ -114,7 +114,7 @@ impl Recover {
stage: Stage::Intact, stage: Stage::Intact,
}; };
if let Err(err) = self.input.read_exact(&mut buf) { if let Err(err) = self.input.read_exact(&mut buf.0) {
// If buf were zeroed out before every read, one could theoretically recover // If buf were zeroed out before every read, one could theoretically recover
// part of that read given the assumption that all null values from the end to // part of that read given the assumption that all null values from the end to
// the first non-null value are unread, and some further padding from the last // the first non-null value are unread, and some further padding from the last
@@ -141,7 +141,7 @@ impl Recover {
if cluster.stage == Stage::Intact { if cluster.stage == Stage::Intact {
self.output self.output
.write_all(&buf[0..buf_capacity]) .write_all(&buf.0[0..buf_capacity])
.context("Failed to write data to output file")?; .context("Failed to write data to output file")?;
} }
@@ -151,6 +151,8 @@ impl Recover {
} }
} }
drop(buf);
self.map.write_to(&mut crate::io::load_map_write()?)?; self.map.write_to(&mut crate::io::load_map_write()?)?;
Ok(()) Ok(())
@@ -159,7 +161,7 @@ impl Recover {
/// Set buffer capacity as cluster length in bytes. /// Set buffer capacity as cluster length in bytes.
/// Varies depending on the recovery stage. /// Varies depending on the recovery stage.
fn get_buf_capacity(&mut self) -> u64 { fn get_buf_capacity(&mut self) -> u64 {
CONFIG.sector_size as u64 * CONFIG.cluster_length as u64 crate::MAX_BUFFER_SIZE.min(CONFIG.sector_size * CONFIG.cluster_length) as u64
} }
/// Reloads the input and restores the seek position. /// Reloads the input and restores the seek position.