metadata_checker
This commit is contained in:
		
							
								
								
									
										1
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								Makefile
									
									
									
									
									
								
							@@ -9,6 +9,7 @@ SOURCE=\
 | 
			
		||||
	hex_dump.cc \
 | 
			
		||||
	human_readable_format.cc \
 | 
			
		||||
	metadata.cc \
 | 
			
		||||
	metadata_checker.cc \
 | 
			
		||||
	metadata_ll.cc \
 | 
			
		||||
	metadata_dump.cc \
 | 
			
		||||
	metadata_disk_structures.cc \
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										158
									
								
								metadata.cc
									
									
									
									
									
								
							
							
						
						
									
										158
									
								
								metadata.cc
									
									
									
									
									
								
							@@ -15,92 +15,6 @@ using namespace thin_provisioning;
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
	// As well as the standard btree checks, we build up a set of what
 | 
			
		||||
	// devices having mappings defined, which can later be cross
 | 
			
		||||
	// referenced with the details tree.  A separate block_counter is
 | 
			
		||||
	// used to later verify the data space map.
 | 
			
		||||
	class mapping_validator : public btree_checker<2, block_traits> {
 | 
			
		||||
	public:
 | 
			
		||||
		typedef boost::shared_ptr<mapping_validator> ptr;
 | 
			
		||||
 | 
			
		||||
		mapping_validator(block_counter &metadata_counter, block_counter &data_counter)
 | 
			
		||||
			: btree_checker<2, block_traits>(metadata_counter),
 | 
			
		||||
			  data_counter_(data_counter) {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Sharing can only occur in level 1 nodes.
 | 
			
		||||
		// FIXME: not true once we start having held roots.
 | 
			
		||||
		bool visit_internal_leaf(unsigned level,
 | 
			
		||||
					 bool sub_root,
 | 
			
		||||
					 optional<uint64_t> key,
 | 
			
		||||
					 btree_detail::node_ref<uint64_traits> const &n) {
 | 
			
		||||
 | 
			
		||||
			bool r = btree_checker<2, block_traits>::visit_internal_leaf(level, sub_root, key, n);
 | 
			
		||||
			if (!r && level == 0) {
 | 
			
		||||
				throw runtime_error("unexpected sharing in level 0 of mapping tree.");
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			for (unsigned i = 0; i < n.get_nr_entries(); i++)
 | 
			
		||||
				devices_.insert(n.key_at(i));
 | 
			
		||||
 | 
			
		||||
			return r;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		bool visit_leaf(unsigned level,
 | 
			
		||||
				bool sub_root,
 | 
			
		||||
				optional<uint64_t> key,
 | 
			
		||||
				btree_detail::node_ref<block_traits> const &n) {
 | 
			
		||||
			bool r = btree_checker<2, block_traits>::visit_leaf(level, sub_root, key, n);
 | 
			
		||||
 | 
			
		||||
			if (r)
 | 
			
		||||
				for (unsigned i = 0; i < n.get_nr_entries(); i++)
 | 
			
		||||
					data_counter_.inc(n.value_at(i).block_);
 | 
			
		||||
 | 
			
		||||
			return r;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		set<uint64_t> const &get_devices() const {
 | 
			
		||||
			return devices_;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		block_counter &data_counter_;
 | 
			
		||||
		set<uint64_t> devices_;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	class details_validator : public btree_checker<1, device_details_traits> {
 | 
			
		||||
	public:
 | 
			
		||||
		typedef boost::shared_ptr<details_validator> ptr;
 | 
			
		||||
 | 
			
		||||
		details_validator(block_counter &counter)
 | 
			
		||||
			: btree_checker<1, device_details_traits>(counter) {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		bool visit_leaf(unsigned level,
 | 
			
		||||
				bool sub_root,
 | 
			
		||||
				optional<uint64_t> key,
 | 
			
		||||
				btree_detail::node_ref<device_details_traits> const &n) {
 | 
			
		||||
			bool r = btree_checker<1, device_details_traits>::visit_leaf(level, sub_root, key, n);
 | 
			
		||||
 | 
			
		||||
			if (r)
 | 
			
		||||
				for (unsigned i = 0; i < n.get_nr_entries(); i++)
 | 
			
		||||
					devices_.insert(n.key_at(i));
 | 
			
		||||
 | 
			
		||||
			return r;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		set<uint64_t> const &get_devices() const {
 | 
			
		||||
			return devices_;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		set<uint64_t> devices_;
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
thin::thin(thin_dev_t dev, metadata *metadata)
 | 
			
		||||
	: dev_(dev),
 | 
			
		||||
	  metadata_(metadata)
 | 
			
		||||
@@ -298,76 +212,4 @@ metadata::device_exists(thin_dev_t dev) const
 | 
			
		||||
	return md_->details_.lookup(key);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
	struct check_count : public space_map::iterator {
 | 
			
		||||
		check_count(string const &desc, block_counter const &expected)
 | 
			
		||||
			: bad_(false),
 | 
			
		||||
			  expected_(expected),
 | 
			
		||||
			  errors_(new error_set(desc)) {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		virtual void operator() (block_address b, ref_t actual) {
 | 
			
		||||
			ref_t expected = expected_.get_count(b);
 | 
			
		||||
 | 
			
		||||
			if (actual != expected) {
 | 
			
		||||
				ostringstream out;
 | 
			
		||||
				out << b << ": was " << actual
 | 
			
		||||
				    << ", expected " << expected;
 | 
			
		||||
				errors_->add_child(out.str());
 | 
			
		||||
				bad_ = true;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		bool bad_;
 | 
			
		||||
		block_counter const &expected_;
 | 
			
		||||
		error_set::ptr errors_;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	optional<error_set::ptr>
 | 
			
		||||
	check_ref_counts(string const &desc, block_counter const &counts,
 | 
			
		||||
			 space_map::ptr sm) {
 | 
			
		||||
 | 
			
		||||
		check_count checker(desc, counts);
 | 
			
		||||
		sm->iterate(checker);
 | 
			
		||||
		return checker.bad_ ? optional<error_set::ptr>(checker.errors_) : optional<error_set::ptr>();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
boost::optional<error_set::ptr>
 | 
			
		||||
metadata::check()
 | 
			
		||||
{
 | 
			
		||||
	error_set::ptr errors(new error_set("Errors in metadata"));
 | 
			
		||||
 | 
			
		||||
	block_counter metadata_counter, data_counter;
 | 
			
		||||
 | 
			
		||||
	mapping_validator::ptr mv(new mapping_validator(metadata_counter,
 | 
			
		||||
							data_counter));
 | 
			
		||||
	md_->mappings_.visit(mv);
 | 
			
		||||
	set<uint64_t> const &mapped_devs = mv->get_devices();
 | 
			
		||||
 | 
			
		||||
	details_validator::ptr dv(new details_validator(metadata_counter));
 | 
			
		||||
	md_->details_.visit(dv);
 | 
			
		||||
	set<uint64_t> const &details_devs = dv->get_devices();
 | 
			
		||||
 | 
			
		||||
	for (set<uint64_t>::const_iterator it = mapped_devs.begin(); it != mapped_devs.end(); ++it)
 | 
			
		||||
		if (details_devs.count(*it) == 0) {
 | 
			
		||||
			ostringstream out;
 | 
			
		||||
			out << "mapping exists for device " << *it
 | 
			
		||||
			    << ", yet there is no entry in the details tree.";
 | 
			
		||||
			throw runtime_error(out.str());
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	metadata_counter.inc(SUPERBLOCK_LOCATION);
 | 
			
		||||
	md_->metadata_sm_->check(metadata_counter);
 | 
			
		||||
	md_->data_sm_->check(metadata_counter);
 | 
			
		||||
	errors->add_child(check_ref_counts("Errors in metadata block reference counts",
 | 
			
		||||
					   metadata_counter, md_->metadata_sm_));
 | 
			
		||||
	errors->add_child(check_ref_counts("Errors in data block reference counts",
 | 
			
		||||
					   data_counter, md_->data_sm_));
 | 
			
		||||
 | 
			
		||||
	return (errors->get_children().size() > 0) ?
 | 
			
		||||
		optional<error_set::ptr>(errors) :
 | 
			
		||||
		optional<error_set::ptr>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 
 | 
			
		||||
@@ -2,11 +2,9 @@
 | 
			
		||||
#define MULTISNAP_METADATA_H
 | 
			
		||||
 | 
			
		||||
#include "emitter.h"
 | 
			
		||||
#include "error_set.h"
 | 
			
		||||
#include "metadata_ll.h"
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
#include <boost/shared_ptr.hpp>
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
@@ -62,10 +60,6 @@ namespace thin_provisioning {
 | 
			
		||||
 | 
			
		||||
		thin::ptr open_thin(thin_dev_t);
 | 
			
		||||
 | 
			
		||||
		// FIXME: split out into a separate interface
 | 
			
		||||
		// Validation
 | 
			
		||||
		boost::optional<persistent_data::error_set::ptr> check();
 | 
			
		||||
 | 
			
		||||
		// FIXME: split out into a separate interface
 | 
			
		||||
		// Dumping metadata
 | 
			
		||||
		void dump(emitter::ptr e);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										164
									
								
								metadata_checker.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								metadata_checker.cc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,164 @@
 | 
			
		||||
#include "metadata_checker.h"
 | 
			
		||||
 | 
			
		||||
using namespace thin_provisioning;
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
	// As well as the standard btree checks, we build up a set of what
 | 
			
		||||
	// devices having mappings defined, which can later be cross
 | 
			
		||||
	// referenced with the details tree.  A separate block_counter is
 | 
			
		||||
	// used to later verify the data space map.
 | 
			
		||||
	class mapping_validator : public btree_checker<2, block_traits> {
 | 
			
		||||
	public:
 | 
			
		||||
		typedef boost::shared_ptr<mapping_validator> ptr;
 | 
			
		||||
 | 
			
		||||
		mapping_validator(block_counter &metadata_counter, block_counter &data_counter)
 | 
			
		||||
			: btree_checker<2, block_traits>(metadata_counter),
 | 
			
		||||
			  data_counter_(data_counter) {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Sharing can only occur in level 1 nodes.
 | 
			
		||||
		// FIXME: not true once we start having held roots.
 | 
			
		||||
		bool visit_internal_leaf(unsigned level,
 | 
			
		||||
					 bool sub_root,
 | 
			
		||||
					 optional<uint64_t> key,
 | 
			
		||||
					 btree_detail::node_ref<uint64_traits> const &n) {
 | 
			
		||||
 | 
			
		||||
			bool r = btree_checker<2, block_traits>::visit_internal_leaf(level, sub_root, key, n);
 | 
			
		||||
			if (!r && level == 0) {
 | 
			
		||||
				throw runtime_error("unexpected sharing in level 0 of mapping tree.");
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			for (unsigned i = 0; i < n.get_nr_entries(); i++)
 | 
			
		||||
				devices_.insert(n.key_at(i));
 | 
			
		||||
 | 
			
		||||
			return r;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		bool visit_leaf(unsigned level,
 | 
			
		||||
				bool sub_root,
 | 
			
		||||
				optional<uint64_t> key,
 | 
			
		||||
				btree_detail::node_ref<block_traits> const &n) {
 | 
			
		||||
			bool r = btree_checker<2, block_traits>::visit_leaf(level, sub_root, key, n);
 | 
			
		||||
 | 
			
		||||
			if (r)
 | 
			
		||||
				for (unsigned i = 0; i < n.get_nr_entries(); i++)
 | 
			
		||||
					data_counter_.inc(n.value_at(i).block_);
 | 
			
		||||
 | 
			
		||||
			return r;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		set<uint64_t> const &get_devices() const {
 | 
			
		||||
			return devices_;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		block_counter &data_counter_;
 | 
			
		||||
		set<uint64_t> devices_;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	class details_validator : public btree_checker<1, device_details_traits> {
 | 
			
		||||
	public:
 | 
			
		||||
		typedef boost::shared_ptr<details_validator> ptr;
 | 
			
		||||
 | 
			
		||||
		details_validator(block_counter &counter)
 | 
			
		||||
			: btree_checker<1, device_details_traits>(counter) {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		bool visit_leaf(unsigned level,
 | 
			
		||||
				bool sub_root,
 | 
			
		||||
				optional<uint64_t> key,
 | 
			
		||||
				btree_detail::node_ref<device_details_traits> const &n) {
 | 
			
		||||
			bool r = btree_checker<1, device_details_traits>::visit_leaf(level, sub_root, key, n);
 | 
			
		||||
 | 
			
		||||
			if (r)
 | 
			
		||||
				for (unsigned i = 0; i < n.get_nr_entries(); i++)
 | 
			
		||||
					devices_.insert(n.key_at(i));
 | 
			
		||||
 | 
			
		||||
			return r;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		set<uint64_t> const &get_devices() const {
 | 
			
		||||
			return devices_;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		set<uint64_t> devices_;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct check_count : public space_map::iterator {
 | 
			
		||||
		check_count(string const &desc, block_counter const &expected)
 | 
			
		||||
			: bad_(false),
 | 
			
		||||
			  expected_(expected),
 | 
			
		||||
			  errors_(new error_set(desc)) {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		virtual void operator() (block_address b, ref_t actual) {
 | 
			
		||||
			ref_t expected = expected_.get_count(b);
 | 
			
		||||
 | 
			
		||||
			if (actual != expected) {
 | 
			
		||||
				ostringstream out;
 | 
			
		||||
				out << b << ": was " << actual
 | 
			
		||||
				    << ", expected " << expected;
 | 
			
		||||
				errors_->add_child(out.str());
 | 
			
		||||
				bad_ = true;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		bool bad_;
 | 
			
		||||
		block_counter const &expected_;
 | 
			
		||||
		error_set::ptr errors_;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	optional<error_set::ptr>
 | 
			
		||||
	check_ref_counts(string const &desc, block_counter const &counts,
 | 
			
		||||
			 space_map::ptr sm) {
 | 
			
		||||
 | 
			
		||||
		check_count checker(desc, counts);
 | 
			
		||||
		sm->iterate(checker);
 | 
			
		||||
		return checker.bad_ ? optional<error_set::ptr>(checker.errors_) : optional<error_set::ptr>();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
boost::optional<error_set::ptr>
 | 
			
		||||
thin_provisioning::metadata_check(metadata_ll::ptr md)
 | 
			
		||||
{
 | 
			
		||||
	error_set::ptr errors(new error_set("Errors in metadata"));
 | 
			
		||||
 | 
			
		||||
	block_counter metadata_counter, data_counter;
 | 
			
		||||
 | 
			
		||||
	mapping_validator::ptr mv(new mapping_validator(metadata_counter,
 | 
			
		||||
							data_counter));
 | 
			
		||||
	md->mappings_.visit(mv);
 | 
			
		||||
	set<uint64_t> const &mapped_devs = mv->get_devices();
 | 
			
		||||
 | 
			
		||||
	details_validator::ptr dv(new details_validator(metadata_counter));
 | 
			
		||||
	md->details_.visit(dv);
 | 
			
		||||
	set<uint64_t> const &details_devs = dv->get_devices();
 | 
			
		||||
 | 
			
		||||
	for (set<uint64_t>::const_iterator it = mapped_devs.begin(); it != mapped_devs.end(); ++it)
 | 
			
		||||
		if (details_devs.count(*it) == 0) {
 | 
			
		||||
			ostringstream out;
 | 
			
		||||
			out << "mapping exists for device " << *it
 | 
			
		||||
			    << ", yet there is no entry in the details tree.";
 | 
			
		||||
			throw runtime_error(out.str());
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	metadata_counter.inc(SUPERBLOCK_LOCATION);
 | 
			
		||||
	md->metadata_sm_->check(metadata_counter);
 | 
			
		||||
	md->data_sm_->check(metadata_counter);
 | 
			
		||||
	errors->add_child(check_ref_counts("Errors in metadata block reference counts",
 | 
			
		||||
					   metadata_counter, md->metadata_sm_));
 | 
			
		||||
	errors->add_child(check_ref_counts("Errors in data block reference counts",
 | 
			
		||||
					   data_counter, md->data_sm_));
 | 
			
		||||
 | 
			
		||||
	return (errors->get_children().size() > 0) ?
 | 
			
		||||
		optional<error_set::ptr>(errors) :
 | 
			
		||||
		optional<error_set::ptr>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
							
								
								
									
										15
									
								
								metadata_checker.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								metadata_checker.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
#ifndef METADATA_CHECKER_H
 | 
			
		||||
#define METADATA_CHECKER_H
 | 
			
		||||
 | 
			
		||||
#include "error_set.h"
 | 
			
		||||
#include "metadata_ll.h"
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
namespace thin_provisioning {
 | 
			
		||||
	boost::optional<persistent_data::error_set::ptr> metadata_check(metadata_ll::ptr md);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
#include "metadata.h"
 | 
			
		||||
#include "metadata_checker.h"
 | 
			
		||||
 | 
			
		||||
using namespace boost;
 | 
			
		||||
using namespace persistent_data;
 | 
			
		||||
@@ -9,10 +10,9 @@ using namespace thin_provisioning;
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
	int check(string const &path) {
 | 
			
		||||
		metadata_ll::ptr ll(new metadata_ll(path));
 | 
			
		||||
		metadata md(ll);
 | 
			
		||||
		metadata_ll::ptr md(new metadata_ll(path));
 | 
			
		||||
 | 
			
		||||
		optional<error_set::ptr> maybe_errors = md.check();
 | 
			
		||||
		optional<error_set::ptr> maybe_errors = metadata_check(md);
 | 
			
		||||
		if (maybe_errors) {
 | 
			
		||||
			cerr << error_selector(*maybe_errors, 3);
 | 
			
		||||
			return 1;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user