diff --git a/bin/thin_generate_metadata b/bin/thin_generate_metadata new file mode 120000 index 0000000..84c01e7 --- /dev/null +++ b/bin/thin_generate_metadata @@ -0,0 +1 @@ +pdata_tools \ No newline at end of file diff --git a/thin-provisioning/thin_generate_metadata.cc b/thin-provisioning/thin_generate_metadata.cc index 4d5903d..6eb3c62 100644 --- a/thin-provisioning/thin_generate_metadata.cc +++ b/thin-provisioning/thin_generate_metadata.cc @@ -1,9 +1,129 @@ -#include "thin-provisioning/commands.h" +// Copyright (C) 2016 Red Hat, Inc. All rights reserved. +// +// 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/output_file_requirements.h" +#include "persistent-data/file_utils.h" +#include "thin-provisioning/commands.h" +#include "thin-provisioning/emitter.h" +#include "thin-provisioning/human_readable_format.h" +#include "thin-provisioning/metadata.h" +#include "thin-provisioning/restore_emitter.h" +#include "thin-provisioning/xml_format.h" +#include "version.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace boost; +using namespace persistent_data; +using namespace std; using namespace thin_provisioning; //---------------------------------------------------------------- +namespace { + struct flags { + flags() + : data_block_size(128), + nr_data_blocks(10240), + nr_thins(1), + blocks_per_thin(1024), + run_lengths(1024) { + } + + block_address data_block_size; + block_address nr_data_blocks; + unsigned nr_thins; + block_address blocks_per_thin; + block_address run_lengths; + optional output; + }; + + // This is how we stir in some entropy. It mixes up the data + // device. + class shuffler { + public: + shuffler(block_address nr_blocks, unsigned run_lengths) + : nr_blocks_(nr_blocks / run_lengths), + run_lengths_(run_lengths) { + } + + block_address map(block_address b) const { + return reverse(b / run_lengths_) + (b % run_lengths_); + } + + private: + block_address reverse(block_address b) const { + return nr_blocks_ - b - 1ull; + } + + block_address nr_blocks_; + block_address run_lengths_; + }; + + void generate_device(emitter::ptr e, shuffler const &s, uint32_t dev_id, + block_address nr_blocks, block_address base) { + + e->begin_device(dev_id, nr_blocks, 0, 0, 0); + for (unsigned b = 0; b < nr_blocks; b++) + e->single_map(b, s.map(base + b), 0); + e->end_device(); + } + + void generate_metadata(flags const &fs, emitter::ptr e) { + e->begin_superblock("fake metadata", 0, 0, optional(), optional(), + fs.data_block_size, fs.nr_data_blocks, optional()); + + shuffler s(fs.nr_data_blocks, fs.run_lengths); + for (unsigned i = 0; i < fs.nr_thins; i++) + generate_device(e, s, i, fs.blocks_per_thin, i * fs.blocks_per_thin); + + e->end_superblock(); + } + + int create_metadata(flags const &fs) { + try { + // The block size gets updated by the restorer. + block_manager<>::ptr bm(open_bm(*fs.output, block_manager<>::READ_WRITE)); + metadata::ptr md(new metadata(bm, metadata::CREATE, 128, 0)); + emitter::ptr restorer = create_restore_emitter(md); + + generate_metadata(fs, restorer); + + } catch (std::exception &e) { + cerr << e.what() << endl; + return 1; + } + + return 0; + } +} + +//---------------------------------------------------------------- + thin_generate_metadata_cmd::thin_generate_metadata_cmd() : command("thin_generate_metadata") { @@ -12,14 +132,84 @@ thin_generate_metadata_cmd::thin_generate_metadata_cmd() void thin_generate_metadata_cmd::usage(std::ostream &out) const { - + out << "Usage: " << get_name() << " [options]\n" + << "Options:\n" + << " {-h|--help}\n" + << " --data-block-size \n" + << " --nr-data-blocks \n" + << " --nr-thins \n" + << " --blocks-per-thin \n" + << " --run-lengths \n" + << " {-o|--output} \n" + << " {-V|--version}" << endl; } int thin_generate_metadata_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'}, + { "data-block-size", required_argument, NULL, 1}, + { "nr-data-blocks", required_argument, NULL, 2}, + { "nr-thins", required_argument, NULL, 3}, + { "blocks-per-thin", required_argument, NULL, 4}, + { "run-lengths", required_argument, NULL, 5}, + { "version", no_argument, NULL, 'V'}, + { NULL, no_argument, NULL, 0 } + }; - return 1; + 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.data_block_size = parse_uint64(optarg, "data block size"); + break; + + case 2: + fs.nr_data_blocks = parse_uint64(optarg, "nr data blocks"); + break; + + case 3: + fs.nr_thins = parse_uint64(optarg, "nr thins"); + break; + + case 4: + fs.blocks_per_thin = parse_uint64(optarg, "blocks per thin"); + break; + + case 5: + fs.run_lengths = parse_uint64(optarg, "run lengths"); + break; + + case 'V': + cout << THIN_PROVISIONING_TOOLS_VERSION << endl; + return 0; + + default: + usage(cerr); + return 1; + } + } + + if (!fs.output) { + cerr << "No output file provided.\n\n"; + usage(cerr); + return 1; + } else + check_output_file_requirements(*fs.output); + + return create_metadata(fs); } //----------------------------------------------------------------