A stack of thin_check refactorings
This commit is contained in:
		@@ -56,6 +56,7 @@ SOURCE=\
 | 
				
			|||||||
	thin-provisioning/metadata_dumper.cc \
 | 
						thin-provisioning/metadata_dumper.cc \
 | 
				
			||||||
	thin-provisioning/restore_emitter.cc \
 | 
						thin-provisioning/restore_emitter.cc \
 | 
				
			||||||
	thin-provisioning/superblock_validator.cc \
 | 
						thin-provisioning/superblock_validator.cc \
 | 
				
			||||||
 | 
						thin-provisioning/superblock_checker.cc \
 | 
				
			||||||
	thin-provisioning/thin_pool.cc \
 | 
						thin-provisioning/thin_pool.cc \
 | 
				
			||||||
	thin-provisioning/xml_format.cc
 | 
						thin-provisioning/xml_format.cc
 | 
				
			||||||
PDATA_OBJECTS=$(subst .cc,.o,$(SOURCE))
 | 
					PDATA_OBJECTS=$(subst .cc,.o,$(SOURCE))
 | 
				
			||||||
@@ -136,6 +137,7 @@ THIN_CHECK_SOURCE=\
 | 
				
			|||||||
	thin-provisioning/metadata.cc \
 | 
						thin-provisioning/metadata.cc \
 | 
				
			||||||
	thin-provisioning/metadata_checker.cc \
 | 
						thin-provisioning/metadata_checker.cc \
 | 
				
			||||||
	thin-provisioning/metadata_disk_structures.cc \
 | 
						thin-provisioning/metadata_disk_structures.cc \
 | 
				
			||||||
 | 
						thin-provisioning/superblock_checker.cc \
 | 
				
			||||||
	thin-provisioning/superblock_validator.cc
 | 
						thin-provisioning/superblock_validator.cc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
