diff --git a/Makefile.in b/Makefile.in index b1fd4aa..2c3c09f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -134,6 +134,7 @@ DEVTOOLS_SOURCE=\ thin-provisioning/thin_generate_metadata.cc \ thin-provisioning/thin_generate_mappings.cc \ thin-provisioning/variable_chunk_stream.cc \ + thin-provisioning/thin_patch_superblock.cc \ thin-provisioning/thin_show_metadata.cc \ thin-provisioning/thin_scan.cc \ ui/ui.cc diff --git a/thin-provisioning/commands.cc b/thin-provisioning/commands.cc index 23399af..262b02d 100644 --- a/thin-provisioning/commands.cc +++ b/thin-provisioning/commands.cc @@ -25,6 +25,7 @@ thin_provisioning::register_thin_commands(base::application &app) app.add_cmd(command::ptr(new thin_generate_damage_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_patch_superblock_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 906c340..88e1346 100644 --- a/thin-provisioning/commands.h +++ b/thin-provisioning/commands.h @@ -124,6 +124,13 @@ namespace thin_provisioning { virtual int run(int argc, char **argv); }; + class thin_patch_superblock_cmd : public base::command { + public: + thin_patch_superblock_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_patch_superblock.cc b/thin-provisioning/thin_patch_superblock.cc new file mode 100644 index 0000000..7150805 --- /dev/null +++ b/thin-provisioning/thin_patch_superblock.cc @@ -0,0 +1,193 @@ +#include + +#include "persistent-data/file_utils.h" +#include "persistent-data/space-maps/disk_structures.h" +#include "thin-provisioning/commands.h" +#include "thin-provisioning/metadata.h" +#include "thin-provisioning/superblock.h" +#include "version.h" + +using namespace persistent_data; +using namespace sm_disk_detail; +using namespace thin_provisioning; + +//---------------------------------------------------------------- + +namespace { + struct flags { + flags(); + bool check_conformance(); + + string output; + + boost::optional transaction_id; + block_address data_mapping_root; + block_address device_details_root; + + block_address metadata_bitmap_root; + block_address metadata_ref_count_root; + + block_address data_bitmap_root; + block_address data_ref_count_root; + }; + + flags::flags() + : data_mapping_root(0), device_details_root(0), + metadata_bitmap_root(0), metadata_ref_count_root(0), + data_bitmap_root(0), data_ref_count_root(0) { + } + + bool flags::check_conformance() { + if (!output.size()) + return false; + + return true; + } + + void patch_space_map_root(void *root, + block_address bitmap_root, + block_address ref_count_root) { + sm_disk_detail::sm_root v; + sm_disk_detail::sm_root_disk d; + + memcpy(&d, root, sizeof(d)); + sm_root_traits::unpack(d, v); + + if (bitmap_root) + v.bitmap_root_ = bitmap_root; + if (ref_count_root) + v.ref_count_root_ = ref_count_root; + + sm_root_traits::pack(v, d); + memcpy(root, &d, sizeof(d)); + } + + int patch_superblock(flags const &fs) { + block_manager::ptr bm = open_bm(fs.output, block_manager::READ_WRITE); + superblock_detail::superblock sb = read_superblock(bm, superblock_detail::SUPERBLOCK_LOCATION); + + if (fs.transaction_id) + sb.trans_id_ = *fs.transaction_id; + + if (fs.data_mapping_root) + sb.data_mapping_root_ = fs.data_mapping_root; + + if (fs.device_details_root) + sb.device_details_root_ = fs.device_details_root; + + patch_space_map_root(sb.metadata_space_map_root_, + fs.metadata_bitmap_root, + fs.metadata_ref_count_root); + + patch_space_map_root(sb.data_space_map_root_, + fs.data_bitmap_root, + fs.data_ref_count_root); + + write_superblock(bm, sb); + + return 0; + } +} + +//---------------------------------------------------------------- + +thin_patch_superblock_cmd::thin_patch_superblock_cmd() + : command("thin_patch_superblock") +{ +} + +void +thin_patch_superblock_cmd::usage(std::ostream &out) const +{ + out << "Usage: " << get_name() << " [options]\n" + << "Options:\n" + << " {-h|--help}\n" + << " {-o|--output} \n" + << " {--transaction-id} \n" + << " {--data-mapping-root} \n" + << " {--device-details-root} \n" + << " {--metadata-bitmap-root} \n" + << " {--metadata-ref-count-root} \n" + << " {--data-bitmap-root} \n" + << " {--data-ref-count-root} \n" + << " {-V|--version}" << endl; +} + +int +thin_patch_superblock_cmd::run(int argc, char **argv) +{ + int c; + flags fs; + const char shortopts[] = "ho:V"; + + const struct option longopts[] = { + { "help", no_argument, NULL, 'h'}, + { "output", required_argument, NULL, 'o'}, + { "transaction-id", required_argument, NULL, 1 }, + { "data-mapping-root", required_argument, NULL, 2 }, + { "device-details-root", required_argument, NULL, 3 }, + { "metadata-bitmap-root", required_argument, NULL, 4 }, + { "metadata-ref-count-root", required_argument, NULL, 5 }, + { "data-bitmap-root", required_argument, NULL, 6 }, + { "data-ref-count-root", required_argument, NULL, 7 }, + { "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.transaction_id = parse_uint64(optarg, "transaction_id"); + break; + + case 2: + fs.data_mapping_root = parse_uint64(optarg, "data_mapping_root"); + break; + + case 3: + fs.device_details_root = parse_uint64(optarg, "device_details_root"); + break; + + case 4: + fs.metadata_bitmap_root = parse_uint64(optarg, "metadata_bitmap_root"); + break; + + case 5: + fs.metadata_ref_count_root = parse_uint64(optarg, "metadata_ref_count_root"); + break; + + case 6: + fs.data_bitmap_root = parse_uint64(optarg, "data_bitmap_root"); + break; + + case 7: + fs.data_ref_count_root = parse_uint64(optarg, "data_ref_count_root"); + 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 patch_superblock(fs); +} + +//----------------------------------------------------------------