From 67a54b4ebc4d5f96589bbb01462895f1d96c6e65 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 18 Aug 2020 11:47:42 +0100 Subject: [PATCH] [thin_check (rust)] add --auto-repair switch --- src/bin/thin_check.rs | 34 ++++++++++++++++++---------------- src/report.rs | 7 ++++++- src/thin/check.rs | 33 ++++++++++++++++++++++----------- 3 files changed, 46 insertions(+), 28 deletions(-) diff --git a/src/bin/thin_check.rs b/src/bin/thin_check.rs index 236c508..59e9696 100644 --- a/src/bin/thin_check.rs +++ b/src/bin/thin_check.rs @@ -5,11 +5,11 @@ use atty::Stream; use clap::{App, Arg}; use std::path::Path; use std::process; -use thinp::file_utils; -use thinp::thin::check::{check, ThinCheckOptions}; -use std::sync::Arc; use std::process::exit; +use std::sync::Arc; +use thinp::file_utils; use thinp::report::*; +use thinp::thin::check::{check, ThinCheckOptions}; fn main() { let parser = App::new("thin_check") @@ -19,25 +19,27 @@ fn main() { Arg::with_name("QUIET") .help("Suppress output messages, return only exit code.") .short("q") - .long("quiet") + .long("quiet"), ) .arg( Arg::with_name("SB_ONLY") .help("Only check the superblock.") .long("super-block-only") .value_name("SB_ONLY"), + ) .arg( + Arg::with_name("AUTO_REPAIR") + .help("Auto repair trivial issues.") + .long("auto-repair"), ) .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.") - .long("ignore-non-fatal-errors") - .value_name("IGNORE_NON_FATAL"), + .long("ignore-non-fatal-errors"), ) .arg( - Arg::with_name("clear-needs-check-flag") + Arg::with_name("CLEAR_NEEDS_CHECK") .help("Clears the 'needs_check' flag in the superblock") - .long("clear-needs-check") - .value_name("CLEAR_NEEDS_CHECK"), + .long("clear-needs-check"), ) .arg( Arg::with_name("OVERRIDE_MAPPING_ROOT") @@ -62,9 +64,7 @@ fn main() { .arg( Arg::with_name("SYNC_IO") .help("Force use of synchronous io") - .long("sync-io") - .value_name("SYNC_IO") - .takes_value(false), + .long("sync-io"), ); let matches = parser.get_matches(); @@ -82,17 +82,19 @@ fn main() { } else if atty::is(Stream::Stdout) { report = std::sync::Arc::new(mk_progress_bar_report()); } else { - report = Arc::new(mk_simple_report()); + report = Arc::new(mk_simple_report()); } let opts = ThinCheckOptions { dev: &input_file, 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) { - println!("Application error: {}", reason); + println!("{}", reason); process::exit(1); } } diff --git a/src/report.rs b/src/report.rs index 1fed51f..dd87a48 100644 --- a/src/report.rs +++ b/src/report.rs @@ -3,7 +3,7 @@ use std::sync::Mutex; //------------------------------------------ -#[derive(Clone)] +#[derive(Clone, PartialEq)] pub enum ReportOutcome { Success, NonFatal, @@ -86,6 +86,11 @@ impl Report { let mut inner = self.inner.lock().unwrap(); inner.complete(); } + + pub fn get_outcome(&self) -> ReportOutcome { + let outcome = self.outcome.lock().unwrap(); + outcome.clone() + } } //------------------------------------------ diff --git a/src/thin/check.rs b/src/thin/check.rs index 2073502..243b6b3 100644 --- a/src/thin/check.rs +++ b/src/thin/check.rs @@ -247,8 +247,7 @@ fn inc_entries(sm: &ASpaceMap, entries: &[IndexEntry]) -> Result<()> { Ok(()) } -fn inc_superblock(sm: &ASpaceMap) -> Result<()> -{ +fn inc_superblock(sm: &ASpaceMap) -> Result<()> { let mut sm = sm.lock().unwrap(); sm.inc(SUPERBLOCK_LOCATION, 1)?; Ok(()) @@ -261,6 +260,8 @@ const MAX_CONCURRENT_IO: u32 = 1024; pub struct ThinCheckOptions<'a> { pub dev: &'a Path, pub async_io: bool, + pub ignore_non_fatal: bool, + pub auto_repair: bool, pub report: Arc, } @@ -329,7 +330,6 @@ fn check_mapping_bottom_level( std::process::abort(); } Ok(_result) => { - //eprintln!("checked thin_dev {} -> {:?}", thin_id, result); } } }); @@ -359,6 +359,15 @@ fn mk_context(opts: ThinCheckOptions) -> Result { }) } +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<()> { let ctx = mk_context(opts)?; @@ -370,12 +379,7 @@ pub fn check(opts: ThinCheckOptions) -> Result<()> { // superblock let sb = read_superblock(engine.as_ref(), SUPERBLOCK_LOCATION)?; - - let nr_allocated_metadata; - { - let root = unpack::(&sb.metadata_sm_root[0..])?; - nr_allocated_metadata = root.nr_allocated; - } + let metadata_root = unpack::(&sb.metadata_sm_root[0..])?; // 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 @@ -393,8 +397,11 @@ pub fn check(opts: ThinCheckOptions) -> Result<()> { sb.details_root, )?; - let (tid, stop_progress) = - spawn_progress_thread(metadata_sm.clone(), nr_allocated_metadata, report.clone())?; + let (tid, stop_progress) = spawn_progress_thread( + metadata_sm.clone(), + metadata_root.nr_allocated, + report.clone(), + )?; // mapping top level let roots = @@ -405,6 +412,7 @@ pub fn check(opts: ThinCheckOptions) -> Result<()> { let root = unpack::(&sb.data_sm_root[0..])?; let data_sm = core_sm(root.nr_blocks, nr_devs as u32); check_mapping_bottom_level(&ctx, &metadata_sm, &data_sm, &roots)?; + bail_out(&ctx, "mapping tree")?; report.set_sub_title("data space map"); let root = unpack::(&sb.data_sm_root[0..])?; @@ -426,6 +434,7 @@ pub fn check(opts: ThinCheckOptions) -> Result<()> { data_sm.clone(), root, )?; + bail_out(&ctx, "data space map")?; report.set_sub_title("metadata space map"); let root = unpack::(&sb.metadata_sm_root[0..])?; @@ -461,6 +470,8 @@ pub fn check(opts: ThinCheckOptions) -> Result<()> { } tid.join(); + bail_out(&ctx, "metadata space map")?; + Ok(()) }