diff options
Diffstat (limited to 'src/librbd/Features.cc')
-rw-r--r-- | src/librbd/Features.cc | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/src/librbd/Features.cc b/src/librbd/Features.cc new file mode 100644 index 000000000..9da5b1dc4 --- /dev/null +++ b/src/librbd/Features.cc @@ -0,0 +1,111 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include <boost/lexical_cast.hpp> +#include <boost/algorithm/string.hpp> + +#include "librbd/Features.h" +#include "include/rbd/features.h" + +#include <map> +#include <vector> + +static const std::map<std::string, uint64_t> 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<uint64_t>(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<std::string> 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 |