From d1fed5f5ec4bba147be8b3116d3ca411e30c56fc Mon Sep 17 00:00:00 2001 From: Ming-Hung Tsai Date: Thu, 23 Jul 2020 17:11:01 +0800 Subject: [PATCH] [thin_generate_damage] Introduce tools to generate metadata damage --- Makefile.in | 2 + thin-provisioning/commands.cc | 1 + thin-provisioning/commands.h | 7 ++ thin-provisioning/damage_generator.cc | 66 ++++++++++ thin-provisioning/damage_generator.h | 22 ++++ thin-provisioning/thin_generate_damage.cc | 144 ++++++++++++++++++++++ 6 files changed, 242 insertions(+) create mode 100644 thin-provisioning/damage_generator.cc create mode 100644 thin-provisioning/damage_generator.h create mode 100644 thin-provisioning/thin_generate_damage.cc diff --git a/Makefile.in b/Makefile.in index 97b86c4..63b46b3 100644 --- a/Makefile.in +++ b/Makefile.in @@ -123,11 +123,13 @@ SOURCE=\ thin-provisioning/xml_format.cc DEVTOOLS_SOURCE=\ + thin-provisioning/damage_generator.cc \ thin-provisioning/thin_journal.cc \ thin-provisioning/thin_journal_check.cc \ thin-provisioning/thin_ll_dump.cc \ thin-provisioning/thin_ll_restore.cc \ thin-provisioning/thin_show_duplicates.cc \ + thin-provisioning/thin_generate_damage.cc \ thin-provisioning/thin_generate_metadata.cc \ thin-provisioning/thin_generate_mappings.cc \ thin-provisioning/variable_chunk_stream.cc \ diff --git a/thin-provisioning/commands.cc b/thin-provisioning/commands.cc index 23f4b0e..23399af 100644 --- a/thin-provisioning/commands.cc +++ b/thin-provisioning/commands.cc @@ -22,6 +22,7 @@ thin_provisioning::register_thin_commands(base::application &app) app.add_cmd(command::ptr(new thin_ll_dump_cmd())); app.add_cmd(command::ptr(new thin_ll_restore_cmd())); app.add_cmd(command::ptr(new thin_scan_cmd())); + app.add_cmd(command::ptr(new thin_generate_damage_cmd())); app.add_cmd(command::ptr(new thin_generate_metadata_cmd())); app.add_cmd(command::ptr(new thin_generate_mappings_cmd())); app.add_cmd(command::ptr(new thin_show_duplicates_cmd())); diff --git a/thin-provisioning/commands.h b/thin-provisioning/commands.h index e3a41e7..906c340 100644 --- a/thin-provisioning/commands.h +++ b/thin-provisioning/commands.h @@ -103,6 +103,13 @@ namespace thin_provisioning { virtual int run(int argc, char **argv); }; + class thin_generate_damage_cmd : public base::command { + public: + thin_generate_damage_cmd(); + virtual void usage(std::ostream &out) const; + virtual int run(int argc, char **argv); + }; + class thin_generate_metadata_cmd : public base::command { public: thin_generate_metadata_cmd(); diff --git a/thin-provisioning/damage_generator.cc b/thin-provisioning/damage_generator.cc new file mode 100644 index 0000000..1518296 --- /dev/null +++ b/thin-provisioning/damage_generator.cc @@ -0,0 +1,66 @@ +#include "damage_generator.h" + +using namespace thin_provisioning; + +//---------------------------------------------------------------- + +namespace { + void find_blocks(space_map::ptr sm, + block_address nr_blocks, + ref_t expected, + std::set &found) { + block_address sm_size = sm->get_nr_blocks(); + base::run_set visited; + block_address nr_visited = 0; + + srand(time(NULL)); + while (nr_blocks) { + if (nr_visited == sm_size) + break; + + block_address b = rand() % sm_size; + if (visited.member(b)) + continue; + + ref_t c = sm->get_count(b); + if (c == expected) { + found.insert(b); + --nr_blocks; + } + + visited.add(b); + ++nr_visited; + } + + if (nr_blocks) { + ostringstream out; + out << "cannot find " << (nr_blocks + found.size()) + << " blocks of ref-count " << expected; + throw runtime_error(out.str()); + } + } +} + +//---------------------------------------------------------------- + +damage_generator::damage_generator(block_manager::ptr bm) +{ + md_ = metadata::ptr(new metadata(bm, true)); +} + +void damage_generator::commit() +{ + md_->commit(); +} + +void damage_generator::create_metadata_leaks(block_address nr_leaks, + ref_t expected, ref_t actual) +{ + std::set leaks; + find_blocks(md_->metadata_sm_, nr_leaks, expected, leaks); + + for (auto const &b : leaks) + md_->metadata_sm_->set_count(b, actual); +} + +//---------------------------------------------------------------- diff --git a/thin-provisioning/damage_generator.h b/thin-provisioning/damage_generator.h new file mode 100644 index 0000000..5ad700d --- /dev/null +++ b/thin-provisioning/damage_generator.h @@ -0,0 +1,22 @@ +#ifndef METADATA_DAMAGE_GENERATOR_H +#define METADATA_DAMAGE_GENERATOR_H + +#include "metadata.h" + +//---------------------------------------------------------------- + +class damage_generator { +public: + typedef std::shared_ptr ptr; + + damage_generator(block_manager::ptr bm); + void commit(); + void create_metadata_leaks(block_address nr_leaks, ref_t expected, ref_t actual); + +private: + thin_provisioning::metadata::ptr md_; +}; + +//---------------------------------------------------------------- + +#endif diff --git a/thin-provisioning/thin_generate_damage.cc b/thin-provisioning/thin_generate_damage.cc new file mode 100644 index 0000000..1863d96 --- /dev/null +++ b/thin-provisioning/thin_generate_damage.cc @@ -0,0 +1,144 @@ +#include "base/output_file_requirements.h" +#include "persistent-data/file_utils.h" +#include "thin-provisioning/commands.h" +#include "thin-provisioning/damage_generator.h" +#include "version.h" + +#include +#include + +using namespace persistent_data; +using namespace thin_provisioning; + +//---------------------------------------------------------------- + +namespace { + struct flags { + enum damage_operations { + DAMAGE_OP_NONE, + DAMAGE_OP_CREATE_METADATA_LEAKS, + DAMAGE_OP_LAST + }; + + flags() + : op(DAMAGE_OP_NONE), + nr_blocks(0), + expected_rc(0), + actual_rc(0) { + } + + bool check_conformance(); + + damage_operations op; + string output; + block_address nr_blocks; + ref_t expected_rc; + ref_t actual_rc; + }; + + bool flags::check_conformance() { + if (op == DAMAGE_OP_NONE || op >= DAMAGE_OP_LAST) { + cerr << "Invalid operation." << endl; + return false; + } + + if (!output.size()) { + cerr << "No output file provided." << endl; + return false; + } + + if (!nr_blocks) { + cerr << "Invalid number of blocks" << endl; + return false; + } + + if (op == DAMAGE_OP_CREATE_METADATA_LEAKS && + expected_rc == actual_rc) { + cerr << "Invalid reference count parameters" << endl; + return false; + } + + check_output_file_requirements(output); + + return true; + } + + int generate_damage(flags const &fs) { + block_manager::ptr bm = open_bm(fs.output, block_manager::READ_WRITE); + damage_generator::ptr gen = damage_generator::ptr(new damage_generator(bm)); + + switch (fs.op) { + case flags::DAMAGE_OP_CREATE_METADATA_LEAKS: + gen->create_metadata_leaks(fs.nr_blocks, fs.expected_rc, fs.actual_rc); + break; + default: + break; + } + + gen->commit(); + + return 0; + } +} + +//---------------------------------------------------------------- + +thin_generate_damage_cmd::thin_generate_damage_cmd() + : command("thin_generate_damage") +{ +} + +void +thin_generate_damage_cmd::usage(std::ostream &out) const +{ +} + +int +thin_generate_damage_cmd::run(int argc, char **argv) +{ + int c; + struct flags fs; + const char *shortopts = "ho:V"; + const struct option longopts[] = { + { "help", no_argument, NULL, 'h' }, + { "output", required_argument, NULL, 'o' }, + { "create-metadata-leaks", no_argument, NULL, 1 }, + { "nr-blocks", required_argument, NULL, 1001 }, + { "expected", required_argument, NULL, 1002 }, + { "actual", required_argument, NULL, 1003 }, + { "version", no_argument, NULL, 'V' }, + { NULL, no_argument, NULL, 0 } + }; + + while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { + switch(c) { + case 'h': + usage(cout); + break; + case 'o': + fs.output = optarg; + break; + case 1: + fs.op = flags::DAMAGE_OP_CREATE_METADATA_LEAKS; + break; + case 1001: + fs.nr_blocks = parse_uint64(optarg, "nr_blocks"); + break; + case 1002: + fs.expected_rc = parse_uint64(optarg, "expected"); + break; + case 1003: + fs.actual_rc = parse_uint64(optarg, "actual"); + break; + } + } + + if (!fs.check_conformance()) { + usage(cerr); + return 1; + } + + return generate_damage(fs); +} + +//----------------------------------------------------------------