diff --git a/thin-provisioning/thin_generate_metadata.cc b/thin-provisioning/thin_generate_metadata.cc index 7a7c990..f7127cc 100644 --- a/thin-provisioning/thin_generate_metadata.cc +++ b/thin-provisioning/thin_generate_metadata.cc @@ -17,6 +17,7 @@ // . #include "base/output_file_requirements.h" +#include "persistent-data/file_utils.h" #include "thin-provisioning/commands.h" #include "thin-provisioning/metadata.h" #include "version.h" @@ -34,16 +35,132 @@ using namespace thin_provisioning; namespace { struct flags { + enum metadata_operations { + METADATA_OP_NONE, + METADATA_OP_FORMAT, + METADATA_OP_OPEN, + METADATA_OP_CREATE_THIN, + METADATA_OP_LAST + }; + flags() - : data_block_size(128), + : op(METADATA_OP_NONE), + data_block_size(128), nr_data_blocks(10240) { } - block_address data_block_size; + bool check_conformance(); + + metadata_operations op; + sector_t data_block_size; block_address nr_data_blocks; + optional dev_id; optional output; }; + + // FIXME: modulize the conditions + bool flags::check_conformance() { + if (op == METADATA_OP_NONE || op >= METADATA_OP_LAST) { + cerr << "Invalid operation." << endl; + return false; + } + + if (!output) { + cerr << "No output file provided." << endl; + return false; + } else + check_output_file_requirements(*output); + + if (op == METADATA_OP_CREATE_THIN && !dev_id) { + cerr << "no device id provided." << endl; + return false; + } + + return true; + } + + //-------------------------------- + + single_mapping_tree::ptr new_mapping_tree(metadata::ptr md) { + return single_mapping_tree::ptr( + new single_mapping_tree(*md->tm_, + mapping_tree_detail::block_time_ref_counter(md->data_sm_))); + } + + bool is_device_exists(metadata::ptr md, uint64_t dev_id) { + uint64_t key[1] = {dev_id}; + + device_tree::maybe_value v1 = md->details_->lookup(key); + if (v1) + return true; + + dev_tree::maybe_value v2 = md->mappings_top_level_->lookup(key); + if (v2) + return true; + + return false; + } + + //-------------------------------- + + metadata::ptr format_metadata(block_manager::ptr bm, + sector_t data_block_size, + block_address nr_data_blocks) { + metadata::ptr md(new metadata(bm, + metadata::CREATE, + data_block_size, + nr_data_blocks)); + md->commit(); + return md; + } + + metadata::ptr open_metadata(block_manager::ptr bm) { + metadata::ptr md(new metadata(bm, true)); + return md; + } + + void create_thin(metadata::ptr md, uint64_t dev_id) { + uint64_t key[1] = {dev_id}; + + if (is_device_exists(md, dev_id)) + throw runtime_error("device already exists"); + + device_tree_detail::device_details details; + details.transaction_id_ = md->sb_.trans_id_; + details.creation_time_ = md->sb_.time_; + details.snapshotted_time_ = details.creation_time_; + md->details_->insert(key, details); + + single_mapping_tree::ptr subtree = new_mapping_tree(md); + md->mappings_top_level_->insert(key, subtree->get_root()); + md->mappings_->set_root(md->mappings_top_level_->get_root()); // FIXME: ugly + + md->commit(); + } + + metadata::ptr open_or_format_metadata(block_manager::ptr bm, flags const &fs) { + + if (fs.op == flags::METADATA_OP_FORMAT) + return format_metadata(bm, fs.data_block_size, fs.nr_data_blocks); + else + return open_metadata(bm); + } + + int generate_metadata(flags const &fs) { + block_manager::ptr bm = open_bm(*fs.output, block_manager::READ_WRITE); + metadata::ptr md = open_or_format_metadata(bm, fs); + + switch (fs.op) { + case flags::METADATA_OP_CREATE_THIN: + create_thin(md, *fs.dev_id); + break; + default: + break; + } + + return 0; + } } //---------------------------------------------------------------- @@ -74,8 +191,12 @@ thin_generate_metadata_cmd::run(int argc, char **argv) const struct option longopts[] = { { "help", no_argument, NULL, 'h' }, { "output", required_argument, NULL, 'o' }, + { "format", no_argument, NULL, 1 }, + { "open", no_argument, NULL, 2 }, + { "create-thin", no_argument, NULL, 3 }, { "data-block-size", required_argument, NULL, 101 }, { "nr-data-blocks", required_argument, NULL, 102 }, + { "dev-id", required_argument, NULL, 301 }, { "version", no_argument, NULL, 'V' }, { NULL, no_argument, NULL, 0 } }; @@ -90,6 +211,18 @@ thin_generate_metadata_cmd::run(int argc, char **argv) fs.output = optarg; break; + case 1: + fs.op = flags::METADATA_OP_FORMAT; + break; + + case 2: + fs.op = flags::METADATA_OP_OPEN; + break; + + case 3: + fs.op = flags::METADATA_OP_CREATE_THIN; + break; + case 101: fs.data_block_size = parse_uint64(optarg, "data block size"); break; @@ -98,6 +231,10 @@ thin_generate_metadata_cmd::run(int argc, char **argv) fs.nr_data_blocks = parse_uint64(optarg, "nr data blocks"); break; + case 301: + fs.dev_id = parse_uint64(optarg, "dev id"); + break; + case 'V': cout << THIN_PROVISIONING_TOOLS_VERSION << endl; return 0; @@ -108,14 +245,12 @@ thin_generate_metadata_cmd::run(int argc, char **argv) } } - if (!fs.output) { - cerr << "No output file provided.\n\n"; + if (!fs.check_conformance()) { usage(cerr); return 1; - } else - check_output_file_requirements(*fs.output); + } - return 0; + return generate_metadata(fs); } //----------------------------------------------------------------