diff --git a/cache/cache_check.cc b/cache/cache_check.cc new file mode 100644 index 0000000..e0aed80 --- /dev/null +++ b/cache/cache_check.cc @@ -0,0 +1,100 @@ +// Copyright (C) 2011 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 +// . + +#include +#include +#include + +#include "array.h" +#include "metadata.h" +#include "metadata_checker.h" +#include "version.h" + +using namespace persistent_data; +using namespace std; +using namespace thin_provisioning; + +namespace { + int check(string const &path, bool quiet) { + try { + metadata::ptr md(new metadata(path, metadata::OPEN)); + + optional maybe_errors = metadata_check(md); + if (maybe_errors) { + if (!quiet) + cerr << error_selector(*maybe_errors, 3); + return 1; + } + } catch (std::exception &e) { + if (!quiet) + cerr << e.what() << endl; + return 1; + } + + return 0; + } + + void usage(ostream &out, string const &cmd) { + out << "Usage: " << cmd << " [options] {device|file}" << endl + << "Options:" << endl + << " {-q|--quiet}" << endl + << " {-h|--help}" << endl + << " {-V|--version}" << endl; + } +} + +int main(int argc, char **argv) +{ + int c; + bool quiet = false; + const char shortopts[] = "qhV"; + const struct option longopts[] = { + { "quiet", no_argument, NULL, 'q'}, + { "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, basename(argv[0])); + return 0; + + case 'q': + quiet = true; + break; + + case 'V': + cout << THIN_PROVISIONING_TOOLS_VERSION << endl; + return 0; + + default: + usage(cerr, basename(argv[0])); + return 1; + } + } + + if (argc == optind) { + cerr << "No input file provided." << endl; + usage(cerr, basename(argv[0])); + exit(1); + } + + return check(argv[optind], quiet); +} diff --git a/cache/cache_dump.cc b/cache/cache_dump.cc new file mode 100644 index 0000000..fc299c4 --- /dev/null +++ b/cache/cache_dump.cc @@ -0,0 +1,119 @@ +// Copyright (C) 2012 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 +// . + +#include +#include +#include + +#include "human_readable_format.h" +#include "cache_metadata_dumper.h" +#include "cache_metadata.h" +#include "xml_format.h" +#include "version.h" + +using namespace persistent_data; +using namespace std; +using namespace thin_provisioning; + +namespace { + int dump(string const &path, string const &format, bool repair, + block_address metadata_snap = 0) { + try { + metadata::ptr md(metadata_snap ? + new metadata(path, metadata_snap) : + new metadata(path, metadata::OPEN)); + emitter::ptr e; + + if (format == "xml") + e = create_xml_emitter(cout); + else if (format == "human_readable") + e = create_human_readable_emitter(cout); + else { + cerr << "unknown format '" << format << "'" << endl; + exit(1); + } + + metadata_dump(md, e, repair); + + } catch (std::exception &e) { + cerr << e.what() << endl; + return 1; + } + + return 0; + } + + void usage(ostream &out, string const &cmd) { + out << "Usage: " << cmd << " [options] {device|file}" << endl + << "Options:" << endl + << " {-h|--help}" << endl + << " {-f|--format} {xml|human_readable}" << endl + << " {-r|--repair}" << endl + << " {-m|--metadata-snap}" << endl + << " {-V|--version}" << endl; + } +} + +int main(int argc, char **argv) +{ + int c; + bool repair = false; + const char shortopts[] = "hm:f:rV"; + string format = "xml"; + char *end_ptr; + + const struct option longopts[] = { + { "help", no_argument, NULL, 'h'}, + { "format", required_argument, NULL, 'f' }, + { "repair", no_argument, NULL, 'r'}, + { "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, basename(argv[0])); + return 0; + + case 'f': + format = optarg; + break; + + case 'r': + repair = true; + break; + + case 'V': + cout << THIN_PROVISIONING_TOOLS_VERSION << endl; + return 0; + + default: + usage(cerr, basename(argv[0])); + return 1; + } + } + + if (argc == optind) { + cerr << "No input file provided." << endl; + usage(cerr, basename(argv[0])); + return 1; + } + + return dump(argv[optind], format, repair, metadata_snap); +} diff --git a/cache/cache_metadata.h b/cache/cache_metadata.h new file mode 100644 index 0000000..c03c04b --- /dev/null +++ b/cache/cache_metadata.h @@ -0,0 +1,143 @@ +// Copyright (C) 2011 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 +// . + +#ifndef CACHE_METADATA_H +#define CACHE_METADATA_H + +#include "block.h" +#include "array.h" +#include "endian_utils.h" +#include "space_map_disk.h" +#include "transaction_manager.h" + +//---------------------------------------------------------------- + +namespace cache { + // FIXME: don't use namespaces in a header + using namespace base; + using namespace persistent_data; + + block_address const SUPERBLOCK_LOCATION = 0; + + typedef uint64_t sector_t; + + //------------------------------------------------ + + class space_map_ref_counter { + public: + space_map_ref_counter(space_map::ptr sm) + : sm_(sm) { + } + + void inc(block_address b) { + sm_->inc(b); + } + + void dec(block_address b) { + sm_->dec(b); + } + + private: + space_map::ptr sm_; + }; + + struct block_flags { + uint64_t block_; + uint32_t flags_; + }; + + class block_flags_ref_counter { + public: + block_flags_ref_counter(space_map::ptr sm) + : sm_(sm) { + } + + void inc(block_flags bf) { + sm_->inc(bf.block_); + } + + void dec(block_flags bf) { + sm_->dec(bf.block_); + } + + private: + space_map::ptr sm_; + }; + + struct block_traits { + typedef base::__le64 disk_type; + typedef block_flags value_type; + typedef block_flags_ref_counter ref_counter; + + static void unpack(disk_type const &disk, value_type &value) { + uint64_t v = to_cpu(disk); + value.block_ = v >> 24; + value.flags_ = v & ((1 << 24) - 1); + } + + static void pack(value_type const &value, disk_type &disk) { + uint64_t v = (value.block_ << 24) | value.flags_; + disk = base::to_disk(v); + } + }; + + //------------------------------------------------ + + // FIXME: should these be in a sub-namespace? + typedef persistent_data::transaction_manager::ptr tm_ptr; + typedef persistent_data::btree<1, device_details_traits> detail_tree; + typedef persistent_data::btree<1, mtree_traits> dev_tree; + typedef persistent_data::btree<2, block_traits> mapping_tree; + typedef persistent_data::btree<1, block_traits> single_mapping_tree; + + // The tools require different interfaces onto the metadata than + // the in kernel driver. This class gives access to the low-level + // implementation of metadata. Implement more specific interfaces + // on top of this. + struct metadata { + enum open_type { + CREATE, + OPEN + }; + + metadata(std::string const &dev_path, open_type ot, + sector_t data_block_size = 128, + block_address nr_cache_blocks = 0); // Only used if CREATE + + metadata(std::string const &dev_path, block_address metadata_snap); + + void commit(); + + typedef block_manager<>::read_ref read_ref; + typedef block_manager<>::write_ref write_ref; + typedef boost::shared_ptr ptr; + + tm_ptr tm_; + superblock sb_; + + checked_space_map::ptr metadata_sm_; + checked_space_map::ptr data_sm_; + detail_tree::ptr details_; + dev_tree::ptr mappings_top_level_; + mapping_tree::ptr mappings_; + }; +} + +//---------------------------------------------------------------- + +#endif diff --git a/cache/cache_metadata_disk_structures.cc b/cache/cache_metadata_disk_structures.cc new file mode 100644 index 0000000..e3d369f --- /dev/null +++ b/cache/cache_metadata_disk_structures.cc @@ -0,0 +1,113 @@ +// Copyright (C) 2012 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 +// . + +#include "cache_metadata_disk_structures.h" + +#include + +using namespace cache_tools; + +//---------------------------------------------------------------- + +void +superblock_traits::unpack(superblock_disk const &disk, superblock &core) +{ + core.csum = to_cpu(disk.csum); + core.flags = to_cpu(disk.flags); + core.blocknr = to_cpu(disk.blocknr); + + ::memcpy(core.uuid, disk.uuid, sizeof(core.uuid)); + core.magic = to_cpu(disk.magic); + core.version = to_cpu(disk.version); + + ::memcpy(core.policy_name, disk.policy_name, sizeof(core.policy_name)); + + for (unsigned i = 0; i < CACHE_POLICY_VERSION_SIZE; i++) + core.policy_version[i] = to_cpu(disk.policy_version[i]); + + core.policy_hint_size = to_cpu(disk.policy_hint_size); + + ::memcpy(core.metadata_space_map_root, + disk.metadata_space_map_root, + sizeof(core.metadata_space_map_root)); + + core.mapping_root = to_cpu(disk.mapping_root); + core.hint_root = to_cpu(disk.hint_root); + + core.discard_root = to_cpu(disk.discard_root); + core.discard_block_size = to_cpu(disk.discard_block_size); + core.discard_nr_blocks = to_cpu(disk.discard_nr_blocks); + + core.data_block_size = to_cpu(disk.data_block_size); + core.metadata_block_size = to_cpu(disk.metadata_block_size); + core.cache_blocks = to_cpu(disk.cache_blocks); + + core.compat_flags = to_cpu(disk.compat_flags); + core.compat_ro_flags = to_cpu(disk.compat_ro_flags); + core.incompat_flags = to_cpu(disk.incompat_flags); + + core.read_hits = to_cpu(disk.read_hits); + core.read_misses = to_cpu(disk.read_misses); + core.write_hits = to_cpu(disk.write_hits); + core.write_misses = to_cpu(disk.write_misses); +} + +void +superblock_traits::pack(superblock const &value, superblock_disk &disk) +{ + disk.csum = to_disk<__le32>(core.csum); + disk.flags = to_disk<__le32>(core.flags); + disk.blocknr = to_disk<__le64>(core.blocknr); + + ::memcpy(disk.uuid, core.uuid, sizeof(disk.uuid)); + disk.magic = to_disk<__le64>(core.magic); + disk.version = to_disk<__le32>(core.version); + + ::memcpy(disk.policy_name, core.policy_name, sizeof(disk.policy_name)); + + for (unsigned i = 0; i < CACHE_POLICY_VERSION_SIZE; i++) + disk.policy_version[i] = to_disk<__le32>(core.policy_version[i]); + + disk.policy_hint_size = to_disk<__le32>(core.policy_hint_size); + + ::memcpy(disk.metadata_space_map_root, + core.metadata_space_map_root, + sizeof(disk.metadata_space_map_root)); + + disk.mapping_root = to_disk<__le64>(core.mapping_root); + disk.hint_root = to_disk<__le64>(core.hint_root); + + disk.discard_root = to_disk<__le64>(core.discard_root); + disk.discard_block_size = to_disk<__le64>(core.discard_block_size); + disk.discard_nr_blocks = to_disk<__le64>(core.discard_nr_blocks); + + disk.data_block_size = to_disk<__le32>(core.data_block_size); + disk.metadata_block_size = to_disk<__le32>(core.metadata_block_size); + disk.cache_blocks = to_disk<__le32>(core.cache_blocks); + + disk.compat_flags = to_disk<__le32>(core.compat_flags); + disk.compat_ro_flags = to_disk<__le32>(core.compat_ro_flags); + disk.incompat_flags = to_disk<__le32>(core.incompat_flags); + + disk.read_hits = to_disk<__le32>(core.read_hits); + disk.read_misses = to_disk<__le32>(core.read_misses); + disk.write_hits = to_disk<__le32>(core.write_hits); + disk.write_misses = to_disk<__le32>(core.write_misses); +} + +//---------------------------------------------------------------- diff --git a/cache/cache_metadata_disk_structures.h b/cache/cache_metadata_disk_structures.h new file mode 100644 index 0000000..7eebb24 --- /dev/null +++ b/cache/cache_metadata_disk_structures.h @@ -0,0 +1,118 @@ +// Copyright (C) 2012 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 +// . + +#ifndef CACHE_METADATA_DISK_STRUCTURES_H +#define CACHE_METADATA_DISK_STRUCTURES_H + +#include "endian_utils.h" +#include "btree.h" + +//---------------------------------------------------------------- + +// FIXME: rename to just METADATA_DISK_STRUCTURES +namespace cache_tools { + using namespace base; // FIXME: don't use namespaces in headers. + + unsigned const SPACE_MAP_ROOT_SIZE = 128; + + typedef unsigned char __u8; + + struct superblock_disk { + __le32 csum; + __le32 flags; + __le64 blocknr; + + __u8 uuid[16]; + __le64 magic; + __le32 version; + + __u8 policy_name[CACHE_POLICY_NAME_SIZE]; + __le32 policy_version[CACHE_POLICY_VERSION_SIZE]; + __le32 policy_hint_size; + + __u8 metadata_space_map_root[SPACE_MAP_ROOT_SIZE]; + + __le64 mapping_root; + __le64 hint_root; + + __le64 discard_root; + __le64 discard_block_size; + __le64 discard_nr_blocks; + + __le32 data_block_size; /* in 512-byte sectors */ + __le32 metadata_block_size; /* in 512-byte sectors */ + __le32 cache_blocks; + + __le32 compat_flags_; + __le32 compat_ro_flags_; + __le32 incompat_flags_; + + __le32 read_hits; + __le32 read_misses; + __le32 write_hits; + __le32 write_misses; + } __attribute__ ((packed)); + + struct superblock { + uint32_t csum; + uint32_t flags; + uint64_t blocknr; + + __u8 uuid[16]; + uint64_t magic; + uint32_t version; + + __u8 policy_name[CACHE_POLICY_NAME_SIZE]; + uint32_t policy_version[CACHE_POLICY_VERSION_SIZE]; + uint32_t policy_hint_size; + + __u8 metadata_space_map_root[SPACE_MAP_ROOT_SIZE]; + + uint64_t mapping_root; + uint64_t hint_root; + + uint64_t discard_root; + uint64_t discard_block_size; + uint64_t discard_nr_blocks; + + uint32_t data_block_size; /* in 512-byte sectors */ + uint32_t metadata_block_size; /* in 512-byte sectors */ + uint32_t cache_blocks; + + uint32_t compat_flags_; + uint32_t compat_ro_flags_; + uint32_t incompat_flags_; + + uint32_t read_hits; + uint32_t read_misses; + uint32_t write_hits; + uint32_t write_misses; + }; + + struct superblock_traits { + typedef superblock_disk disk_type; + typedef superblock value_type; + + static void unpack(superblock_disk const &disk, superblock &value); + static void pack(superblock const &value, superblock_disk &disk); + }; +} + +//---------------------------------------------------------------- + +#endif