diff --git a/Cargo.lock b/Cargo.lock index 4349d0f..761163b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,6 +65,18 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "bitvec" +version = "0.19.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7ba35e9565969edb811639dbebfe34edc0368e472c5018474c8eb2543397f81" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "byteorder" version = "1.3.4" @@ -188,6 +200,12 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "funty" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ba62103ce691c2fd80fbae2213dfdda9ce60804973ac6b6e97de818ea7f52c8" + [[package]] name = "futures" version = "0.3.5" @@ -396,8 +414,11 @@ dependencies = [ [[package]] name = "nom" -version = "6.0.0-alpha1" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4489ccc7d668957ddf64af7cd027c081728903afa6479d35da7e99bf5728f75f" dependencies = [ + "bitvec", "lexical-core", "memchr", "version_check", @@ -555,6 +576,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" + [[package]] name = "rand" version = "0.7.3" @@ -683,6 +710,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "tap" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36474e732d1affd3a6ed582781b3683df3d0563714c59c39591e8ff707cf078e" + [[package]] name = "tempfile" version = "3.1.0" @@ -895,3 +928,9 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "wyz" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" diff --git a/Cargo.toml b/Cargo.toml index 74836d5..a98b956 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ io-uring = "0.3" indicatif = "0.15" libc = "0.2.71" nix = "0.17" -nom = { path = "/home/ejt/builds/nom/" } +nom = "6.0.0" num_cpus = "1.13" num-derive = "0.3" num-traits = "0.2" 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_delta.cc b/thin-provisioning/thin_delta.cc index 5b31608..0eb119e 100644 --- a/thin-provisioning/thin_delta.cc +++ b/thin-provisioning/thin_delta.cc @@ -22,47 +22,7 @@ using namespace thin_provisioning; //---------------------------------------------------------------- -namespace local { - class application { - public: - application(string const &cmd) - : cmd_(cmd) { - } - - void usage(ostream &out) { - out << "Usage: " << cmd_ << " [options] \n" - << "Options:\n" - << " {--thin1, --snap1}\n" - << " {--thin2, --snap2}\n" - << " {-m, --metadata-snap} [block#]\n" - << " {--verbose}\n" - << " {-h|--help}\n" - << " {-V|--version}" << endl; - } - - void die(string const &msg) { - cerr << msg << endl; - usage(cerr); - exit(1); - } - - uint64_t parse_int(string const &str, string const &desc) { - try { - return boost::lexical_cast(str); - - } catch (...) { - ostringstream out; - out << "Couldn't parse " << desc << ": '" << str << "'"; - die(out.str()); - } - - return 0; // never get here - } - - private: - string cmd_; - }; - +namespace { struct flags { flags() : verbose(false), @@ -76,6 +36,8 @@ namespace local { boost::optional metadata_snap; boost::optional snap1; boost::optional snap2; + boost::optional root1; + boost::optional root2; }; //-------------------------------- @@ -96,13 +58,6 @@ namespace local { uint64_t vbegin_, dbegin_, len_; }; - ostream &operator <<(ostream &out, mapping const &m) { - out << "mapping[vbegin = " << m.vbegin_ - << ", dbegin = " << m.dbegin_ - << ", len = " << m.len_ << "]"; - return out; - } - //-------------------------------- template @@ -528,9 +483,26 @@ namespace local { out << "\n"; } - void begin_diff(indented_stream &out, uint64_t snap1, uint64_t snap2) { + // FIXME: always show the blocknr? + void begin_diff(indented_stream &out, + boost::optional snap1, + boost::optional root1, + boost::optional snap2, + boost::optional root2) { out.indent(); - out << "\n"; + out << "\n"; out.inc(); } @@ -540,7 +512,7 @@ namespace local { out << "\n"; } - void delta_(application &app, flags const &fs) { + void delta_(flags const &fs) { mapping_recorder mr1; mapping_recorder mr2; damage_visitor damage_v; @@ -552,25 +524,33 @@ namespace local { metadata::ptr md(fs.use_metadata_snap ? new metadata(bm, fs.metadata_snap) : new metadata(bm)); sb = md->sb_; - dev_tree::key k = {*fs.snap1}; - boost::optional snap1_root = md->mappings_top_level_->lookup(k); + boost::optional snap1_root; + if (fs.snap1) { + dev_tree::key k = {*fs.snap1}; + snap1_root = md->mappings_top_level_->lookup(k); + } else if (fs.root1) + snap1_root = *fs.root1; if (!snap1_root) { ostringstream out; out << "Unable to find mapping tree for snap1 (" << *fs.snap1 << ")"; - app.die(out.str()); + throw std::runtime_error(out.str()); } single_mapping_tree snap1(*md->tm_, *snap1_root, mapping_tree_detail::block_traits::ref_counter(md->tm_->get_sm())); - k[0] = *fs.snap2; - boost::optional snap2_root = md->mappings_top_level_->lookup(k); + boost::optional snap2_root; + if (fs.snap2) { + dev_tree::key k = {*fs.snap2}; + snap2_root = md->mappings_top_level_->lookup(k); + } else if (fs.root2) + snap2_root = *fs.root2; if (!snap2_root) { ostringstream out; out << "Unable to find mapping tree for snap2 (" << *fs.snap2 << ")"; - app.die(out.str()); + throw std::runtime_error(out.str()); } single_mapping_tree snap2(*md->tm_, *snap2_root, @@ -593,7 +573,7 @@ namespace local { sb.metadata_snap_ ? boost::optional(sb.metadata_snap_) : boost::optional()); - begin_diff(is, *fs.snap1, *fs.snap2); + begin_diff(is, fs.snap1, fs.root1, fs.snap2, fs.root2); if (fs.verbose) { verbose_emitter e(is); @@ -607,12 +587,12 @@ namespace local { end_superblock(is); } - int delta(application &app, flags const &fs) { + int delta(flags const &fs) { try { - delta_(app, fs); + delta_(fs); } catch (exception const &e) { - app.die(e.what()); - return 1; // never get here + cerr << e.what() << endl; + return 1; } return 0; @@ -631,77 +611,95 @@ thin_delta_cmd::thin_delta_cmd() void thin_delta_cmd::usage(std::ostream &out) const { - // FIXME: finish + out << "Usage: " << get_name() << " [options] \n" + << "Options:\n" + << " {--thin1, --snap1, --root1}\n" + << " {--thin2, --snap2, --root2}\n" + << " {-m, --metadata-snap} [block#]\n" + << " {--verbose}\n" + << " {-h|--help}\n" + << " {-V|--version}" << endl; } int thin_delta_cmd::run(int argc, char **argv) { - using namespace local; - int c; flags fs; - local::application app(basename(argv[0])); char const shortopts[] = "hVm::"; option const longopts[] = { { "help", no_argument, NULL, 'h' }, + { "metadata-snap", optional_argument, NULL, 'm' }, { "version", no_argument, NULL, 'V' }, { "thin1", required_argument, NULL, 1 }, { "snap1", required_argument, NULL, 1 }, { "thin2", required_argument, NULL, 2 }, { "snap2", required_argument, NULL, 2 }, - { "metadata-snap", optional_argument, NULL, 'm' }, { "verbose", no_argument, NULL, 4 }, + { "root1", required_argument, NULL, 5 }, + { "root2", required_argument, NULL, 6 }, { NULL, no_argument, NULL, 0 } }; while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { switch (c) { case 'h': - app.usage(cout); + usage(cout); return 0; + case 'm': + fs.use_metadata_snap = true; + if (optarg) + fs.metadata_snap = parse_uint64(optarg, "metadata snapshot block"); + break; + case 'V': cout << THIN_PROVISIONING_TOOLS_VERSION << endl; return 0; case 1: - fs.snap1 = app.parse_int(optarg, "thin id 1"); + fs.snap1 = parse_uint64(optarg, "thin id 1"); break; case 2: - fs.snap2 = app.parse_int(optarg, "thin id 2"); - break; - - case 'm': - fs.use_metadata_snap = true; - if (optarg) - fs.metadata_snap = app.parse_int(optarg, "metadata snapshot block"); + fs.snap2 = parse_uint64(optarg, "thin id 2"); break; case 4: fs.verbose = true; break; + case 5: + fs.root1 = parse_uint64(optarg, "thin root 1"); + break; + + case 6: + fs.root2 = parse_uint64(optarg, "thin root 2"); + break; + default: - app.usage(cerr); + usage(cerr); return 1; } } if (argc == optind) - app.die("No input device provided."); + die("No input device provided."); else fs.dev = argv[optind]; - if (!fs.snap1) - app.die("--snap1 not specified."); + if (!fs.snap1 && !fs.root1) + die("--snap1 or --root1 not specified."); + if (!!fs.snap1 && !!fs.root1) + die("--snap1 and --root1 are not compatible."); - if (!fs.snap2) - app.die("--snap2 not specified."); + if (!fs.snap2 && !fs.root2) + die("--snap2 or --root2 not specified."); + if (!!fs.snap2 && !!fs.root2) + die("--snap2 and --root2 are not compatible."); - return delta(app, fs); + return delta(fs); } //---------------------------------------------------------------- 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); +} + +//----------------------------------------------------------------