diff --git a/.gitignore b/.gitignore index 0db515f..c53e066 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,23 @@ cachegrind.* core bin/pdata_tools +thin_check +thin_dump +thin_restore +thin_repair +thin_rmap +thin_metadata_size +thin_show_blocks + +cache_check +cache_dump +cache_restore +cache_repair +cache_metadata_size + +era_check +era_dump +era_invalidate *.metadata bad-metadata @@ -27,6 +44,8 @@ autom4te.cache/ *.xml *.bin *.patch +*.orig +*.rej version.h config.cache @@ -34,4 +53,4 @@ config.log config.status configure -callgrind.* \ No newline at end of file +callgrind.* diff --git a/Makefile.in b/Makefile.in index 9e62019..0365e1e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -105,7 +105,8 @@ SOURCE=\ DEVTOOLS_SOURCE=\ thin-provisioning/thin_generate_metadata.cc \ - thin-provisioning/variable_chunk_stream.cc + thin-provisioning/variable_chunk_stream.cc \ + thin-provisioning/thin_show_blocks.cc ifeq ("@DEVTOOLS@", "yes") SOURCE+=$(DEVTOOLS_SOURCE) diff --git a/bin/thin_show_metadata b/bin/thin_show_metadata new file mode 120000 index 0000000..84c01e7 --- /dev/null +++ b/bin/thin_show_metadata @@ -0,0 +1 @@ +pdata_tools \ No newline at end of file diff --git a/persistent-data/space-maps/disk.cc b/persistent-data/space-maps/disk.cc index e915eb4..ce38718 100644 --- a/persistent-data/space-maps/disk.cc +++ b/persistent-data/space-maps/disk.cc @@ -62,8 +62,6 @@ namespace { //-------------------------------- - uint64_t const INDEX_CSUM_XOR = 160478; - // FIXME: factor out the common code in these validators struct index_block_validator : public bcache::validator { virtual void check(void const *raw, block_address location) const { diff --git a/persistent-data/space-maps/disk_structures.h b/persistent-data/space-maps/disk_structures.h index 0a57e61..aa8fbe5 100644 --- a/persistent-data/space-maps/disk_structures.h +++ b/persistent-data/space-maps/disk_structures.h @@ -111,6 +111,9 @@ namespace persistent_data { le32 not_used; le64 blocknr; } __attribute__ ((packed)); + + uint64_t const BITMAP_CSUM_XOR = 240779; + uint64_t const INDEX_CSUM_XOR = 160478; } } diff --git a/thin-provisioning/commands.cc b/thin-provisioning/commands.cc index 66aca99..8acd3f8 100644 --- a/thin-provisioning/commands.cc +++ b/thin-provisioning/commands.cc @@ -16,11 +16,12 @@ thin_provisioning::register_thin_commands(base::application &app) app.add_cmd(command::ptr(new thin_restore_cmd())); app.add_cmd(command::ptr(new thin_repair_cmd())); app.add_cmd(command::ptr(new thin_rmap_cmd())); - app.add_cmd(command::ptr(new thin_trim_cmd())); #ifdef DEV_TOOLS + app.add_cmd(command::ptr(new thin_trim_cmd())); app.add_cmd(command::ptr(new thin_generate_metadata_cmd())); app.add_cmd(command::ptr(new thin_show_duplicates_cmd())); + app.add_cmd(command::ptr(new thin_show_metadata_cmd())); #endif } diff --git a/thin-provisioning/commands.h b/thin-provisioning/commands.h index 74fbe99..075e605 100644 --- a/thin-provisioning/commands.h +++ b/thin-provisioning/commands.h @@ -63,6 +63,7 @@ namespace thin_provisioning { virtual int run(int argc, char **argv); }; +#ifdef DEV_TOOLS class thin_trim_cmd : public base::command { public: thin_trim_cmd(); @@ -84,6 +85,14 @@ namespace thin_provisioning { virtual int run(int argc, char **argv); }; + class thin_show_metadata_cmd : public base::command { + public: + thin_show_metadata_cmd(); + virtual void usage(std::ostream &out) const; + virtual int run(int argc, char **argv); + }; +#endif + void register_thin_commands(base::application &app); } diff --git a/thin-provisioning/thin_show_blocks.cc b/thin-provisioning/thin_show_blocks.cc new file mode 100644 index 0000000..2a7140a --- /dev/null +++ b/thin-provisioning/thin_show_blocks.cc @@ -0,0 +1,148 @@ +#include "persistent-data/checksum.h" +#include "persistent-data/data-structures/btree.h" +#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" + +#include +#include +#include +#include +#include + +using namespace persistent_data; +using namespace sm_disk_detail; +using namespace std; +using namespace thin_provisioning; + +//---------------------------------------------------------------- + +namespace { + bool is_superblock(block_manager<>::read_ref &rr) { + using namespace superblock_detail; + + superblock_disk const *sbd = reinterpret_cast(rr.data()); + if (to_cpu(sbd->magic_) == SUPERBLOCK_MAGIC) { + superblock sb; + superblock_traits::unpack(*sbd, sb); + cout << "metadata nr blocks: " << sb.metadata_nr_blocks_ << endl; + + return true; + } + + return false; + } + + bool is_bitmap_block(block_manager<>::read_ref &rr) { + bitmap_header const *data = reinterpret_cast(rr.data()); + crc32c sum(BITMAP_CSUM_XOR); + sum.append(&data->not_used, MD_BLOCK_SIZE - sizeof(uint32_t)); + return sum.get_sum() == to_cpu(data->csum); + } + + bool is_index_block(block_manager<>::read_ref &rr) { + metadata_index const *mi = reinterpret_cast(rr.data()); + crc32c sum(INDEX_CSUM_XOR); + sum.append(&mi->padding_, MD_BLOCK_SIZE - sizeof(uint32_t)); + return sum.get_sum() == to_cpu(mi->csum_); + } + + bool is_btree_node(block_manager<>::read_ref &rr) { + using namespace btree_detail; + + disk_node const *data = reinterpret_cast(rr.data()); + node_header const *n = &data->header; + crc32c sum(BTREE_CSUM_XOR); + sum.append(&n->flags, MD_BLOCK_SIZE - sizeof(uint32_t)); + return sum.get_sum() == to_cpu(n->csum); + } + + void show_blocks(string const &dev) { + block_manager<>::ptr bm = open_bm(dev, block_manager<>::READ_ONLY); + + metadata md(bm, metadata::OPEN); + cout << "Metadata space map: nr_blocks = " << md.metadata_sm_->get_nr_blocks() + << ", nr_free_blocks = " << md.metadata_sm_->get_nr_free() + << endl; + cout << "Data space map: nr_blocks = " << md.data_sm_->get_nr_blocks() + << ", nr_free_blocks = " << md.data_sm_->get_nr_free() + << endl; + + block_address nr_blocks = bm->get_nr_blocks(); + for (block_address b = 0; b < nr_blocks; b++) { + block_manager<>::read_ref rr = bm->read_lock(b); + + if (is_superblock(rr)) + cout << b << ": superblock" << endl; + + else if (is_bitmap_block(rr)) + cout << b << ": bitmap block" << endl; + + else if (is_btree_node(rr)) + cout << b << ": btree_node" << endl; + + else + cout << b << ": unknown" << endl; + } + } +} + +//---------------------------------------------------------------- + +thin_show_metadata_cmd::thin_show_metadata_cmd() + : command("thin_show_metadata") +{ +} + +void +thin_show_metadata_cmd::usage(ostream &out) const +{ + out << "Usage: " << get_name() << " {device|file}" << endl + << "Options:" << endl + << " {-h|--help}" << endl + << " {-V|--version}" << endl; +} + +int +thin_show_metadata_cmd::run(int argc, char **argv) +{ + int c; + const char shortopts[] = "hV"; + const struct option longopts[] = { + { "help", no_argument, NULL, 'h'}, + { "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 'V': + cerr << THIN_PROVISIONING_TOOLS_VERSION << endl; + return 0; + } + } + + if (argc == optind) { + usage(cerr); + exit(1); + } + + try { + show_blocks(argv[optind]); + + } catch (std::exception const &e) { + cerr << e.what() << endl; + return 1; + } + + return 0; +} + +//----------------------------------------------------------------