diff --git a/persistent-data/data-structures/array.h b/persistent-data/data-structures/array.h index 6c76bf2..faa800e 100644 --- a/persistent-data/data-structures/array.h +++ b/persistent-data/data-structures/array.h @@ -288,23 +288,8 @@ namespace persistent_data { } } - //-------------------------------- - - struct ablock_counter { - ablock_counter(block_counter &bc) - : bc_(bc) { - } - - void visit(btree_detail::node_location const &loc, block_address b) { - bc_.inc(b); - } - - private: - block_counter &bc_; - }; - void count_metadata_blocks(block_counter &bc) const { - ablock_counter vc(bc); + block_address_counter vc(bc); count_btree_blocks(block_tree_, bc, vc); } diff --git a/persistent-data/data-structures/btree_counter.h b/persistent-data/data-structures/btree_counter.h index 2f00173..ed7b845 100644 --- a/persistent-data/data-structures/btree_counter.h +++ b/persistent-data/data-structures/btree_counter.h @@ -1,6 +1,7 @@ #ifndef PERSISTENT_DATA_DATA_STRUCTURES_BTREE_COUNTER_H #define PERSISTENT_DATA_DATA_STRUCTURES_BTREE_COUNTER_H +#include "persistent-data/data-structures/btree.h" #include "persistent-data/block_counter.h" //---------------------------------------------------------------- @@ -65,6 +66,19 @@ namespace persistent_data { } }; + struct block_address_counter { + block_address_counter(block_counter &bc) + : bc_(bc) { + } + + void visit(btree_detail::node_location const &loc, block_address b) { + bc_.inc(b); + } + + private: + block_counter &bc_; + }; + // Counts how many times each metadata block is referenced in the // tree. Blocks already referenced in the block counter are not // walked. This walk should only be done once you're sure the tree diff --git a/persistent-data/space-maps/careful_alloc.cc b/persistent-data/space-maps/careful_alloc.cc index a25653c..5bca0ca 100644 --- a/persistent-data/space-maps/careful_alloc.cc +++ b/persistent-data/space-maps/careful_alloc.cc @@ -89,6 +89,10 @@ namespace { sm_->iterate(it); } + virtual void count_metadata(block_counter &bc) const { + sm_->count_metadata(bc); + } + virtual size_t root_size() const { return sm_->root_size(); } diff --git a/persistent-data/space-maps/core.h b/persistent-data/space-maps/core.h index d3d0e45..4547f12 100644 --- a/persistent-data/space-maps/core.h +++ b/persistent-data/space-maps/core.h @@ -105,6 +105,9 @@ namespace persistent_data { throw std::runtime_error("'extend' not implemented"); } + void count_metadata(block_counter &bc) const { + } + // FIXME: meaningless, but this class is only used for testing size_t root_size() const { return 0; diff --git a/persistent-data/space-maps/disk.cc b/persistent-data/space-maps/disk.cc index df3ed43..388450f 100644 --- a/persistent-data/space-maps/disk.cc +++ b/persistent-data/space-maps/disk.cc @@ -22,6 +22,7 @@ #include "persistent-data/space-maps/careful_alloc.h" #include "persistent-data/data-structures/btree_damage_visitor.h" +#include "persistent-data/data-structures/btree_counter.h" #include "persistent-data/checksum.h" #include "persistent-data/endian_utils.h" #include "persistent-data/math_utils.h" @@ -222,6 +223,7 @@ namespace { public: typedef boost::shared_ptr ptr; + virtual void count_metadata(block_counter &bc) const = 0; virtual void resize(block_address nr_indexes) = 0; virtual index_entry find_ie(block_address b) const = 0; virtual void save_ie(block_address b, struct index_entry ie) = 0; @@ -405,6 +407,13 @@ namespace { } } + virtual void count_metadata(block_counter &bc) const { + indexes_->count_metadata(bc); + + noop_value_counter vc; + count_btree_blocks(ref_counts_, bc, vc); + } + virtual size_t root_size() const { return sizeof(sm_root_disk); } @@ -554,6 +563,29 @@ namespace { bitmaps_(tm, root, index_entry_traits::ref_counter()) { } + //-------------------------------- + + struct index_entry_counter { + index_entry_counter(block_counter &bc) + : bc_(bc) { + } + + void visit(btree_detail::node_location const &loc, index_entry const &ie) { + if (ie.blocknr_ != 0) + bc_.inc(ie.blocknr_); + } + + private: + block_counter &bc_; + }; + + virtual void count_metadata(block_counter &bc) const { + index_entry_counter vc(bc); + count_btree_blocks(bitmaps_, bc, vc); + } + + //-------------------------------- + virtual void resize(block_address nr_entries) { // No op } @@ -612,6 +644,15 @@ namespace { load_ies(); } + virtual void count_metadata(block_counter &bc) const { + for (unsigned i = 0; i < entries_.size(); i++) { + block_address b = entries_[i].blocknr_; + + if (b != 0) + bc.inc(b); + } + } + virtual void resize(block_address nr_indexes) { entries_.resize(nr_indexes); } diff --git a/persistent-data/space-maps/recursive.cc b/persistent-data/space-maps/recursive.cc index 6533c20..76976a8 100644 --- a/persistent-data/space-maps/recursive.cc +++ b/persistent-data/space-maps/recursive.cc @@ -176,6 +176,10 @@ namespace { sm_->iterate(it); } + virtual void count_metadata(block_counter &bc) const { + sm_->count_metadata(bc); + } + virtual size_t root_size() const { cant_recurse("root_size"); recursing_const_lock lock(*this); diff --git a/persistent-data/space_map.h b/persistent-data/space_map.h index 5395c90..064ff76 100644 --- a/persistent-data/space_map.h +++ b/persistent-data/space_map.h @@ -141,6 +141,7 @@ namespace persistent_data { public: typedef boost::shared_ptr ptr; + virtual void count_metadata(block_counter &bc) const = 0; virtual size_t root_size() const = 0; virtual void copy_root(void *dest, size_t len) const = 0; }; diff --git a/thin-provisioning/thin_check.cc b/thin-provisioning/thin_check.cc index ea5e56e..1202876 100644 --- a/thin-provisioning/thin_check.cc +++ b/thin-provisioning/thin_check.cc @@ -24,7 +24,9 @@ #include "base/error_state.h" #include "base/nested_output.h" +#include "persistent-data/data-structures/btree_counter.h" #include "persistent-data/space-maps/core.h" +#include "persistent-data/space-maps/disk.h" #include "persistent-data/file_utils.h" #include "thin-provisioning/device_tree.h" #include "thin-provisioning/mapping_tree.h" @@ -209,9 +211,71 @@ namespace { } } - return combine_errors(sb_rep.get_error(), - combine_errors(mapping_rep.get_error(), - dev_rep.get_error())); + error_state mplus_err = combine_errors(sb_rep.get_error(), + combine_errors(mapping_rep.get_error(), + dev_rep.get_error())); + + // if we're checking everything, and there were no errors, + // then we should check the space maps too. + if (fs.check_device_tree && fs.check_mapping_tree_level2 && mplus_err == NO_ERROR) { + out << "checking space map counts" << end_message(); + { + nested_output::nest _ = out.push(); + block_counter bc; + + // Count the device tree + { + noop_value_counter vc; + device_tree dtree(tm, sb.device_details_root_, + device_tree_detail::device_details_traits::ref_counter()); + count_btree_blocks(dtree, bc, vc); + } + + // Count the mapping tree + { + noop_value_counter vc; + mapping_tree mtree(tm, sb.data_mapping_root_, + mapping_tree_detail::block_traits::ref_counter(tm->get_sm())); + count_btree_blocks(mtree, bc, vc); + } + + // Count the metadata space map + { + persistent_space_map::ptr metadata_sm = + open_metadata_sm(tm, static_cast(&sb.metadata_space_map_root_)); + metadata_sm->count_metadata(bc); + } + + // Count the data space map + { + persistent_space_map::ptr data_sm = + open_disk_sm(tm, static_cast(&sb.data_space_map_root_)); + data_sm->count_metadata(bc); + } + + // Finally we need to check the metadata + // space map agrees with the counts we've + // just calculated. + { + persistent_space_map::ptr metadata_sm = + open_metadata_sm(tm, static_cast(&sb.metadata_space_map_root_)); + for (unsigned b = 0; b < metadata_sm->get_nr_blocks(); b++) { + ref_t c_actual = metadata_sm->get_count(b); + ref_t c_expected = bc.get_count(b); + + if (c_actual != c_expected) { + out << "metadata reference counts differ for block " << b + << ", expected " << c_expected + << ", but got " << c_actual + << end_message(); + mplus_err = combine_errors(mplus_err, FATAL); + } + } + } + } + } + + return mplus_err; } int check(string const &path, flags fs) {