From ad5aa13c2b0c3124cace770140040ac558e8b53c Mon Sep 17 00:00:00 2001 From: Loic Dachary Date: Thu, 16 Jul 2015 18:02:02 +0200 Subject: [PATCH] mon: test the crush ruleset when creating a pool We want to fix the following scenario: * an erasure code plugin (or another part of the code) creates a ruleset * the ruleset crashes during mapping (for whatever reason) * ceph osd pool create uses the bugous ruleset * the monitors try to do mapping a crash Having a bugous ruleset in the crush map is very difficult prevent. The catastrophic event of using it with a newly created pool can however be prevented by calling the CrushTester just before creating the pool and after all implicit or explicit crush ruleset creation happened. http://tracker.ceph.com/issues/11814 Fixes: #11814 Signed-off-by: Loic Dachary (cherry picked from commit f1e86be589803596e86acc964ac5c5c03b4038d8) Conflicts: src/test/mon/osd-crush.sh removed the run_mon because in hammer it is shared between all tests src/mon/OSDMonitor.cc prepare_new_pool changed stringstream to *ostream (cherry picked from commit f47ba4b1a1029a55f8bc4ab393a7fa3712cd4e00) --- src/mon/OSDMonitor.cc | 9 +++++++++ src/test/mon/osd-crush.sh | 12 ++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/mon/OSDMonitor.cc b/src/mon/OSDMonitor.cc index 730702e7ca83b..fe3a0851caadd 100644 --- a/src/mon/OSDMonitor.cc +++ b/src/mon/OSDMonitor.cc @@ -3874,6 +3874,7 @@ int OSDMonitor::prepare_pool_crush_ruleset(const unsigned pool_type, int *crush_ruleset, stringstream &ss) { + if (*crush_ruleset < 0) { switch (pool_type) { case pg_pool_t::TYPE_REPLICATED: @@ -3985,6 +3986,14 @@ int OSDMonitor::prepare_new_pool(string& name, uint64_t auid, crush_ruleset_name, &crush_ruleset, ss); if (r) return r; + CrushWrapper newcrush; + _get_pending_crush(newcrush); + CrushTester tester(newcrush, ss); + r = tester.test_with_crushtool(g_conf->crushtool.c_str(), + osdmap.get_max_osd(), + g_conf->mon_lease); + if (r) + return r; unsigned size, min_size; r = prepare_pool_size(pool_type, erasure_code_profile, &size, &min_size, ss); if (r) diff --git a/src/test/mon/osd-crush.sh b/src/test/mon/osd-crush.sh index 2242e9c957ce3..db607f106c82c 100755 --- a/src/test/mon/osd-crush.sh +++ b/src/test/mon/osd-crush.sh @@ -78,6 +78,9 @@ function TEST_crush_rule_rm() { function TEST_crush_rule_create_erasure() { local dir=$1 + # should have at least one OSD + run_osd $dir 0 || return 1 + local ruleset=ruleset3 # # create a new ruleset with the default profile, implicitly @@ -108,6 +111,15 @@ function TEST_crush_rule_create_erasure() { ./ceph osd erasure-code-profile ls | grep default || return 1 ./ceph osd crush rule rm $ruleset || return 1 ! ./ceph osd crush rule ls | grep $ruleset || return 1 + # + # create a bugous ruleset and verify it cannot be used + # to create a pool. + # + ceph osd erasure-code-profile set myprofile plugin=lrc mapping=__DD__DD layers='[[ "_cDD_cDD", "" ],[ "cDDD____", "" ],[ "____cDDD", "" ],]' ruleset-steps='[ [ "choose", "datacenter", 3 ], [ "chooseleaf", "osd", 0] ]' + expect_failure $dir "Error EINVAL" \ + ./ceph osd pool create mypool 1 1 erasure myprofile || return 1 + ./ceph osd crush rule rm mypool || return 1 + ./ceph osd erasure-code-profile rm myprofile || return 1 } function check_ruleset_id_match_rule_id() { -- 2.39.5