diff --git a/src/mon/OSDMonitor.cc b/src/mon/OSDMonitor.cc index 16c281cc48b..b1c804d7da2 100644 --- a/src/mon/OSDMonitor.cc +++ b/src/mon/OSDMonitor.cc @@ -2996,7 +2996,7 @@ int OSDMonitor::check_cluster_features(uint64_t features, { stringstream unsupported_ss; int unsupported_count = 0; - if (!(mon->get_quorum_features() & features)) { + if ((mon->get_quorum_features() & features) != features) { unsupported_ss << "the monitor cluster"; ++unsupported_count; } @@ -3035,6 +3035,27 @@ int OSDMonitor::check_cluster_features(uint64_t features, return 0; } +bool OSDMonitor::validate_crush_against_features(const CrushWrapper *newcrush, + stringstream& ss) +{ + OSDMap::Incremental new_pending = pending_inc; + ::encode(*newcrush, new_pending.crush); + OSDMap newmap; + newmap.deepish_copy_from(osdmap); + newmap.apply_incremental(new_pending); + uint64_t features = newmap.get_features(CEPH_ENTITY_TYPE_MON, NULL); + + stringstream features_ss; + + int r = check_cluster_features(features, features_ss); + + if (!r) + return true; + + ss << "Could not change CRUSH: " << features_ss.str(); + return false; +} + bool OSDMonitor::erasure_code_profile_in_use(const map &pools, const string &profile, ostream &ss) @@ -3649,6 +3670,11 @@ bool OSDMonitor::prepare_command_impl(MMonCommand *m, goto reply; } + if (!validate_crush_against_features(&crush, ss)) { + err = -EINVAL; + goto reply; + } + // sanity check: test some inputs to make sure this map isn't totally broken dout(10) << " testing map" << dendl; stringstream ess; @@ -4066,6 +4092,12 @@ bool OSDMonitor::prepare_command_impl(MMonCommand *m, err = -EINVAL; goto reply; } + + if (!validate_crush_against_features(&newcrush, ss)) { + err = -EINVAL; + goto reply; + } + pending_inc.crush.clear(); newcrush.encode(pending_inc.crush); ss << "adjusted tunables profile to " << profile; diff --git a/src/mon/OSDMonitor.h b/src/mon/OSDMonitor.h index 80d083e8bd7..fbce5fecd18 100644 --- a/src/mon/OSDMonitor.h +++ b/src/mon/OSDMonitor.h @@ -186,6 +186,15 @@ private: void update_msgr_features(); int check_cluster_features(uint64_t features, stringstream &ss); + /** + * check if the cluster supports the features required by the + * given crush map. Outputs the daemons which don't support it + * to the stringstream. + * + * @returns true if the map is passable, false otherwise + */ + bool validate_crush_against_features(const CrushWrapper *newcrush, + stringstream &ss); void share_map_with_random_osd();