THIN_DEBUG_OBJECTS=$(subst .cc,.o,$(THIN_DEBUG_SOURCE))
 | 
					THIN_DEBUG_OBJECTS=$(subst .cc,.o,$(THIN_DEBUG_SOURCE))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -49,7 +49,6 @@ Feature: thin_check
 | 
				
			|||||||
    When I run thin_check with --super-block-only
 | 
					    When I run thin_check with --super-block-only
 | 
				
			||||||
    Then it should pass
 | 
					    Then it should pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @announce
 | 
					 | 
				
			||||||
  Scenario: --super-block-only check fails with corrupt superblock
 | 
					  Scenario: --super-block-only check fails with corrupt superblock
 | 
				
			||||||
    Given a corrupt superblock
 | 
					    Given a corrupt superblock
 | 
				
			||||||
    When I run thin_check with --super-block-only
 | 
					    When I run thin_check with --super-block-only
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,15 +38,18 @@ using namespace thin_provisioning;
 | 
				
			|||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
	unsigned const METADATA_CACHE_SIZE = 1024;
 | 
						unsigned const METADATA_CACHE_SIZE = 1024;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	transaction_manager::ptr
 | 
						block_manager<>::ptr open_bm(string const &dev_path, bool writeable) {
 | 
				
			||||||
	open_tm(string const &dev_path, bool writeable) {
 | 
					 | 
				
			||||||
		block_address nr_blocks = get_nr_blocks(dev_path);
 | 
							block_address nr_blocks = get_nr_blocks(dev_path);
 | 
				
			||||||
		typename block_io<>::mode m = writeable ?
 | 
							typename block_io<>::mode m = writeable ?
 | 
				
			||||||
			block_io<>::READ_WRITE :
 | 
								block_io<>::READ_WRITE :
 | 
				
			||||||
			block_io<>::READ_ONLY;
 | 
								block_io<>::READ_ONLY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		block_manager<>::ptr bm(new block_manager<>(dev_path, nr_blocks, 1, m));
 | 
							return block_manager<>::ptr(new block_manager<>(dev_path, nr_blocks, 1, m));
 | 
				
			||||||
		space_map::ptr sm(new core_map(nr_blocks));
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						transaction_manager::ptr
 | 
				
			||||||
 | 
						open_tm(block_manager<>::ptr bm) {
 | 
				
			||||||
 | 
							space_map::ptr sm(new core_map(bm->get_nr_blocks()));
 | 
				
			||||||
		sm->inc(SUPERBLOCK_LOCATION);
 | 
							sm->inc(SUPERBLOCK_LOCATION);
 | 
				
			||||||
		transaction_manager::ptr tm(new transaction_manager(bm, sm));
 | 
							transaction_manager::ptr tm(new transaction_manager(bm, sm));
 | 
				
			||||||
		return tm;
 | 
							return tm;
 | 
				
			||||||
@@ -69,6 +72,21 @@ namespace {
 | 
				
			|||||||
				lhs->set_count(b, rhs->get_count(b));
 | 
									lhs->set_count(b, rhs->get_count(b));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void print_superblock(superblock const &sb) {
 | 
				
			||||||
 | 
							using namespace std;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							cerr << "superblock " << sb.csum_ << endl
 | 
				
			||||||
 | 
							     << "flags " << sb.flags_ << endl
 | 
				
			||||||
 | 
							     << "blocknr " << sb.blocknr_ << endl
 | 
				
			||||||
 | 
							     << "transaction id " << sb.trans_id_ << endl
 | 
				
			||||||
 | 
							     << "data mapping root " << sb.data_mapping_root_ << endl
 | 
				
			||||||
 | 
							     << "details root " << sb.device_details_root_ << endl
 | 
				
			||||||
 | 
							     << "data block size " << sb.data_block_size_ << endl
 | 
				
			||||||
 | 
							     << "metadata block size " << sb.metadata_block_size_ << endl
 | 
				
			||||||
 | 
							     << "metadata nr blocks " << sb.metadata_nr_blocks_ << endl
 | 
				
			||||||
 | 
								;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//----------------------------------------------------------------
 | 
					//----------------------------------------------------------------
 | 
				
			||||||
@@ -78,7 +96,7 @@ metadata::metadata(std::string const &dev_path, open_type ot,
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	switch (ot) {
 | 
						switch (ot) {
 | 
				
			||||||
	case OPEN:
 | 
						case OPEN:
 | 
				
			||||||
		tm_ = open_tm(dev_path, false);
 | 
							tm_ = open_tm(open_bm(dev_path, false));
 | 
				
			||||||
		sb_ = read_superblock(tm_->get_bm());
 | 
							sb_ = read_superblock(tm_->get_bm());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (sb_.version_ != 1)
 | 
							if (sb_.version_ != 1)
 | 
				
			||||||
@@ -94,7 +112,7 @@ metadata::metadata(std::string const &dev_path, open_type ot,
 | 
				
			|||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case CREATE:
 | 
						case CREATE:
 | 
				
			||||||
		tm_ = open_tm(dev_path, true);
 | 
							tm_ = open_tm(open_bm(dev_path, true));
 | 
				
			||||||
		space_map::ptr core = tm_->get_sm();
 | 
							space_map::ptr core = tm_->get_sm();
 | 
				
			||||||
		metadata_sm_ = create_metadata_sm(tm_, tm_->get_bm()->get_nr_blocks());
 | 
							metadata_sm_ = create_metadata_sm(tm_, tm_->get_bm()->get_nr_blocks());
 | 
				
			||||||
		copy_space_maps(metadata_sm_, core);
 | 
							copy_space_maps(metadata_sm_, core);
 | 
				
			||||||
@@ -120,7 +138,7 @@ metadata::metadata(std::string const &dev_path, open_type ot,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
metadata::metadata(std::string const &dev_path, block_address metadata_snap)
 | 
					metadata::metadata(std::string const &dev_path, block_address metadata_snap)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	tm_ = open_tm(dev_path, false);
 | 
						tm_ = open_tm(open_bm(dev_path, false));
 | 
				
			||||||
	sb_ = read_superblock(tm_->get_bm(), metadata_snap);
 | 
						sb_ = read_superblock(tm_->get_bm(), metadata_snap);
 | 
				
			||||||
	// We don't open the metadata sm for a held root
 | 
						// We don't open the metadata sm for a held root
 | 
				
			||||||
	//metadata_sm_ = open_metadata_sm(tm_, &sb_.metadata_space_map_root_);
 | 
						//metadata_sm_ = open_metadata_sm(tm_, &sb_.metadata_space_map_root_);
 | 
				
			||||||
@@ -132,20 +150,50 @@ metadata::metadata(std::string const &dev_path, block_address metadata_snap)
 | 
				
			|||||||
	mappings_ = mapping_tree::ptr(new mapping_tree(tm_, sb_.data_mapping_root_, block_time_ref_counter(data_sm_)));
 | 
						mappings_ = mapping_tree::ptr(new mapping_tree(tm_, sb_.data_mapping_root_, block_time_ref_counter(data_sm_)));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					// FIXME: duplication
 | 
				
			||||||
	void print_superblock(superblock const &sb) {
 | 
					metadata::metadata(block_manager<>::ptr bm, open_type ot,
 | 
				
			||||||
		using namespace std;
 | 
							   sector_t data_block_size,
 | 
				
			||||||
 | 
							   block_address nr_data_blocks)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (ot) {
 | 
				
			||||||
 | 
						case OPEN:
 | 
				
			||||||
 | 
							tm_ = open_tm(bm);
 | 
				
			||||||
 | 
							sb_ = read_superblock(tm_->get_bm());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		cerr << "superblock " << sb.csum_ << endl
 | 
							if (sb_.version_ != 1)
 | 
				
			||||||
		     << "flags " << sb.flags_ << endl
 | 
								throw runtime_error("unknown metadata version");
 | 
				
			||||||
		     << "blocknr " << sb.blocknr_ << endl
 | 
					
 | 
				
			||||||
		     << "transaction id " << sb.trans_id_ << endl
 | 
							metadata_sm_ = open_metadata_sm(tm_, &sb_.metadata_space_map_root_);
 | 
				
			||||||
		     << "data mapping root " << sb.data_mapping_root_ << endl
 | 
							tm_->set_sm(metadata_sm_);
 | 
				
			||||||
		     << "details root " << sb.device_details_root_ << endl
 | 
					
 | 
				
			||||||
		     << "data block size " << sb.data_block_size_ << endl
 | 
							data_sm_ = open_disk_sm(tm_, static_cast<void *>(&sb_.data_space_map_root_));
 | 
				
			||||||
		     << "metadata block size " << sb.metadata_block_size_ << endl
 | 
							details_ = detail_tree::ptr(new detail_tree(tm_, sb_.device_details_root_, device_details_traits::ref_counter()));
 | 
				
			||||||
		     << "metadata nr blocks " << sb.metadata_nr_blocks_ << endl
 | 
							mappings_top_level_ = dev_tree::ptr(new dev_tree(tm_, sb_.data_mapping_root_, mtree_ref_counter(tm_)));
 | 
				
			||||||
			;
 | 
							mappings_ = mapping_tree::ptr(new mapping_tree(tm_, sb_.data_mapping_root_, block_time_ref_counter(data_sm_)));
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case CREATE:
 | 
				
			||||||
 | 
							tm_ = open_tm(bm);
 | 
				
			||||||
 | 
							space_map::ptr core = tm_->get_sm();
 | 
				
			||||||
 | 
							metadata_sm_ = create_metadata_sm(tm_, tm_->get_bm()->get_nr_blocks());
 | 
				
			||||||
 | 
							copy_space_maps(metadata_sm_, core);
 | 
				
			||||||
 | 
							tm_->set_sm(metadata_sm_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							data_sm_ = create_disk_sm(tm_, nr_data_blocks);
 | 
				
			||||||
 | 
							details_ = detail_tree::ptr(new detail_tree(tm_, device_details_traits::ref_counter()));
 | 
				
			||||||
 | 
							mappings_ = mapping_tree::ptr(new mapping_tree(tm_, block_time_ref_counter(data_sm_)));
 | 
				
			||||||
 | 
							mappings_top_level_ = dev_tree::ptr(new dev_tree(tm_, mappings_->get_root(), mtree_ref_counter(tm_)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							::memset(&sb_, 0, sizeof(sb_));
 | 
				
			||||||
 | 
							sb_.magic_ = SUPERBLOCK_MAGIC;
 | 
				
			||||||
 | 
							sb_.version_ = 1;
 | 
				
			||||||
 | 
							sb_.data_mapping_root_ = mappings_->get_root();
 | 
				
			||||||
 | 
							sb_.device_details_root_ = details_->get_root();
 | 
				
			||||||
 | 
							sb_.data_block_size_ = data_block_size;
 | 
				
			||||||
 | 
							sb_.metadata_block_size_ = MD_BLOCK_SIZE;
 | 
				
			||||||
 | 
							sb_.metadata_nr_blocks_ = tm_->get_bm()->get_nr_blocks();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,8 +34,6 @@ namespace thin_provisioning {
 | 
				
			|||||||
	using namespace base;
 | 
						using namespace base;
 | 
				
			||||||
	using namespace persistent_data;
 | 
						using namespace persistent_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	block_address const SUPERBLOCK_LOCATION = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	typedef uint64_t sector_t;
 | 
						typedef uint64_t sector_t;
 | 
				
			||||||
	typedef uint32_t thin_dev_t;
 | 
						typedef uint32_t thin_dev_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -148,17 +146,27 @@ namespace thin_provisioning {
 | 
				
			|||||||
			OPEN
 | 
								OPEN
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							typedef block_manager<>::read_ref read_ref;
 | 
				
			||||||
 | 
							typedef block_manager<>::write_ref write_ref;
 | 
				
			||||||
 | 
							typedef boost::shared_ptr<metadata> ptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Deprecated: it would be better if we passed in an already
 | 
				
			||||||
 | 
							// constructed block_manager.
 | 
				
			||||||
		metadata(std::string const &dev_path, open_type ot,
 | 
							metadata(std::string const &dev_path, open_type ot,
 | 
				
			||||||
			 sector_t data_block_size = 128,
 | 
								 sector_t data_block_size = 128,
 | 
				
			||||||
			 block_address nr_data_blocks = 0); // Only used if CREATE
 | 
								 block_address nr_data_blocks = 0); // Only used if CREATE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		metadata(std::string const &dev_path, block_address metadata_snap);
 | 
							metadata(std::string const &dev_path, block_address metadata_snap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// ... use these instead ...
 | 
				
			||||||
 | 
							metadata(block_manager<>::ptr bm, open_type ot,
 | 
				
			||||||
 | 
								 sector_t data_block_size = 128,
 | 
				
			||||||
 | 
								 block_address nr_data_blocks = 0); // Only used if CREATE
 | 
				
			||||||
 | 
							metadata(block_manager<>::ptr bm, block_address metadata_snap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void commit();
 | 
							void commit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		typedef block_manager<>::read_ref read_ref;
 | 
					 | 
				
			||||||
		typedef block_manager<>::write_ref write_ref;
 | 
					 | 
				
			||||||
		typedef boost::shared_ptr<metadata> ptr;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		tm_ptr tm_;
 | 
							tm_ptr tm_;
 | 
				
			||||||
		superblock sb_;
 | 
							superblock sb_;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,10 +21,155 @@
 | 
				
			|||||||
#include "thin-provisioning/metadata_checker.h"
 | 
					#include "thin-provisioning/metadata_checker.h"
 | 
				
			||||||
#include "thin-provisioning/superblock_validator.h"
 | 
					#include "thin-provisioning/superblock_validator.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using namespace persistent_data;
 | 
				
			||||||
using namespace thin_provisioning;
 | 
					using namespace thin_provisioning;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//----------------------------------------------------------------
 | 
					//----------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					metadata_damage::set_message(std::string const &message)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						message_ = message;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::string const &
 | 
				
			||||||
 | 
					metadata_damage::get_message() const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return message_;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//--------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					super_block_corruption::visit(metadata_damage_visitor &visitor) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						visitor.visit(*this);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//--------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					missing_device_details::missing_device_details(uint64_t missing_begin,
 | 
				
			||||||
 | 
										       uint64_t missing_end)
 | 
				
			||||||
 | 
						: missing_begin_(missing_begin),
 | 
				
			||||||
 | 
						  missing_end_(missing_end)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					missing_device_details::visit(metadata_damage_visitor &visitor) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						visitor.visit(*this);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//--------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					missing_devices::missing_devices(uint64_t missing_begin,
 | 
				
			||||||
 | 
									 uint64_t missing_end)
 | 
				
			||||||
 | 
						: missing_begin_(missing_begin),
 | 
				
			||||||
 | 
						  missing_end_(missing_end)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					missing_devices::visit(metadata_damage_visitor &visitor) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						visitor.visit(*this);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//--------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					missing_mappings::missing_mappings(uint64_t dev,
 | 
				
			||||||
 | 
									   uint64_t missing_begin,
 | 
				
			||||||
 | 
									   uint64_t missing_end)
 | 
				
			||||||
 | 
						: dev_(dev),
 | 
				
			||||||
 | 
						  missing_begin_(missing_begin),
 | 
				
			||||||
 | 
						  missing_end_(missing_end)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					missing_mappings::visit(metadata_damage_visitor &visitor) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						visitor.visit(*this);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//--------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bad_metadata_ref_count::bad_metadata_ref_count(block_address b,
 | 
				
			||||||
 | 
										       ref_t actual,
 | 
				
			||||||
 | 
										       ref_t expected)
 | 
				
			||||||
 | 
						: b_(b),
 | 
				
			||||||
 | 
						  actual_(actual),
 | 
				
			||||||
 | 
						  expected_(expected)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					bad_metadata_ref_count::visit(metadata_damage_visitor &visitor) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						visitor.visit(*this);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//--------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bad_data_ref_count::bad_data_ref_count(block_address b,
 | 
				
			||||||
 | 
									       ref_t actual,
 | 
				
			||||||
 | 
									       ref_t expected)
 | 
				
			||||||
 | 
						: b_(b),
 | 
				
			||||||
 | 
						  actual_(actual),
 | 
				
			||||||
 | 
						  expected_(expected)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					bad_data_ref_count::visit(metadata_damage_visitor &visitor) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						visitor.visit(*this);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//--------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					missing_metadata_ref_counts::missing_metadata_ref_counts(block_address missing_begin,
 | 
				
			||||||
 | 
												 block_address missing_end)
 | 
				
			||||||
 | 
						: missing_begin_(missing_begin),
 | 
				
			||||||
 | 
						  missing_end_(missing_end)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					missing_metadata_ref_counts::visit(metadata_damage_visitor &visitor) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						visitor.visit(*this);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//--------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					missing_data_ref_counts::missing_data_ref_counts(block_address missing_begin,
 | 
				
			||||||
 | 
											 block_address missing_end)
 | 
				
			||||||
 | 
						: missing_begin_(missing_begin),
 | 
				
			||||||
 | 
						  missing_end_(missing_end)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					missing_data_ref_counts::visit(metadata_damage_visitor &visitor) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						visitor.visit(*this);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//--------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					metadata_damage_visitor::visit(metadata_damage const &damage)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						damage.visit(*this);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//----------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
	// As well as the standard btree checks, we build up a set of what
 | 
						// As well as the standard btree checks, we build up a set of what
 | 
				
			||||||
	// devices having mappings defined, which can later be cross
 | 
						// devices having mappings defined, which can later be cross
 | 
				
			||||||
@@ -166,19 +311,24 @@ namespace {
 | 
				
			|||||||
	class metadata_checker {
 | 
						class metadata_checker {
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
		metadata_checker(string const &dev_path)
 | 
							metadata_checker(string const &dev_path)
 | 
				
			||||||
		: bm_(open_bm(dev_path)) {
 | 
							: bm_(open_bm(dev_path)),
 | 
				
			||||||
 | 
							  errors_(new error_set("Errors in metadata")) {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		boost::optional<error_set::ptr> check() {
 | 
							boost::optional<error_set::ptr> check() {
 | 
				
			||||||
#if 1
 | 
					#if 1
 | 
				
			||||||
			// FIXME: finish
 | 
					 | 
				
			||||||
			error_set::ptr errors(new error_set("Errors in metadata"));
 | 
					 | 
				
			||||||
			superblock sb = read_superblock();
 | 
								superblock sb = read_superblock();
 | 
				
			||||||
			return errors;
 | 
					
 | 
				
			||||||
 | 
								// FIXME: check version?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								check_mappings();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return (errors_->get_children().size() > 0) ?
 | 
				
			||||||
 | 
									optional<error_set::ptr>(errors_) :
 | 
				
			||||||
 | 
									optional<error_set::ptr>();
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
			error_set::ptr errors(new error_set("Errors in metadata"));
 | 
								error_set::ptr errors(new error_set("Errors in metadata"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			block_counter metadata_counter, data_counter;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (md->sb_.metadata_snap_) {
 | 
								if (md->sb_.metadata_snap_) {
 | 
				
			||||||
				block_manager<>::ptr bm = md->tm_->get_bm();
 | 
									block_manager<>::ptr bm = md->tm_->get_bm();
 | 
				
			||||||
@@ -197,9 +347,6 @@ namespace {
 | 
				
			|||||||
				metadata_counter.inc(sb.device_details_root_);
 | 
									metadata_counter.inc(sb.device_details_root_);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			mapping_validator::ptr mv(new mapping_validator(metadata_counter,
 | 
					 | 
				
			||||||
									data_counter));
 | 
					 | 
				
			||||||
			md->mappings_->visit(mv);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			set<uint64_t> const &mapped_devs = mv->get_devices();
 | 
								set<uint64_t> const &mapped_devs = mv->get_devices();
 | 
				
			||||||
			details_validator::ptr dv(new details_validator(metadata_counter));
 | 
								details_validator::ptr dv(new details_validator(metadata_counter));
 | 
				
			||||||
@@ -246,11 +393,26 @@ namespace {
 | 
				
			|||||||
			return sb;
 | 
								return sb;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							void check_mappings() {
 | 
				
			||||||
 | 
								mapping_validator::ptr mv(
 | 
				
			||||||
 | 
									new mapping_validator(metadata_counter_,
 | 
				
			||||||
 | 
											      data_counter_));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								md->mappings_->visit(mv);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		typedef block_manager<>::read_ref read_ref;
 | 
							typedef block_manager<>::read_ref read_ref;
 | 
				
			||||||
		typedef block_manager<>::write_ref write_ref;
 | 
							typedef block_manager<>::write_ref write_ref;
 | 
				
			||||||
		typedef boost::shared_ptr<metadata> ptr;
 | 
							typedef boost::shared_ptr<metadata> ptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		block_manager<>::ptr bm_;
 | 
							block_manager<>::ptr bm_;
 | 
				
			||||||
 | 
							error_set::ptr errors_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							block_counter metadata_counter_, data_counter_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if 0
 | 
					#if 0
 | 
				
			||||||
		tm_ptr tm_;
 | 
							tm_ptr tm_;
 | 
				
			||||||
		superblock sb_;
 | 
							superblock sb_;
 | 
				
			||||||
@@ -275,3 +437,4 @@ thin_provisioning::metadata_check(std::string const &dev_path)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//----------------------------------------------------------------
 | 
					//----------------------------------------------------------------
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,14 +19,140 @@
 | 
				
			|||||||
#ifndef METADATA_CHECKER_H
 | 
					#ifndef METADATA_CHECKER_H
 | 
				
			||||||
#define METADATA_CHECKER_H
 | 
					#define METADATA_CHECKER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "persistent-data/block.h"
 | 
				
			||||||
#include "persistent-data/error_set.h"
 | 
					#include "persistent-data/error_set.h"
 | 
				
			||||||
 | 
					#include "persistent-data/space_map.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <deque>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//----------------------------------------------------------------
 | 
					//----------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace thin_provisioning {
 | 
					namespace thin_provisioning {
 | 
				
			||||||
	// FIXME: pass in flags like --super-block-only
 | 
						class metadata_damage_visitor;
 | 
				
			||||||
	boost::optional<persistent_data::error_set::ptr>
 | 
					
 | 
				
			||||||
	metadata_check(std::string const &dev_path);
 | 
						// Base class for all types of metadata damage.  Used in reporting.
 | 
				
			||||||
 | 
						class metadata_damage {
 | 
				
			||||||
 | 
						public:
 | 
				
			||||||
 | 
							typedef boost::shared_ptr<metadata_damage> ptr;
 | 
				
			||||||
 | 
							virtual ~metadata_damage() {}
 | 
				
			||||||
 | 
							virtual void visit(metadata_damage_visitor &visitor) const = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							void set_message(std::string const &message);
 | 
				
			||||||
 | 
							std::string const &get_message() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private:
 | 
				
			||||||
 | 
							std::string message_;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						class super_block_corruption : public metadata_damage {
 | 
				
			||||||
 | 
							void visit(metadata_damage_visitor &visitor) const;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct missing_device_details : public metadata_damage {
 | 
				
			||||||
 | 
							missing_device_details(uint64_t missing_begin,
 | 
				
			||||||
 | 
									       uint64_t missing_end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							virtual void visit(metadata_damage_visitor &visitor) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							uint64_t missing_begin_;
 | 
				
			||||||
 | 
							uint64_t missing_end_;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct missing_devices : public metadata_damage {
 | 
				
			||||||
 | 
							missing_devices(uint64_t missing_begin,
 | 
				
			||||||
 | 
									uint64_t missing_end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							virtual void visit(metadata_damage_visitor &visitor) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							uint64_t missing_begin_;
 | 
				
			||||||
 | 
							uint64_t missing_end_;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct missing_mappings : public metadata_damage {
 | 
				
			||||||
 | 
							missing_mappings(uint64_t dev,
 | 
				
			||||||
 | 
									 uint64_t missing_begin,
 | 
				
			||||||
 | 
									 uint64_t missing_end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							virtual void visit(metadata_damage_visitor &visitor) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							uint64_t dev_;
 | 
				
			||||||
 | 
							uint64_t missing_begin_;
 | 
				
			||||||
 | 
							uint64_t missing_end_;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct bad_metadata_ref_count : public metadata_damage {
 | 
				
			||||||
 | 
							bad_metadata_ref_count(block_address b,
 | 
				
			||||||
 | 
									       ref_t actual,
 | 
				
			||||||
 | 
									       ref_t expected);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							virtual void visit(metadata_damage_visitor &visitor) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							block_address b_;
 | 
				
			||||||
 | 
							ref_t actual_;
 | 
				
			||||||
 | 
							ref_t expected_;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct bad_data_ref_count : public metadata_damage {
 | 
				
			||||||
 | 
							bad_data_ref_count(block_address b,
 | 
				
			||||||
 | 
									   ref_t actual,
 | 
				
			||||||
 | 
									   ref_t expected);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							virtual void visit(metadata_damage_visitor &visitor) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							block_address b_;
 | 
				
			||||||
 | 
							ref_t actual_;
 | 
				
			||||||
 | 
							ref_t expected_;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct missing_metadata_ref_counts : public metadata_damage {
 | 
				
			||||||
 | 
							missing_metadata_ref_counts(block_address missing_begin,
 | 
				
			||||||
 | 
										    block_address missing_end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							virtual void visit(metadata_damage_visitor &visitor) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							block_address missing_begin_;
 | 
				
			||||||
 | 
							block_address missing_end_;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct missing_data_ref_counts : public metadata_damage {
 | 
				
			||||||
 | 
							missing_data_ref_counts(block_address missing_begin,
 | 
				
			||||||
 | 
										block_address missing_end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							virtual void visit(metadata_damage_visitor &visitor) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							block_address missing_begin_;
 | 
				
			||||||
 | 
							block_address missing_end_;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						class metadata_damage_visitor {
 | 
				
			||||||
 | 
						public:
 | 
				
			||||||
 | 
							typedef boost::shared_ptr<metadata_damage_visitor> ptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							virtual ~metadata_damage_visitor() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							void visit(metadata_damage const &damage);
 | 
				
			||||||
 | 
							virtual void visit(super_block_corruption const &damage) = 0;
 | 
				
			||||||
 | 
							virtual void visit(missing_device_details const &damage) = 0;
 | 
				
			||||||
 | 
							virtual void visit(missing_devices const &damage) = 0;
 | 
				
			||||||
 | 
							virtual void visit(missing_mappings const &damage) = 0;
 | 
				
			||||||
 | 
							virtual void visit(bad_metadata_ref_count const &damage) = 0;
 | 
				
			||||||
 | 
							virtual void visit(bad_data_ref_count const &damage) = 0;
 | 
				
			||||||
 | 
							virtual void visit(missing_metadata_ref_counts const &damage) = 0;
 | 
				
			||||||
 | 
							virtual void visit(missing_data_ref_counts const &damage) = 0;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						typedef std::deque<metadata_damage::ptr> damage_list;
 | 
				
			||||||
 | 
						typedef boost::shared_ptr<damage_list> damage_list_ptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//--------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						class checker {
 | 
				
			||||||
 | 
						public:
 | 
				
			||||||
 | 
							typedef boost::shared_ptr<checker> ptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							virtual ~checker() {};
 | 
				
			||||||
 | 
							virtual damage_list_ptr check() = 0;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//----------------------------------------------------------------
 | 
					//----------------------------------------------------------------
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -128,6 +128,8 @@ namespace thin_provisioning {
 | 
				
			|||||||
		static void unpack(superblock_disk const &disk, superblock &core);
 | 
							static void unpack(superblock_disk const &disk, superblock &core);
 | 
				
			||||||
		static void pack(superblock const &core, superblock_disk &disk);
 | 
							static void pack(superblock const &core, superblock_disk &disk);
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						block_address const SUPERBLOCK_LOCATION = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//----------------------------------------------------------------
 | 
					//----------------------------------------------------------------
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										45
									
								
								thin-provisioning/superblock_checker.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								thin-provisioning/superblock_checker.cc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
				
			|||||||
 | 
					#include "thin-provisioning/superblock_checker.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "thin-provisioning/metadata_disk_structures.h"
 | 
				
			||||||
 | 
					#include "thin-provisioning/superblock_validator.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using namespace thin_provisioning;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//----------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					superblock_checker::superblock_checker(block_manager::ptr bm)
 | 
				
			||||||
 | 
						: bm_(bm),
 | 
				
			||||||
 | 
						  damage(new damage_list)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FIXME: Other things to check:
 | 
				
			||||||
 | 
					// - magic
 | 
				
			||||||
 | 
					// - version
 | 
				
			||||||
 | 
					// - 3 * flags (should be zero)
 | 
				
			||||||
 | 
					// - in bounds: metadata_snap, data_mapping_root
 | 
				
			||||||
 | 
					// - metadata_nr_blocks_ matches what we've been given.
 | 
				
			||||||
 | 
					damage_list_ptr
 | 
				
			||||||
 | 
					superblock_checker::check()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						superblock sb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						damage_list_ptr damage(new damage_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						try {
 | 
				
			||||||
 | 
							block_manager::read_ref r = bm_->read_lock(SUPERBLOCK_LOCATION, superblock_validator());
 | 
				
			||||||
 | 
							superblock_disk const *sbd = reinterpret_cast<superblock_disk const *>(&r.data());
 | 
				
			||||||
 | 
							superblock_traits::unpack(*sbd, sb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						} catch (checksum_error const &e) {
 | 
				
			||||||
 | 
							metadata_damage::ptr err(new super_block_corruption);
 | 
				
			||||||
 | 
							err->set_message("checksum error");
 | 
				
			||||||
 | 
							damage->push_back(err);
 | 
				
			||||||
 | 
							return damage;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return damage;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//----------------------------------------------------------------
 | 
				
			||||||
							
								
								
									
										24
									
								
								thin-provisioning/superblock_checker.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								thin-provisioning/superblock_checker.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					#ifndef THIN_SUPERBLOCK_CHECKER_H
 | 
				
			||||||
 | 
					#define THIN_SUPERBLOCK_CHECKER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "thin-provisioning/metadata_checker.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//----------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace thin_provisioning {
 | 
				
			||||||
 | 
						class superblock_checker : public checker {
 | 
				
			||||||
 | 
						public:
 | 
				
			||||||
 | 
							typedef persistent_data::block_manager<> block_manager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							superblock_checker(block_manager::ptr bm);
 | 
				
			||||||
 | 
							boost::shared_ptr<damage_list> check();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private:
 | 
				
			||||||
 | 
							block_manager::ptr bm_;
 | 
				
			||||||
 | 
							damage_list_ptr damage;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//----------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
@@ -49,6 +49,7 @@ TEST_SOURCE=\
 | 
				
			|||||||
	unit-tests/buffer_t.cc \
 | 
						unit-tests/buffer_t.cc \
 | 
				
			||||||
	unit-tests/cache_t.cc \
 | 
						unit-tests/cache_t.cc \
 | 
				
			||||||
	unit-tests/endian_t.cc \
 | 
						unit-tests/endian_t.cc \
 | 
				
			||||||
 | 
						unit-tests/metadata_checker_t.cc \
 | 
				
			||||||
	unit-tests/space_map_t.cc \
 | 
						unit-tests/space_map_t.cc \
 | 
				
			||||||
	unit-tests/span_iterator_t.cc \
 | 
						unit-tests/span_iterator_t.cc \
 | 
				
			||||||
	unit-tests/thin_metadata_t.cc \
 | 
						unit-tests/thin_metadata_t.cc \
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										158
									
								
								unit-tests/metadata_checker_t.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								unit-tests/metadata_checker_t.cc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,158 @@
 | 
				
			|||||||
 | 
					#include "gmock/gmock.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "test_utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "persistent-data/block.h"
 | 
				
			||||||
 | 
					#include "thin-provisioning/restore_emitter.h"
 | 
				
			||||||
 | 
					#include "thin-provisioning/superblock_checker.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using namespace persistent_data;
 | 
				
			||||||
 | 
					using namespace std;
 | 
				
			||||||
 | 
					using namespace test;
 | 
				
			||||||
 | 
					using namespace testing;
 | 
				
			||||||
 | 
					using namespace thin_provisioning;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//----------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace {
 | 
				
			||||||
 | 
						block_address const BLOCK_SIZE = 4096;
 | 
				
			||||||
 | 
						block_address const NR_BLOCKS = 10240;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// FIXME: move to utils
 | 
				
			||||||
 | 
						class with_directory {
 | 
				
			||||||
 | 
						public:
 | 
				
			||||||
 | 
							with_directory(std::string const &path)
 | 
				
			||||||
 | 
								: old_path_(pwd()) {
 | 
				
			||||||
 | 
								chdir(path);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							~with_directory() {
 | 
				
			||||||
 | 
								chdir(old_path_);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private:
 | 
				
			||||||
 | 
							std::string pwd() const {
 | 
				
			||||||
 | 
								char buffer[PATH_MAX];
 | 
				
			||||||
 | 
								char *ptr = getcwd(buffer, sizeof(buffer));
 | 
				
			||||||
 | 
								if (!ptr) {
 | 
				
			||||||
 | 
									// FIXME: still need a standard syscall failed exception
 | 
				
			||||||
 | 
									throw std::runtime_error("getcwd failed");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return ptr;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							void chdir(std::string const &path) {
 | 
				
			||||||
 | 
								int r = ::chdir(path.c_str());
 | 
				
			||||||
 | 
								if (r < 0)
 | 
				
			||||||
 | 
									throw std::runtime_error("chdir failed");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							std::string old_path_;
 | 
				
			||||||
 | 
							std::string new_path_;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						class with_temp_directory {
 | 
				
			||||||
 | 
						public:
 | 
				
			||||||
 | 
							with_temp_directory() {
 | 
				
			||||||
 | 
								std::string name("./tmp");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								rm_rf(name);
 | 
				
			||||||
 | 
								mkdir(name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								dir_.reset(new with_directory(name));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private:
 | 
				
			||||||
 | 
							void rm_rf(std::string const &name) {
 | 
				
			||||||
 | 
								std::string cmd("rm -rf ");
 | 
				
			||||||
 | 
								cmd += name;
 | 
				
			||||||
 | 
								system(cmd);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							void mkdir(std::string const &name) {
 | 
				
			||||||
 | 
								std::string cmd("mkdir ");
 | 
				
			||||||
 | 
								cmd += name;
 | 
				
			||||||
 | 
								system(cmd);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							void system(std::string const &cmd) {
 | 
				
			||||||
 | 
								int r = ::system(cmd.c_str());
 | 
				
			||||||
 | 
								if (r < 0)
 | 
				
			||||||
 | 
									throw std::runtime_error("system failed");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							std::auto_ptr<with_directory> dir_;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//--------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						class metadata_builder {
 | 
				
			||||||
 | 
						public:
 | 
				
			||||||
 | 
							metadata_builder(block_manager<>::ptr bm)
 | 
				
			||||||
 | 
								: bm_(bm) {
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							void build() {
 | 
				
			||||||
 | 
								metadata::ptr md(new metadata(bm_, metadata::CREATE, 128, 10240));
 | 
				
			||||||
 | 
								emitter::ptr restorer = create_restore_emitter(md);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								restorer->begin_superblock("test-generated", 0, 0, 128, 10240, boost::optional<uint64_t>());
 | 
				
			||||||
 | 
								restorer->end_superblock();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// FIXME: add methods to specify volumes with particular
 | 
				
			||||||
 | 
							// mapping patterns.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private:
 | 
				
			||||||
 | 
							block_manager<>::ptr bm_;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						class SuperBlockCheckerTests : public Test {
 | 
				
			||||||
 | 
						public:
 | 
				
			||||||
 | 
							SuperBlockCheckerTests()
 | 
				
			||||||
 | 
								: bm_(create_bm<BLOCK_SIZE>()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								metadata_builder builder(bm_);
 | 
				
			||||||
 | 
								builder.build();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							void corrupt_superblock() {
 | 
				
			||||||
 | 
								block_manager<>::write_ref wr = bm_->write_lock(0);
 | 
				
			||||||
 | 
								wr.data()[57] = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							with_temp_directory dir_;
 | 
				
			||||||
 | 
							block_manager<>::ptr bm_;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//----------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_F(SuperBlockCheckerTests, creation_requires_a_block_manager)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						superblock_checker sc(bm_);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_F(SuperBlockCheckerTests, passes_with_good_superblock)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						superblock_checker sc(bm_);
 | 
				
			||||||
 | 
						damage_list_ptr damage = sc.check();
 | 
				
			||||||
 | 
						ASSERT_THAT(damage->size(), Eq(0U));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_F(SuperBlockCheckerTests, fails_with_bad_checksum)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						corrupt_superblock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						superblock_checker sc(bm_);
 | 
				
			||||||
 | 
						damage_list_ptr damage = sc.check();
 | 
				
			||||||
 | 
						ASSERT_THAT(damage->size(), Eq(1u));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						metadata_damage::ptr d = *damage->begin();
 | 
				
			||||||
 | 
						ASSERT_THAT(dynamic_cast<super_block_corruption *>(d.get()), NotNull());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//----------------------------------------------------------------
 | 
				
			||||||
		Reference in New Issue
	
	Block a user