216 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			216 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// 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
 | 
						|
// <http://www.gnu.org/licenses/>.
 | 
						|
 | 
						|
#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 <boost/optional.hpp>
 | 
						|
#include <fstream>
 | 
						|
#include <getopt.h>
 | 
						|
#include <iostream>
 | 
						|
#include <libgen.h>
 | 
						|
#include <linux/fs.h>
 | 
						|
#include <sys/ioctl.h>
 | 
						|
#include <sys/stat.h>
 | 
						|
#include <sys/types.h>
 | 
						|
#include <unistd.h>
 | 
						|
 | 
						|
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<string> 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<uint32_t>(), optional<uint32_t>(),
 | 
						|
				    fs.data_block_size, fs.nr_data_blocks, optional<uint64_t>());
 | 
						|
 | 
						|
		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 <block size>\n"
 | 
						|
	    << "  --nr-data-blocks <nr>\n"
 | 
						|
	    << "  --nr-thins <count>\n"
 | 
						|
	    << "  --blocks-per-thin <count>\n"
 | 
						|
	    << "  --run-lengths <count>\n"
 | 
						|
	    << "  {-o|--output} <output device or file>\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);
 | 
						|
}
 | 
						|
 | 
						|
//----------------------------------------------------------------
 |