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