[thin_check (rust)] add --auto-repair switch

This commit is contained in:
Joe Thornber 2020-08-18 11:47:42 +01:00
parent 8eec84fbec
commit 67a54b4ebc
3 changed files with 46 additions and 28 deletions

View File

@ -5,11 +5,11 @@ use atty::Stream;
use clap::{App, Arg}; use clap::{App, Arg};
use std::path::Path; use std::path::Path;
use std::process; use std::process;
use thinp::file_utils;
use thinp::thin::check::{check, ThinCheckOptions};
use std::sync::Arc;
use std::process::exit; use std::process::exit;
use std::sync::Arc;
use thinp::file_utils;
use thinp::report::*; use thinp::report::*;
use thinp::thin::check::{check, ThinCheckOptions};
fn main() { fn main() {
let parser = App::new("thin_check") let parser = App::new("thin_check")
@ -19,25 +19,27 @@ fn main() {
Arg::with_name("QUIET") Arg::with_name("QUIET")
.help("Suppress output messages, return only exit code.") .help("Suppress output messages, return only exit code.")
.short("q") .short("q")
.long("quiet") .long("quiet"),
) )
.arg( .arg(
Arg::with_name("SB_ONLY") Arg::with_name("SB_ONLY")
.help("Only check the superblock.") .help("Only check the superblock.")
.long("super-block-only") .long("super-block-only")
.value_name("SB_ONLY"), .value_name("SB_ONLY"),
) .arg(
Arg::with_name("AUTO_REPAIR")
.help("Auto repair trivial issues.")
.long("auto-repair"),
) )
.arg( .arg(
Arg::with_name("ignore-non-fatal-errors") Arg::with_name("IGNORE_NON_FATAL")
.help("Only return a non-zero exit code if a fatal error is found.") .help("Only return a non-zero exit code if a fatal error is found.")
.long("ignore-non-fatal-errors") .long("ignore-non-fatal-errors"),
.value_name("IGNORE_NON_FATAL"),
) )
.arg( .arg(
Arg::with_name("clear-needs-check-flag") Arg::with_name("CLEAR_NEEDS_CHECK")
.help("Clears the 'needs_check' flag in the superblock") .help("Clears the 'needs_check' flag in the superblock")
.long("clear-needs-check") .long("clear-needs-check"),
.value_name("CLEAR_NEEDS_CHECK"),
) )
.arg( .arg(
Arg::with_name("OVERRIDE_MAPPING_ROOT") Arg::with_name("OVERRIDE_MAPPING_ROOT")
@ -62,9 +64,7 @@ fn main() {
.arg( .arg(
Arg::with_name("SYNC_IO") Arg::with_name("SYNC_IO")
.help("Force use of synchronous io") .help("Force use of synchronous io")
.long("sync-io") .long("sync-io"),
.value_name("SYNC_IO")
.takes_value(false),
); );
let matches = parser.get_matches(); let matches = parser.get_matches();
@ -82,17 +82,19 @@ fn main() {
} else if atty::is(Stream::Stdout) { } else if atty::is(Stream::Stdout) {
report = std::sync::Arc::new(mk_progress_bar_report()); report = std::sync::Arc::new(mk_progress_bar_report());
} else { } else {
report = Arc::new(mk_simple_report()); report = Arc::new(mk_simple_report());
} }
let opts = ThinCheckOptions { let opts = ThinCheckOptions {
dev: &input_file, dev: &input_file,
async_io: !matches.is_present("SYNC_IO"), async_io: !matches.is_present("SYNC_IO"),
report ignore_non_fatal: matches.is_present("IGNORE_NON_FATAL"),
auto_repair: matches.is_present("AUTO_REPAIR"),
report,
}; };
if let Err(reason) = check(opts) { if let Err(reason) = check(opts) {
println!("Application error: {}", reason); println!("{}", reason);
process::exit(1); process::exit(1);
} }
} }

View File

@ -3,7 +3,7 @@ use std::sync::Mutex;
//------------------------------------------ //------------------------------------------
#[derive(Clone)] #[derive(Clone, PartialEq)]
pub enum ReportOutcome { pub enum ReportOutcome {
Success, Success,
NonFatal, NonFatal,
@ -86,6 +86,11 @@ impl Report {
let mut inner = self.inner.lock().unwrap(); let mut inner = self.inner.lock().unwrap();
inner.complete(); inner.complete();
} }
pub fn get_outcome(&self) -> ReportOutcome {
let outcome = self.outcome.lock().unwrap();
outcome.clone()
}
} }
//------------------------------------------ //------------------------------------------

View File

