From 85581cdf5a47d5856fd6d1c78c5afd9faf1c7dd0 Mon Sep 17 00:00:00 2001 From: Ming-Hung Tsai Date: Fri, 16 Jul 2021 20:13:20 +0800 Subject: [PATCH] [thin_repair (rust)] First pass at thin_repair --- src/bin/thin_repair.rs | 86 ++++++++++++++++++++++++++++++++++++++++++ src/thin/mod.rs | 1 + src/thin/repair.rs | 71 ++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+) create mode 100644 src/bin/thin_repair.rs create mode 100644 src/thin/repair.rs diff --git a/src/bin/thin_repair.rs b/src/bin/thin_repair.rs new file mode 100644 index 0000000..7d41bf3 --- /dev/null +++ b/src/bin/thin_repair.rs @@ -0,0 +1,86 @@ +extern crate clap; +extern crate thinp; + +use atty::Stream; +use clap::{App, Arg}; +use std::path::Path; +use std::process; +use std::process::exit; +use std::sync::Arc; +use thinp::file_utils; +use thinp::report::*; +use thinp::thin::repair::{repair, ThinRepairOptions}; + +fn main() { + let parser = App::new("thin_repair") + .version(thinp::version::tools_version()) + .about("Repair thin-provisioning metadata, and write it to different device or file") + // flags + .arg( + Arg::with_name("ASYNC_IO") + .help("Force use of io_uring for synchronous io") + .long("async-io") + .hidden(true), + ) + .arg( + Arg::with_name("QUIET") + .help("Suppress output messages, return only exit code.") + .short("q") + .long("quiet"), + ) + // options + .arg( + Arg::with_name("INPUT") + .help("Specify the input device") + .short("i") + .long("input") + .value_name("INPUT") + .required(true), + ) + .arg( + Arg::with_name("OUTPUT") + .help("Specify the output device") + .short("o") + .long("output") + .value_name("OUTPUT") + .required(true), + ) + .arg( + Arg::with_name("OVERRIDE_MAPPING_ROOT") + .help("Specify a mapping root to use") + .long("override-mapping-root") + .value_name("OVERRIDE_MAPPING_ROOT") + .takes_value(true), + ); + + let matches = parser.get_matches(); + let input_file = Path::new(matches.value_of("INPUT").unwrap()); + let output_file = Path::new(matches.value_of("OUTPUT").unwrap()); + + if !file_utils::file_exists(input_file) { + eprintln!("Couldn't find input file '{:?}'.", &input_file); + exit(1); + } + + let report; + + if matches.is_present("QUIET") { + report = std::sync::Arc::new(mk_quiet_report()); + } else if atty::is(Stream::Stdout) { + report = std::sync::Arc::new(mk_progress_bar_report()); + } else { + report = Arc::new(mk_simple_report()); + } + + let opts = ThinRepairOptions { + input: &input_file, + output: &output_file, + async_io: matches.is_present("ASYNC_IO"), + report, + }; + + if let Err(reason) = repair(opts) { + eprintln!("{}", reason); + process::exit(1); + } +} diff --git a/src/thin/mod.rs b/src/thin/mod.rs index 101c9c2..1f44e9e 100644 --- a/src/thin/mod.rs +++ b/src/thin/mod.rs @@ -4,6 +4,7 @@ pub mod device_detail; pub mod dump; pub mod ir; pub mod metadata; +pub mod repair; pub mod restore; pub mod runs; pub mod superblock; diff --git a/src/thin/repair.rs b/src/thin/repair.rs new file mode 100644 index 0000000..89d6e09 --- /dev/null +++ b/src/thin/repair.rs @@ -0,0 +1,71 @@ +use anyhow::Result; +use std::path::Path; +use std::sync::Arc; + +use crate::io_engine::*; +use crate::pdata::space_map::*; +use crate::report::*; +use crate::thin::dump::*; +use crate::thin::metadata::*; +use crate::thin::restore::*; +use crate::thin::superblock::*; +use crate::write_batcher::*; + +//------------------------------------------ + +pub struct ThinRepairOptions<'a> { + pub input: &'a Path, + pub output: &'a Path, + pub async_io: bool, + pub report: Arc, +} + +struct Context { + report: Arc, + engine_in: Arc, + engine_out: Arc, +} + +const MAX_CONCURRENT_IO: u32 = 1024; + +fn new_context(opts: &ThinRepairOptions) -> Result { + let engine_in: Arc; + let engine_out: Arc; + + if opts.async_io { + engine_in = Arc::new(AsyncIoEngine::new(opts.input, MAX_CONCURRENT_IO, true)?); + engine_out = Arc::new(AsyncIoEngine::new(opts.output, MAX_CONCURRENT_IO, true)?); + } else { + let nr_threads = std::cmp::max(8, num_cpus::get() * 2); + engine_in = Arc::new(SyncIoEngine::new(opts.input, nr_threads, true)?); + engine_out = Arc::new(SyncIoEngine::new(opts.output, nr_threads, true)?); + } + + Ok(Context { + report: opts.report.clone(), + engine_in, + engine_out, + }) +} + +//------------------------------------------ + +pub fn repair(opts: ThinRepairOptions) -> Result<()> { + let ctx = new_context(&opts)?; + + let sb = read_superblock(ctx.engine_in.as_ref(), SUPERBLOCK_LOCATION)?; + let md = build_metadata(ctx.engine_in.clone(), &sb)?; + let md = optimise_metadata(md)?; + + let sm = core_sm(ctx.engine_out.get_nr_blocks(), u32::MAX); + let mut w = WriteBatcher::new( + ctx.engine_out.clone(), + sm.clone(), + ctx.engine_out.get_batch_size(), + ); + let mut restorer = Restorer::new(&mut w, ctx.report); + + dump_metadata(ctx.engine_in, &mut restorer, &sb, &md) +} + +//------------------------------------------