From: Jason Dillaman Date: Wed, 14 Dec 2016 18:13:15 +0000 (-0500) Subject: librbd: keep rbd_default_features setting as bitmask X-Git-Tag: v11.1.1~36^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=8ddfb453263283d38cc082a165a708d4233b8ffc;p=ceph.git librbd: keep rbd_default_features setting as bitmask Support both human readable, comma delimited list of feature names and also integer bitmask value. Attempting to read the setting will always result in the feature bitmask integer value. This is required to avoid breaking backwards compatibility with librbd clients that are dependent on the older behavior (e.g. OpenStack). Fixes: http://tracker.ceph.com/issues/18247 Signed-off-by: Jason Dillaman --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 70cf75018c00..93963cf8bee4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -476,6 +476,7 @@ set(libcommon_files common/ceph_strings.cc common/ceph_frag.cc common/config.cc + common/config_validators.cc common/utf8.c common/mime.c common/strtol.cc diff --git a/src/common/config.cc b/src/common/config.cc index 9804965c63fa..7f39ed0c8b78 100644 --- a/src/common/config.cc +++ b/src/common/config.cc @@ -17,6 +17,7 @@ #include "common/ceph_argparse.h" #include "common/common_init.h" #include "common/config.h" +#include "common/config_validators.h" #include "common/static_assert.h" #include "common/strtol.h" #include "common/version.h" @@ -36,6 +37,7 @@ #include #include +#include #include #include #include @@ -87,6 +89,42 @@ int ceph_resolve_file_search(const std::string& filename_list, return ret; } +#define OPTION(name, type, def_val) +#define OPTION_VALIDATOR(name) \ +struct md_config_t::option_##name##_t { \ + typedef decltype(md_config_t::name) type; \ +}; +#define SAFE_OPTION(name, type, def_val) +#define SUBSYS(name, log, gather) +#define DEFAULT_SUBSYS(log, gather) +#include "common/config_opts.h" +#undef OPTION +#undef OPTION_VALIDATOR +#undef SAFE_OPTION +#undef SUBSYS +#undef DEFAULT_SUBSYS + +namespace { + +template +typename std::enable_if::value, + md_config_t::validator_t>::type create_validator() { + return md_config_t::validator_t(); +} + +template +typename std::enable_if::value, + md_config_t::validator_t>::type create_validator() { + // if T is defined (and not just forward declared), it implies + // that a validator function exists. use a dummy typed pointer to + // pick the correct validator function + return [](std::string *value, std::string *error_message) { + return ::validate(reinterpret_cast(0), value, error_message); + }; +} + +} // anonymous namespace + md_config_t::md_config_t() : cluster(""), @@ -101,6 +139,7 @@ md_config_t::md_config_t() #define OPTION_OPT_U64(name, def_val) name(((uint64_t)1) * def_val), #define OPTION_OPT_UUID(name, def_val) name(def_val), #define OPTION(name, type, def_val) OPTION_##type(name, def_val) +#define OPTION_VALIDATOR(name) #define SAFE_OPTION(name, type, def_val) OPTION(name, type, def_val) #define SUBSYS(name, log, gather) #define DEFAULT_SUBSYS(log, gather) @@ -116,6 +155,7 @@ md_config_t::md_config_t() #undef OPTION_OPT_U64 #undef OPTION_OPT_UUID #undef OPTION +#undef OPTION_VALIDATOR #undef SAFE_OPTION #undef SUBSYS #undef DEFAULT_SUBSYS @@ -123,13 +163,17 @@ md_config_t::md_config_t() { static const std::vector s_config_options = { #define OPTION4(name, type, def_val, safe) \ - config_option{ STRINGIFY(name), type, &md_config_t::name, safe }, + config_option{ STRINGIFY(name), type, &md_config_t::name, safe, \ + create_validator() }, #define OPTION(name, type, def_val) OPTION4(name, type, def_val, false) +#define OPTION_VALIDATOR(name) #define SAFE_OPTION(name, type, def_val) OPTION4(name, type, def_val, true) #define SUBSYS(name, log, gather) #define DEFAULT_SUBSYS(log, gather) #include "common/config_opts.h" +#undef OPTION4 #undef OPTION +#undef OPTION_VALIDATOR #undef SAFE_OPTION #undef SUBSYS #undef DEFAULT_SUBSYS @@ -138,6 +182,7 @@ md_config_t::md_config_t() s_tbl(new std::vector(std::move(s_config_options))); config_options = s_tbl; + validate_default_settings(); init_subsys(); } @@ -148,9 +193,11 @@ void md_config_t::init_subsys() #define DEFAULT_SUBSYS(log, gather) \ subsys.add(ceph_subsys_, "none", log, gather); #define OPTION(a, b, c) +#define OPTION_VALIDATOR(a) #define SAFE_OPTION(a, b, c) #include "common/config_opts.h" #undef OPTION +#undef OPTION_VALIDATOR #undef SAFE_OPTION #undef SUBSYS #undef DEFAULT_SUBSYS @@ -282,10 +329,19 @@ int md_config_t::parse_config_files_impl(const std::list &conf_file std::string val; int ret = _get_val_from_conf_file(my_sections, opt.name, val, false); if (ret == 0) { - set_val_impl(val.c_str(), &opt); + std::string error_message; + int r = set_val_impl(val, &opt, &error_message); + if (warnings != nullptr && (r != 0 || !error_message.empty())) { + *warnings << "parse error setting '" << opt.name << "' to '" << val + << "'"; + if (!error_message.empty()) { + *warnings << " (" << error_message << ")"; + } + *warnings << std::endl; + } } } - + // subsystems? for (int o = 0; o < subsys.get_num(); o++) { std::string as_option("debug_"); @@ -515,20 +571,23 @@ int md_config_t::parse_option(std::vector& args, return ret; } + const char *option_name = nullptr; + std::string error_message; o = 0; for (auto& opt_ref: *config_options) { ostringstream err; config_option const *opt = &opt_ref; std::string as_option("--"); as_option += opt->name; + option_name = opt->name; if (opt->type == OPT_BOOL) { int res; if (ceph_argparse_binary_flag(args, i, &res, oss, as_option.c_str(), (char*)NULL)) { if (res == 0) - set_val_impl("false", opt); + ret = set_val_impl("false", opt, &error_message); else if (res == 1) - set_val_impl("true", opt); + ret = set_val_impl("true", opt, &error_message); else ret = res; break; @@ -536,40 +595,46 @@ int md_config_t::parse_option(std::vector& args, std::string no("--no-"); no += opt->name; if (ceph_argparse_flag(args, i, no.c_str(), (char*)NULL)) { - set_val_impl("false", opt); + ret = set_val_impl("false", opt, &error_message); break; } } - } - else if (ceph_argparse_witharg(args, i, &val, err, - as_option.c_str(), (char*)NULL)) { + } else if (ceph_argparse_witharg(args, i, &val, err, + as_option.c_str(), (char*)NULL)) { if (!err.str().empty()) { - *oss << err.str(); + error_message = err.str(); ret = -EINVAL; break; } if (oss && ((!opt->is_safe()) && (observers.find(opt->name) == observers.end()))) { *oss << "You cannot change " << opt->name << " using injectargs.\n"; - ret = -ENOSYS; - break; - } - int res = set_val_impl(val.c_str(), opt); - if (res) { - if (oss) { - *oss << "Parse error setting " << opt->name << " to '" - << val << "' using injectargs.\n"; - ret = res; - break; - } else { - cerr << "parse error setting '" << opt->name << "' to '" - << val << "'\n" << std::endl; - } + return -ENOSYS; } + ret = set_val_impl(val, opt, &error_message); break; } ++o; } + + if (ret != 0 || !error_message.empty()) { + if (oss) { + *oss << "Parse error setting " << option_name << " to '" + << val << "' using injectargs"; + if (!error_message.empty()) { + *oss << " (" << error_message << ")"; + } + *oss << ".\n"; + } else { + cerr << "parse error setting '" << option_name << "' to '" + << val << "'"; + if (!error_message.empty()) { + cerr << " (" << error_message << ")"; + } + cerr << "\n" << std::endl; + } + } + if (o == (int)config_options->size()) { // ignore ++i; @@ -796,7 +861,10 @@ int md_config_t::set_val(const char *key, const char *val, bool meta, bool safe) return -ENOSYS; } } - return set_val_impl(v.c_str(), opt); + + std::string error_message; + int r = set_val_impl(v, opt, &error_message); + return r; } // couldn't find a configuration option with key 'key' @@ -843,6 +911,24 @@ md_config_t::config_value_t md_config_t::_get_val(const char *key) const return boost::apply_visitor(gvv, opt->md_member_ptr); } +int md_config_t::_get_val(const char *key, std::string *value) const { + assert(lock.is_locked()); + + std::string normalized_key(ConfFile::normalize_key_name(key)); + config_value_t config_value = _get_val(normalized_key.c_str()); + if (!boost::get(&config_value)) { + ostringstream oss; + if (bool *flag = boost::get(&config_value)) { + oss << (*flag ? "true" : "false"); + } else { + oss << config_value; + } + *value = oss.str(); + return 0; + } + return -ENOENT; +} + int md_config_t::_get_val(const char *key, char **buf, int len) const { assert(lock.is_locked()); @@ -964,10 +1050,19 @@ int md_config_t::_get_val_from_conf_file(const std::vector §io return -ENOENT; } -int md_config_t::set_val_impl(const char *val, config_option const *opt) +int md_config_t::set_val_impl(const std::string &val, config_option const *opt, + std::string *error_message) { assert(lock.is_locked()); - int ret = set_val_raw(val, opt); + std::string value(val); + if (opt->validator) { + int r = opt->validator(&value, error_message); + if (r < 0) { + return r; + } + } + + int ret = set_val_raw(value.c_str(), opt); if (ret) return ret; changed.insert(opt->name); @@ -1271,3 +1366,19 @@ void md_config_t::complain_about_parse_errors(CephContext *cct) { ::complain_about_parse_errors(cct, &parse_errors); } + +void md_config_t::validate_default_settings() { + Mutex::Locker l(lock); + for (auto &opt : *config_options) { + // normalize config defaults using their validator + if (opt.validator) { + std::string value; + int r = _get_val(opt.name, &value); + assert(r == 0); + + std::string error_message; + r = set_val_impl(value.c_str(), &opt, &error_message); + assert(r == 0); + } + } +} diff --git a/src/common/config.h b/src/common/config.h index f0ca7ad52ac4..27ec66d227a5 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -16,6 +16,7 @@ #define CEPH_CONFIG_H #include +#include #include #include #include @@ -113,12 +114,15 @@ public: OPT_ADDR, OPT_U32, OPT_U64, OPT_UUID } opt_type_t; + typedef std::function validator_t; + class config_option { public: const char *name; opt_type_t type; md_config_t::member_ptr_t md_member_ptr; bool safe; // promise to access it only via md_config_t::get_val + validator_t validator; private: template struct get_typed_pointer_visitor : public boost::static_visitor { md_config_t const *conf; @@ -241,6 +245,9 @@ public: void complain_about_parse_errors(CephContext *cct); private: + void validate_default_settings(); + + int _get_val(const char *key, std::string *value) const; config_value_t _get_val(const char *key) const; void _show_config(std::ostream *out, Formatter *f); @@ -257,7 +264,8 @@ private: int parse_config_files_impl(const std::list &conf_files, std::ostream *warnings); - int set_val_impl(const char *val, config_option const *opt); + int set_val_impl(const std::string &val, config_option const *opt, + std::string *error_message); int set_val_raw(const char *val, config_option const *opt); void init_subsys(); @@ -308,12 +316,15 @@ public: #define OPTION_OPT_U64(name) const uint64_t name; #define OPTION_OPT_UUID(name) const uuid_d name; #define OPTION(name, ty, init) \ - public: \ - OPTION_##ty(name) + public: \ + OPTION_##ty(name) \ + struct option_##name##_t; +#define OPTION_VALIDATOR(name) #define SAFE_OPTION(name, ty, init) \ - protected: \ - OPTION_##ty(name) \ - public: + protected: \ + OPTION_##ty(name) \ + public: \ + struct option_##name##_t; #define SUBSYS(name, log, gather) #define DEFAULT_SUBSYS(log, gather) #include "common/config_opts.h" @@ -328,6 +339,7 @@ public: #undef OPTION_OPT_U64 #undef OPTION_OPT_UUID #undef OPTION +#undef OPTION_VALIDATOR #undef SAFE_OPTION #undef SUBSYS #undef DEFAULT_SUBSYS @@ -385,6 +397,7 @@ typedef md_config_t::config_option config_option; enum config_subsys_id { ceph_subsys_, // default #define OPTION(a,b,c) +#define OPTION_VALIDATOR(name) #define SAFE_OPTION(a,b,c) #define SUBSYS(name, log, gather) \ ceph_subsys_##name, @@ -392,6 +405,7 @@ enum config_subsys_id { #include "common/config_opts.h" #undef SUBSYS #undef OPTION +#undef OPTION_VALIDATOR #undef SAFE_OPTION #undef DEFAULT_SUBSYS ceph_subsys_max diff --git a/src/common/config_opts.h b/src/common/config_opts.h index 9479e07a96d8..5ce5f7ff95c8 100644 --- a/src/common/config_opts.h +++ b/src/common/config_opts.h @@ -1299,9 +1299,26 @@ OPTION(rbd_default_format, OPT_INT, 2) OPTION(rbd_default_order, OPT_INT, 22) OPTION(rbd_default_stripe_count, OPT_U64, 0) // changing requires stripingv2 feature OPTION(rbd_default_stripe_unit, OPT_U64, 0) // changing to non-object size requires stripingv2 feature -SAFE_OPTION(rbd_default_features, OPT_STR, "layering,exclusive-lock,object-map,fast-diff,deep-flatten") // only applies to format 2 images OPTION(rbd_default_data_pool, OPT_STR, "") // optional default pool for storing image data blocks +/** + * RBD features are only applicable for v2 images. This setting accepts either + * an integer bitmask value or comma-delimited string of RBD feature names. + * This setting is always internally stored as an integer bitmask value. The + * mapping between feature bitmask value and feature name is as follows: + * + * +1 -> layering + * +2 -> striping + * +4 -> exclusive-lock + * +8 -> object-map + * +16 -> fast-diff + * +32 -> deep-flatten + * +64 -> journaling + * +128 -> data-pool + */ +SAFE_OPTION(rbd_default_features, OPT_STR, "layering,exclusive-lock,object-map,fast-diff,deep-flatten") +OPTION_VALIDATOR(rbd_default_features) + OPTION(rbd_default_map_options, OPT_STR, "") // default rbd map -o / --options /** diff --git a/src/common/config_validators.cc b/src/common/config_validators.cc new file mode 100644 index 000000000000..0f224f94b8db --- /dev/null +++ b/src/common/config_validators.cc @@ -0,0 +1,70 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "common/config_validators.h" +#include "include/stringify.h" +#include "include/rbd/features.h" +#include +#include +#include +#include +#include + +int validate(md_config_t::option_rbd_default_features_t *, + std::string *value, std::string *error_message) { + static const std::map 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}, + }; + static_assert((RBD_FEATURE_DATA_POOL << 1) > RBD_FEATURES_ALL, + "new RBD feature added"); + + // convert user-friendly comma delimited feature name list to a bitmask + // that is used by the librbd API + uint64_t features = 0; + error_message->clear(); + + try { + features = boost::lexical_cast(*value); + + uint64_t unsupported_features = (features & ~RBD_FEATURES_ALL); + if (unsupported_features != 0ull) { + features &= RBD_FEATURES_ALL; + + std::stringstream ss; + ss << "ignoring unknown feature mask 0x" + << std::hex << unsupported_features; + *error_message = ss.str(); + } + } catch (const boost::bad_lexical_cast& ) { + int r = 0; + 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 = FEATURE_MAP.find(feature_name); + if (feature_it != FEATURE_MAP.end()) { + features += feature_it->second; + } else { + if (!error_message->empty()) { + *error_message += ", "; + } + *error_message += "ignoring unknown feature " + feature_name; + r = -EINVAL; + } + } + + if (features == 0 && r == -EINVAL) { + features = RBD_FEATURES_DEFAULT; + } + } + *value = stringify(features); + return 0; +} + diff --git a/src/common/config_validators.h b/src/common/config_validators.h new file mode 100644 index 000000000000..22cf6f0866c1 --- /dev/null +++ b/src/common/config_validators.h @@ -0,0 +1,17 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#ifndef CEPH_CONFIG_VALIDATORS +#define CEPH_CONFIG_VALIDATORS + +#include "config.h" +#include + +/** + * Global config value validators for the Ceph project + */ + +int validate(md_config_t::option_rbd_default_features_t *type, + std::string *value, std::string *error_message); + +#endif // CEPH_CONFIG_VALIDATORS diff --git a/src/librbd/Utils.cc b/src/librbd/Utils.cc index a7a225939a61..1dff4ce4b8f1 100644 --- a/src/librbd/Utils.cc +++ b/src/librbd/Utils.cc @@ -64,38 +64,10 @@ std::string generate_image_id(librados::IoCtx &ioctx) { return id; } -uint64_t parse_rbd_default_features(CephContext* cct) +uint64_t get_rbd_default_features(CephContext* cct) { - int ret = 0; - uint64_t value = 0; auto str_val = cct->_conf->get_val("rbd_default_features"); - try { - value = boost::lexical_cast(str_val); - } catch (const boost::bad_lexical_cast& ) { - map conf_vals = {{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}, - }; - std::vector strs; - boost::split(strs, str_val, boost::is_any_of(",")); - for (auto feature: strs) { - boost::trim(feature); - if (conf_vals.find(feature) != conf_vals.end()) { - value += conf_vals[feature]; - } else { - ret = -EINVAL; - lderr(cct) << "ignoring unknown feature " << feature << dendl; - } - } - if (value == 0 && ret == -EINVAL) - value = RBD_FEATURES_DEFAULT; - } - return value; + return boost::lexical_cast(str_val); } } // namespace util diff --git a/src/librbd/Utils.h b/src/librbd/Utils.h index 09c2974f0168..d03da840726d 100644 --- a/src/librbd/Utils.h +++ b/src/librbd/Utils.h @@ -197,7 +197,7 @@ private: Context *m_on_finish = nullptr; }; -uint64_t parse_rbd_default_features(CephContext* cct); +uint64_t get_rbd_default_features(CephContext* cct); } // namespace util diff --git a/src/librbd/image/CreateRequest.cc b/src/librbd/image/CreateRequest.cc index a9e6fee5d6d0..f71642ddc8bd 100644 --- a/src/librbd/image/CreateRequest.cc +++ b/src/librbd/image/CreateRequest.cc @@ -135,7 +135,7 @@ CreateRequest::CreateRequest(IoCtx &ioctx, const std::string &image_name, m_objmap_name = ObjectMap<>::object_map_name(m_image_id, CEPH_NOSNAP); if (image_options.get(RBD_IMAGE_OPTION_FEATURES, &m_features) != 0) { - m_features = util::parse_rbd_default_features(m_cct); + m_features = util::get_rbd_default_features(m_cct); m_negotiate_features = true; } diff --git a/src/test/librbd/test_librbd.cc b/src/test/librbd/test_librbd.cc index 2e67032a122f..cab773505edb 100644 --- a/src/test/librbd/test_librbd.cc +++ b/src/test/librbd/test_librbd.cc @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -5046,3 +5047,26 @@ TEST_F(TestLibRBD, DiscardAfterWrite) read_comp->release(); } +TEST_F(TestLibRBD, DefaultFeatures) { + std::string orig_default_features; + ASSERT_EQ(0, _rados.conf_get("rbd_default_features", orig_default_features)); + BOOST_SCOPE_EXIT_ALL(orig_default_features) { + ASSERT_EQ(0, _rados.conf_set("rbd_default_features", + orig_default_features.c_str())); + }; + + std::list > feature_names_to_bitmask = { + {"", orig_default_features}, + {"layering", "1"}, + {"layering, exclusive-lock", "5"}, + {"exclusive-lock,journaling", "68"}, + {"125", "125"} + }; + + for (auto &pair : feature_names_to_bitmask) { + ASSERT_EQ(0, _rados.conf_set("rbd_default_features", pair.first.c_str())); + std::string features; + ASSERT_EQ(0, _rados.conf_get("rbd_default_features", features)); + ASSERT_EQ(pair.second, features); + } +} diff --git a/src/test/rbd_mirror/test_ImageReplayer.cc b/src/test/rbd_mirror/test_ImageReplayer.cc index 535f36cef948..b2e5b16dc266 100644 --- a/src/test/rbd_mirror/test_ImageReplayer.cc +++ b/src/test/rbd_mirror/test_ImageReplayer.cc @@ -101,7 +101,7 @@ public: m_remote_ioctx)); m_image_name = get_temp_image_name(); - uint64_t features = librbd::util::parse_rbd_default_features(g_ceph_context); + uint64_t features = librbd::util::get_rbd_default_features(g_ceph_context); features |= RBD_FEATURE_EXCLUSIVE_LOCK | RBD_FEATURE_JOURNALING; int order = 0; EXPECT_EQ(0, librbd::create(m_remote_ioctx, m_image_name.c_str(), 1 << 22, diff --git a/src/test/rbd_mirror/test_PoolWatcher.cc b/src/test/rbd_mirror/test_PoolWatcher.cc index f2ae6090e3ea..800d0bbc0f11 100644 --- a/src/test/rbd_mirror/test_PoolWatcher.cc +++ b/src/test/rbd_mirror/test_PoolWatcher.cc @@ -86,7 +86,7 @@ TestPoolWatcher() : m_lock("TestPoolWatcherLock"), void create_image(const string &pool_name, bool mirrored=true, string *image_name=nullptr) { - uint64_t features = librbd::util::parse_rbd_default_features(g_ceph_context); + uint64_t features = librbd::util::get_rbd_default_features(g_ceph_context); string name = "image" + stringify(++m_image_number); if (mirrored) { features |= RBD_FEATURE_EXCLUSIVE_LOCK | RBD_FEATURE_JOURNALING; @@ -135,7 +135,7 @@ TestPoolWatcher() : m_lock("TestPoolWatcherLock"), ictx->state->close(); } - uint64_t features = librbd::util::parse_rbd_default_features(g_ceph_context); + uint64_t features = librbd::util::get_rbd_default_features(g_ceph_context); string name = "clone" + stringify(++m_image_number); if (mirrored) { features |= RBD_FEATURE_EXCLUSIVE_LOCK | RBD_FEATURE_JOURNALING; diff --git a/src/tools/rbd/ArgumentTypes.cc b/src/tools/rbd/ArgumentTypes.cc index 62b681483824..7f19961a255d 100644 --- a/src/tools/rbd/ArgumentTypes.cc +++ b/src/tools/rbd/ArgumentTypes.cc @@ -343,7 +343,7 @@ std::string get_short_features_help(bool append_suffix) { std::string suffix; if (append_suffix) { - if ((pair.first & rbd::utils::parse_rbd_default_features(g_ceph_context)) != 0) { + if ((pair.first & rbd::utils::get_rbd_default_features(g_ceph_context)) != 0) { suffix += "+"; } if ((pair.first & RBD_FEATURES_MUTABLE) != 0) { diff --git a/src/tools/rbd/Utils.cc b/src/tools/rbd/Utils.cc index 4fd0ca79323f..7221a6d5ed60 100644 --- a/src/tools/rbd/Utils.cc +++ b/src/tools/rbd/Utils.cc @@ -543,7 +543,7 @@ int get_image_options(const boost::program_options::variables_map &vm, features = vm[at::IMAGE_FEATURES].as(); features_specified = true; } else { - features = parse_rbd_default_features(g_ceph_context); + features = get_rbd_default_features(g_ceph_context); } if (vm.count(at::IMAGE_STRIPE_UNIT)) { @@ -874,40 +874,9 @@ std::string timestr(time_t t) { return buf; } -// FIXME (asheplyakov): use function from librbd/Utils.cc - -uint64_t parse_rbd_default_features(CephContext* cct) -{ - int ret = 0; - uint64_t value = 0; +uint64_t get_rbd_default_features(CephContext* cct) { auto features = cct->_conf->get_val("rbd_default_features"); - try { - value = boost::lexical_cast(features); - } catch (const boost::bad_lexical_cast& ) { - map conf_vals = {{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}, - }; - std::vector strs; - boost::split(strs, features, boost::is_any_of(",")); - for (auto feature: strs) { - boost::trim(feature); - if (conf_vals.find(feature) != conf_vals.end()) { - value += conf_vals[feature]; - } else { - ret = -EINVAL; - std::cerr << "Warning: unknown rbd feature " << feature << std::endl; - } - } - if (value == 0 && ret == -EINVAL) - value = RBD_FEATURES_DEFAULT; - } - return value; + return boost::lexical_cast(features); } } // namespace utils diff --git a/src/tools/rbd/Utils.h b/src/tools/rbd/Utils.h index 7b426132b5ca..aa75e06cddc5 100644 --- a/src/tools/rbd/Utils.h +++ b/src/tools/rbd/Utils.h @@ -135,7 +135,7 @@ std::string mirror_image_status_state(librbd::mirror_image_status_t status); std::string timestr(time_t t); // duplicate here to not include librbd_internal lib -uint64_t parse_rbd_default_features(CephContext* cct); +uint64_t get_rbd_default_features(CephContext* cct); } // namespace utils } // namespace rbd