@ -247,8 +247,7 @@ fn inc_entries(sm: &ASpaceMap, entries: &[IndexEntry]) -> Result<()> {
Ok(()) Ok(())
} }
fn inc_superblock(sm: &ASpaceMap) -> Result<()> fn inc_superblock(sm: &ASpaceMap) -> Result<()> {
{
let mut sm = sm.lock().unwrap(); let mut sm = sm.lock().unwrap();
sm.inc(SUPERBLOCK_LOCATION, 1)?; sm.inc(SUPERBLOCK_LOCATION, 1)?;
Ok(()) Ok(())
@ -261,6 +260,8 @@ const MAX_CONCURRENT_IO: u32 = 1024;
pub struct ThinCheckOptions<'a> { pub struct ThinCheckOptions<'a> {
pub dev: &'a Path, pub dev: &'a Path,
pub async_io: bool, pub async_io: bool,
pub ignore_non_fatal: bool,
pub auto_repair: bool,
pub report: Arc<Report>, pub report: Arc<Report>,
} }
@ -329,7 +330,6 @@ fn check_mapping_bottom_level(
std::process::abort(); std::process::abort();
} }
Ok(_result) => { Ok(_result) => {
//eprintln!("checked thin_dev {} -> {:?}", thin_id, result);
} }
} }
}); });
@ -359,6 +359,15 @@ fn mk_context(opts: ThinCheckOptions) -> Result<Context> {
}) })
} }
fn bail_out(ctx: &Context, task: &str) -> Result<()> {
use ReportOutcome::*;
match ctx.report.get_outcome() {
Fatal => Err(anyhow!(format!("Check of {} failed, ending check early.", task))),
_ => Ok(()),
}
}
pub fn check(opts: ThinCheckOptions) -> Result<()> { pub fn check(opts: ThinCheckOptions) -> Result<()> {
let ctx = mk_context(opts)?; let ctx = mk_context(opts)?;
@ -370,12 +379,7 @@ pub fn check(opts: ThinCheckOptions) -> Result<()> {
// superblock // superblock
let sb = read_superblock(engine.as_ref(), SUPERBLOCK_LOCATION)?; let sb = read_superblock(engine.as_ref(), SUPERBLOCK_LOCATION)?;
let metadata_root = unpack::<SMRoot>(&sb.metadata_sm_root[0..])?;
let nr_allocated_metadata;
{
let root = unpack::<SMRoot>(&sb.metadata_sm_root[0..])?;
nr_allocated_metadata = root.nr_allocated;
}
// Device details. We read this once to get the number of thin devices, and hence the // Device details. We read this once to get the number of thin devices, and hence the
// maximum metadata ref count. Then create metadata space map, and reread to increment // maximum metadata ref count. Then create metadata space map, and reread to increment
@ -393,8 +397,11 @@ pub fn check(opts: ThinCheckOptions) -> Result<()> {
sb.details_root, sb.details_root,
)?; )?;
let (tid, stop_progress) = let (tid, stop_progress) = spawn_progress_thread(
spawn_progress_thread(metadata_sm.clone(), nr_allocated_metadata, report.clone())?; metadata_sm.clone(),
metadata_root.nr_allocated,
report.clone(),
)?;
// mapping top level // mapping top level
let roots = let roots =
@ -405,6 +412,7 @@ pub fn check(opts: ThinCheckOptions) -> Result<()> {
let root = unpack::<SMRoot>(&sb.data_sm_root[0..])?; let root = unpack::<SMRoot>(&sb.data_sm_root[0..])?;
let data_sm = core_sm(root.nr_blocks, nr_devs as u32); let data_sm = core_sm(root.nr_blocks, nr_devs as u32);
check_mapping_bottom_level(&ctx, &metadata_sm, &data_sm, &roots)?; check_mapping_bottom_level(&ctx, &metadata_sm, &data_sm, &roots)?;
bail_out(&ctx, "mapping tree")?;
report.set_sub_title("data space map"); report.set_sub_title("data space map");
let root = unpack::<SMRoot>(&sb.data_sm_root[0..])?; let root = unpack::<SMRoot>(&sb.data_sm_root[0..])?;
@ -426,6 +434,7 @@ pub fn check(opts: ThinCheckOptions) -> Result<()> {
data_sm.clone(), data_sm.clone(),
root, root,
)?; )?;
bail_out(&ctx, "data space map")?;
report.set_sub_title("metadata space map"); report.set_sub_title("metadata space map");
let root = unpack::<SMRoot>(&sb.metadata_sm_root[0..])?; let root = unpack::<SMRoot>(&sb.metadata_sm_root[0..])?;
@ -461,6 +470,8 @@ pub fn check(opts: ThinCheckOptions) -> Result<()> {
} }
tid.join(); tid.join();
bail_out(&ctx, "metadata space map")?;
Ok(()) Ok(())
} }