// 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") { } 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 } }; 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); } //----------------------------------------------------------------