diff --git a/src/crush/CrushTester.cc b/src/crush/CrushTester.cc index 5ca4978c4c5c5..85ba693aa4bf4 100644 --- a/src/crush/CrushTester.cc +++ b/src/crush/CrushTester.cc @@ -1,6 +1,7 @@ #include "include/stringify.h" #include "CrushTester.h" +#include "CrushTreeDumper.h" #include #include @@ -433,6 +434,54 @@ int CrushTester::test_with_crushtool(const string& crushtool, return -r; } +namespace { + class BadCrushMap : public std::runtime_error { + public: + int item; + BadCrushMap(const char* msg, int id) + : std::runtime_error(msg), item(id) {} + }; + // throws if any node in the crush fail to print + class CrushWalker : public CrushTreeDumper::Dumper { + typedef void DumbFormatter; + typedef CrushTreeDumper::Dumper Parent; + public: + CrushWalker(const CrushWrapper *crush) + : Parent(crush) {} + void dump_item(const CrushTreeDumper::Item &qi, DumbFormatter *) { + int type = -1; + if (qi.is_bucket()) { + if (!crush->get_item_name(qi.id)) { + throw BadCrushMap("unknown item name", qi.id); + } + type = crush->get_bucket_type(qi.id); + } else { + type = 0; + } + if (!crush->get_type_name(type)) { + throw BadCrushMap("unknown type name", qi.id); + } + } + }; +} + +bool CrushTester::check_name_maps() const +{ + CrushWalker crush_walker(&crush); + try { + // walk through the crush, to see if its self-contained + crush_walker.dump(NULL); + // and see if the maps is also able to handle straying OSDs, whose id >= 0. + // "ceph osd tree" will try to print them, even they are not listed in the + // crush map. + crush_walker.dump_item(CrushTreeDumper::Item(0, 0, 0), NULL); + } catch (const BadCrushMap& e) { + err << e.what() << ": item#" << e.item << std::endl; + return false; + } + return true; +} + int CrushTester::test() { if (min_rule < 0 || max_rule < 0) { diff --git a/src/crush/CrushTester.h b/src/crush/CrushTester.h index 09936ce459e39..cc7c7825d1421 100644 --- a/src/crush/CrushTester.h +++ b/src/crush/CrushTester.h @@ -333,6 +333,11 @@ class CrushTester { min_rule = max_rule = rule; } + /** + * check if any bucket/nodes is referencing an unknown name or type + * @return false if an dangling name/type is referenced, true otherwise + */ + bool check_name_maps() const; int test(); int test_with_crushtool(const string& crushtool, int timeout);