Compare commits
2 Commits
read-poiso
...
53d773e2ea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
53d773e2ea | ||
|
|
1607f7ebfa |
36
src/io.rs
36
src/io.rs
@@ -20,33 +20,12 @@ pub fn get_stream_length<S: Seek>(stream: &mut S) -> io::Result<u64> {
|
|||||||
len
|
len
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* IO Error Poisoning:
|
|
||||||
*
|
|
||||||
* 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> {
|
||||||
@@ -82,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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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()?;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
Reference in New Issue
Block a user