From 8fa59553c483ab4371feff53ff77468ef3e23efb Mon Sep 17 00:00:00 2001 From: Ming-Hung Tsai Date: Wed, 10 Jun 2020 10:23:41 +0800 Subject: [PATCH] [thin_generate_mappings] Introduce the mapping generation tool --- Makefile.in | 1 + thin-provisioning/commands.cc | 1 + thin-provisioning/commands.h | 7 + thin-provisioning/thin_generate_mappings.cc | 207 ++++++++++++++++++++ 4 files changed, 216 insertions(+) create mode 100644 thin-provisioning/thin_generate_mappings.cc diff --git a/Makefile.in b/Makefile.in index 31ba2f7..97b86c4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -129,6 +129,7 @@ DEVTOOLS_SOURCE=\ thin-provisioning/thin_ll_restore.cc \ thin-provisioning/thin_show_duplicates.cc \ thin-provisioning/thin_generate_metadata.cc \ + thin-provisioning/thin_generate_mappings.cc \ thin-provisioning/variable_chunk_stream.cc \ thin-provisioning/thin_show_metadata.cc \ thin-provisioning/thin_scan.cc \ diff --git a/thin-provisioning/commands.cc b/thin-provisioning/commands.cc index 13dc76c..23f4b0e 100644 --- a/thin-provisioning/commands.cc +++ b/thin-provisioning/commands.cc @@ -23,6 +23,7 @@ thin_provisioning::register_thin_commands(base::application &app) 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_metadata_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_metadata_cmd())); app.add_cmd(command::ptr(new thin_journal_cmd())); diff --git a/thin-provisioning/commands.h b/thin-provisioning/commands.h index 6b80bdb..e3a41e7 100644 --- a/thin-provisioning/commands.h +++ b/thin-provisioning/commands.h @@ -110,6 +110,13 @@ namespace thin_provisioning { virtual int run(int argc, char **argv); }; + class thin_generate_mappings_cmd : public base::command { + public: + thin_generate_mappings_cmd(); + virtual void usage(std::ostream &out) const; + virtual int run(int argc, char **argv); + }; + class thin_show_metadata_cmd : public base::command { public: thin_show_metadata_cmd(); diff --git a/thin-provisioning/thin_generate_mappings.cc b/thin-provisioning/thin_generate_mappings.cc new file mode 100644 index 0000000..a366eba --- /dev/null +++ b/thin-provisioning/thin_generate_mappings.cc @@ -0,0 +1,207 @@ +// This file is part of the thin-provisioning-tools source. +// +// thin-provisioning-tools is free software: you can redistribute it +// and/or modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// thin-provisioning-tools is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with thin-provisioning-tools. If not, see +// . + +#include "base/io_generator.h" +#include "base/output_file_requirements.h" +#include "persistent-data/file_utils.h" +#include "thin-provisioning/commands.h" +#include "thin-provisioning/thin_pool.h" +#include "version.h" + +#include +#include +#include + +using namespace boost; +using namespace thin_provisioning; + +//---------------------------------------------------------------- + +namespace { + struct flags { + flags() + : pattern("write"), + offset(0) + { + } + + bool check_conformance(); + + boost::optional output; + base::io_pattern pattern; + boost::optional dev_id; + boost::optional block_size; + base::sector_t offset; + boost::optional size; + boost::optional io_size; + }; + + bool flags::check_conformance() { + if (!output) { + cerr << "No output file provided." << endl; + return false; + } + + if (!dev_id) { + cerr << "No device id provided." << endl; + return false; + } + + if (!size) { + cerr << "No device size specified" << endl; + return false; + } + + check_output_file_requirements(*output); + + return true; + } + + //-------------------------------- + + thin_pool::ptr open_pool(flags const &fs) { + block_manager::ptr bm = open_bm(*fs.output, block_manager::READ_WRITE); + return thin_pool::ptr(new thin_pool(bm)); + } + + int generate_mappings(flags const &fs) { + thin_pool::ptr pool = open_pool(fs); + + thin::ptr td = pool->open_thin(*fs.dev_id); + + io_generator_options opts; + opts.pattern_ = fs.pattern; + opts.block_size_ = !fs.block_size ? + pool->get_data_block_size() : + *fs.block_size; + opts.offset_ = fs.offset; + opts.size_ = *fs.size; + opts.io_size_ = !fs.io_size ? *fs.size : *fs.io_size; + io_generator::ptr gen = create_io_generator(opts); + + base::io io; + while (gen->has_next()) { + // TODO: support io.size_ + gen->next(io); + + switch (io.op_) { + case base::REQ_OP_READ: + process_read(td, pool, io.sector_); + break; + case base::REQ_OP_WRITE: + process_write(td, pool, io.sector_); + break; + case base::REQ_OP_DISCARD: + process_discard(td, pool, io.sector_); + break; + } + } + + pool->commit(); + + return 0; + } +} + +//---------------------------------------------------------------- + +thin_generate_mappings_cmd::thin_generate_mappings_cmd() + : command("thin_generate_mappings") +{ +} + +void +thin_generate_mappings_cmd::usage(std::ostream &out) const +{ + out << "Usage: " << get_name() << " [options]\n" + << "Options:\n" + << " {-h|--help}\n" + << " {-o|--output} \n" + << " {--dev-id} \n" + << " {--offset} \n" + << " {--io-size} \n" + << " {--rw write|trim|randwrite|randtrim|randtw}\n" + << " {--size} \n" + << " {-V|--version}" << endl; +} + +int +thin_generate_mappings_cmd::run(int argc, char **argv) +{ + int c; + struct flags fs; + const char *shortopts = "hi:o:qV"; + const struct option longopts[] = { + { "help", no_argument, NULL, 'h' }, + { "output", required_argument, NULL, 'o' }, + { "dev-id", required_argument, NULL, 1 }, + { "rw", required_argument, NULL, 2 }, + { "offset", required_argument, NULL, 3 }, + { "size", required_argument, NULL, 4 }, + { "io-size", required_argument, NULL, 5 }, + { "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); + return 0; + + case 'o': + fs.output = optarg; + break; + + case 1: + fs.dev_id = parse_uint64(optarg, "dev_id"); + break; + + case 2: + fs.pattern.parse(optarg); + break; + + case 3: + fs.offset = parse_uint64(optarg, "offset"); + break; + + case 4: + fs.size = parse_uint64(optarg, "size"); + break; + + case 5: + fs.io_size = parse_uint64(optarg, "io_size"); + break; + + case 'V': + cout << THIN_PROVISIONING_TOOLS_VERSION << endl; + return 0; + + default: + usage(cerr); + return 1; + } + } + + if (!fs.check_conformance()) { + usage(cerr); + return 1; + } + + return generate_mappings(fs); +} + +//----------------------------------------------------------------