// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include #include #include "librbd/Features.h" #include "include/rbd/features.h" #include #include static const std::map RBD_FEATURE_MAP = { {RBD_FEATURE_NAME_LAYERING, RBD_FEATURE_LAYERING}, {RBD_FEATURE_NAME_STRIPINGV2, RBD_FEATURE_STRIPINGV2}, {RBD_FEATURE_NAME_EXCLUSIVE_LOCK, RBD_FEATURE_EXCLUSIVE_LOCK}, {RBD_FEATURE_NAME_OBJECT_MAP, RBD_FEATURE_OBJECT_MAP}, {RBD_FEATURE_NAME_FAST_DIFF, RBD_FEATURE_FAST_DIFF}, {RBD_FEATURE_NAME_DEEP_FLATTEN, RBD_FEATURE_DEEP_FLATTEN}, {RBD_FEATURE_NAME_JOURNALING, RBD_FEATURE_JOURNALING}, {RBD_FEATURE_NAME_DATA_POOL, RBD_FEATURE_DATA_POOL}, {RBD_FEATURE_NAME_OPERATIONS, RBD_FEATURE_OPERATIONS}, {RBD_FEATURE_NAME_MIGRATING, RBD_FEATURE_MIGRATING}, {RBD_FEATURE_NAME_NON_PRIMARY, RBD_FEATURE_NON_PRIMARY}, {RBD_FEATURE_NAME_DIRTY_CACHE, RBD_FEATURE_DIRTY_CACHE}, }; static_assert((RBD_FEATURE_DIRTY_CACHE << 1) > RBD_FEATURES_ALL, "new RBD feature added"); namespace librbd { std::string rbd_features_to_string(uint64_t features, std::ostream *err) { std::string r; for (auto& i : RBD_FEATURE_MAP) { if (features & i.second) { if (!r.empty()) { r += ","; } r += i.first; features &= ~i.second; } } if (err && features) { *err << "ignoring unknown feature mask 0x" << std::hex << features << std::dec; } return r; } uint64_t rbd_features_from_string(const std::string& orig_value, std::ostream *err) { uint64_t features = 0; std::string value = orig_value; boost::trim(value); // empty string means default features if (!value.size()) { return RBD_FEATURES_DEFAULT; } try { // numeric? features = boost::lexical_cast(value); // drop unrecognized bits uint64_t unsupported_features = (features & ~RBD_FEATURES_ALL); if (unsupported_features != 0ull) { features &= RBD_FEATURES_ALL; if (err) { *err << "ignoring unknown feature mask 0x" << std::hex << unsupported_features << std::dec; } } uint64_t ignore_features_mask = ( RBD_FEATURES_INTERNAL | RBD_FEATURES_MUTABLE_INTERNAL); uint64_t ignored_features = (features & ignore_features_mask); if (ignored_features != 0ULL) { features &= ~ignore_features_mask; if (err) { *err << "ignoring feature mask 0x" << std::hex << ignored_features; } } } catch (boost::bad_lexical_cast&) { // feature name list? bool errors = false; std::vector feature_names; boost::split(feature_names, value, boost::is_any_of(",")); for (auto feature_name: feature_names) { boost::trim(feature_name); auto feature_it = RBD_FEATURE_MAP.find(feature_name); if (feature_it != RBD_FEATURE_MAP.end()) { features += feature_it->second; } else if (err) { if (errors) { *err << ", "; } else { errors = true; } *err << "ignoring unknown feature " << feature_name; } } } return features; } } // namespace librbd