[thin_generate_damage] Introduce tools to generate metadata damage

This commit is contained in:
Ming-Hung Tsai 2020-07-23 17:11:01 +08:00
parent e46fabde1a
commit d1fed5f5ec
6 changed files with 242 additions and 0 deletions

View File

@ -123,11 +123,13 @@ SOURCE=\
thin-provisioning/xml_format.cc thin-provisioning/xml_format.cc
DEVTOOLS_SOURCE=\ DEVTOOLS_SOURCE=\
thin-provisioning/damage_generator.cc \
thin-provisioning/thin_journal.cc \ thin-provisioning/thin_journal.cc \
thin-provisioning/thin_journal_check.cc \ thin-provisioning/thin_journal_check.cc \
thin-provisioning/thin_ll_dump.cc \ thin-provisioning/thin_ll_dump.cc \
thin-provisioning/thin_ll_restore.cc \ thin-provisioning/thin_ll_restore.cc \
thin-provisioning/thin_show_duplicates.cc \ thin-provisioning/thin_show_duplicates.cc \
thin-provisioning/thin_generate_damage.cc \
thin-provisioning/thin_generate_metadata.cc \ thin-provisioning/thin_generate_metadata.cc \
thin-provisioning/thin_generate_mappings.cc \ thin-provisioning/thin_generate_mappings.cc \
thin-provisioning/variable_chunk_stream.cc \ thin-provisioning/variable_chunk_stream.cc \

View File

@ -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_dump_cmd()));
app.add_cmd(command::ptr(new thin_ll_restore_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_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_metadata_cmd()));
app.add_cmd(command::ptr(new thin_generate_mappings_cmd())); app.add_cmd(command::ptr(new thin_generate_mappings_cmd()));
app.add_cmd(command::ptr(new thin_show_duplicates_cmd())); app.add_cmd(command::ptr(new thin_show_duplicates_cmd()));

View File

@ -103,6 +103,13 @@ namespace thin_provisioning {
virtual int run(int argc, char **argv); 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 { class thin_generate_metadata_cmd : public base::command {
public: public:
thin_generate_metadata_cmd(); thin_generate_metadata_cmd();

View File

@ -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<block_address> &found) {
block_address sm_size = sm->get_nr_blocks();
base::run_set<block_address> 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<block_address> leaks;
find_blocks(md_->metadata_sm_, nr_leaks, expected, leaks);
for (auto const &b : leaks)
md_->metadata_sm_->set_count(b, actual);
}
//----------------------------------------------------------------

View File

@ -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<damage_generator> 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

View File

@ -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 <getopt.h>
#include <unistd.h>
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);
}
//----------------------------------------------------------------