diff --git a/Makefile.in b/Makefile.in index e8398e9..6b83df4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -135,6 +135,7 @@ THIN_CHECK_SOURCE=\ persistent-data/space-maps/careful_alloc.cc \ persistent-data/transaction_manager.cc \ thin-provisioning/file_utils.cc \ + thin-provisioning/device_tree.cc \ thin-provisioning/metadata.cc \ thin-provisioning/metadata_checker.cc \ thin-provisioning/superblock.cc diff --git a/features/thin_check.feature b/features/thin_check.feature index ac6b455..526ec1a 100644 --- a/features/thin_check.feature +++ b/features/thin_check.feature @@ -49,6 +49,7 @@ Feature: thin_check When I run thin_check with --super-block-only Then it should pass + @announce Scenario: --super-block-only check fails with corrupt superblock Given a corrupt superblock When I run thin_check with --super-block-only diff --git a/thin-provisioning/metadata.cc b/thin-provisioning/metadata.cc index 08b0773..39f31e3 100644 --- a/thin-provisioning/metadata.cc +++ b/thin-provisioning/metadata.cc @@ -34,7 +34,7 @@ using namespace base; using namespace thin_provisioning; //---------------------------------------------------------------- - +#if 0 namespace { using namespace superblock_detail; @@ -227,3 +227,4 @@ metadata::commit() } //---------------------------------------------------------------- +#endif diff --git a/thin-provisioning/superblock.cc b/thin-provisioning/superblock.cc index 96cecac..c23fbc1 100644 --- a/thin-provisioning/superblock.cc +++ b/thin-provisioning/superblock.cc @@ -126,6 +126,17 @@ namespace thin_provisioning { } } + superblock_detail::superblock read_superblock(block_manager<>::ptr bm) + { + using namespace superblock_detail; + + superblock sb; + auto r = bm->read_lock(SUPERBLOCK_LOCATION, superblock_validator()); + superblock_disk const *sbd = reinterpret_cast(&r.data()); + superblock_traits::unpack(*sbd, sb); + return sb; + } + void check_superblock(block_manager<>::ptr bm, superblock_detail::damage_visitor &visitor) { diff --git a/thin-provisioning/superblock.h b/thin-provisioning/superblock.h index 19d8d79..6e47c26 100644 --- a/thin-provisioning/superblock.h +++ b/thin-provisioning/superblock.h @@ -122,6 +122,7 @@ namespace thin_provisioning { block_manager<>::validator::ptr superblock_validator(); + superblock_detail::superblock read_superblock(block_manager<>::ptr bm); void check_superblock(block_manager<>::ptr bm, superblock_detail::damage_visitor &visitor); } diff --git a/thin-provisioning/thin_check.cc b/thin-provisioning/thin_check.cc index 0f57237..0c59606 100644 --- a/thin-provisioning/thin_check.cc +++ b/thin-provisioning/thin_check.cc @@ -22,6 +22,7 @@ #include "version.h" +#include "persistent-data/space-maps/core.h" #include "thin-provisioning/device_tree.h" #include "thin-provisioning/file_utils.h" #include "thin-provisioning/mapping_tree.h" @@ -103,7 +104,6 @@ namespace { //-------------------------------- - enum error_state { NO_ERROR, NON_FATAL, // eg, lost blocks @@ -124,12 +124,25 @@ namespace { } } - block_manager<>::ptr open_bm(string const &path) { + //-------------------------------- + + block_manager<>::ptr + open_bm(string const &path) { block_address nr_blocks = get_nr_blocks(path); typename block_io<>::mode m = block_io<>::READ_ONLY; return block_manager<>::ptr(new block_manager<>(path, nr_blocks, 1, m)); } + transaction_manager::ptr + open_tm(block_manager<>::ptr bm) { + space_map::ptr sm(new core_map(bm->get_nr_blocks())); + sm->inc(superblock_detail::SUPERBLOCK_LOCATION); + transaction_manager::ptr tm(new transaction_manager(bm, sm)); + return tm; + } + + //-------------------------------- + class superblock_reporter : public superblock_detail::damage_visitor { public: superblock_reporter(nested_output &out) @@ -139,6 +152,10 @@ namespace { virtual void visit(superblock_detail::superblock_corruption const &d) { out_ << "superblock is corrupt" << end_message(); + { + auto _ = out_.push(); + out_ << d.desc_ << end_message(); + } err_ = combine_errors(err_, FATAL); } @@ -151,18 +168,64 @@ namespace { error_state err_; }; + //-------------------------------- + + class devices_reporter : public device_tree_detail::damage_visitor { + public: + devices_reporter(nested_output &out) + : out_(out), + err_(NO_ERROR) { + } + + virtual void visit(device_tree_detail::missing_devices const &d) { + out_ << "missing devices: " << d.keys_ << end_message(); + { + auto _ = out_.push(); + out_ << d.desc_ << end_message(); + } + + err_ = combine_errors(err_, FATAL); + } + + error_state get_error() const { + return err_; + } + + private: + nested_output &out_; + error_state err_; + }; + + //-------------------------------- + error_state metadata_check(string const &path) { block_manager<>::ptr bm = open_bm(path); nested_output out(cerr, 2); + superblock_reporter sb_rep(out); + devices_reporter dev_rep(out); + out << "examining superblock" << end_message(); { auto _ = out.push(); - superblock_reporter sb_rep(out); check_superblock(bm, sb_rep); - - return sb_rep.get_error(); } + + if (sb_rep.get_error() == FATAL) + return FATAL; + + out << "examining devices tree" << end_message(); + { + auto _ = out.push(); + superblock_detail::superblock sb = read_superblock(bm); + transaction_manager::ptr tm = open_tm(bm); + device_tree dtree(tm, sb.device_details_root_, + device_tree_detail::device_details_traits::ref_counter()); + check_device_tree(dtree, dev_rep); + } + + return combine_errors(sb_rep.get_error(), + dev_rep.get_error()); } int check(string const &path, bool quiet) {