mirror of
https://github.com/ceph/ceph
synced 2025-01-06 11:12:18 +00:00
common/options,librbd/Utils: refactor RBD feature validation
Move conversion of RBD features to/from string/uint64_t to helpers, and use those from the option validator. Keep the resulting features in integer form to avoid breaking Cinder. Meh. Change behavior from prior version: - fail to parse if any of the specified features is invalid (previously we would parse the ones we understood and ignore the others). Signed-off-by: Sage Weil <sage@redhat.com>
This commit is contained in:
parent
c2d28e2750
commit
fa2faeefd8
@ -536,6 +536,7 @@ set(libcommon_files
|
|||||||
common/dns_resolve.cc
|
common/dns_resolve.cc
|
||||||
common/hostname.cc
|
common/hostname.cc
|
||||||
common/util.cc
|
common/util.cc
|
||||||
|
librbd/Features.cc
|
||||||
arch/probe.cc
|
arch/probe.cc
|
||||||
${auth_files}
|
${auth_files}
|
||||||
${mds_files})
|
${mds_files})
|
||||||
|
@ -14,6 +14,9 @@
|
|||||||
// Definitions for enums
|
// Definitions for enums
|
||||||
#include "common/perf_counters.h"
|
#include "common/perf_counters.h"
|
||||||
|
|
||||||
|
// rbd feature validation
|
||||||
|
#include "librbd/Features.h"
|
||||||
|
|
||||||
|
|
||||||
void Option::dump_value(const char *field_name,
|
void Option::dump_value(const char *field_name,
|
||||||
const Option::value_t &v, Formatter *f) const
|
const Option::value_t &v, Formatter *f) const
|
||||||
@ -5817,71 +5820,17 @@ static std::vector<Option> get_rbd_options() {
|
|||||||
"+4 -> exclusive-lock, +8 -> object-map, +16 -> fast-diff, "
|
"+4 -> exclusive-lock, +8 -> object-map, +16 -> fast-diff, "
|
||||||
"+32 -> deep-flatten, +64 -> journaling, +128 -> data-pool")
|
"+32 -> deep-flatten, +64 -> journaling, +128 -> data-pool")
|
||||||
.set_safe()
|
.set_safe()
|
||||||
.set_validator([](std::string *value, std::string *error_message){
|
.set_validator([](std::string *value, std::string *error_message) {
|
||||||
static const std::map<std::string, uint64_t> FEATURE_MAP = {
|
ostringstream ss;
|
||||||
{RBD_FEATURE_NAME_LAYERING, RBD_FEATURE_LAYERING},
|
uint64_t features = librbd::rbd_features_from_string(*value, &ss);
|
||||||
{RBD_FEATURE_NAME_STRIPINGV2, RBD_FEATURE_STRIPINGV2},
|
// Leave this in integer form to avoid breaking Cinder. Someday
|
||||||
{RBD_FEATURE_NAME_EXCLUSIVE_LOCK, RBD_FEATURE_EXCLUSIVE_LOCK},
|
// we would like to present this in string form instead...
|
||||||
{RBD_FEATURE_NAME_OBJECT_MAP, RBD_FEATURE_OBJECT_MAP},
|
*value = stringify(features);
|
||||||
{RBD_FEATURE_NAME_FAST_DIFF, RBD_FEATURE_FAST_DIFF},
|
if (ss.str().size()) {
|
||||||
{RBD_FEATURE_NAME_DEEP_FLATTEN, RBD_FEATURE_DEEP_FLATTEN},
|
return -EINVAL;
|
||||||
{RBD_FEATURE_NAME_JOURNALING, RBD_FEATURE_JOURNALING},
|
}
|
||||||
{RBD_FEATURE_NAME_DATA_POOL, RBD_FEATURE_DATA_POOL},
|
return 0;
|
||||||
};
|
}),
|
||||||
static_assert((RBD_FEATURE_OPERATIONS << 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<decltype(features)>(*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();
|
|
||||||
}
|
|
||||||
uint64_t internal_features = (features & RBD_FEATURES_INTERNAL);
|
|
||||||
if (internal_features != 0ULL) {
|
|
||||||
features &= ~RBD_FEATURES_INTERNAL;
|
|
||||||
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << "ignoring internal feature mask 0x"
|
|
||||||
<< std::hex << internal_features;
|
|
||||||
*error_message = ss.str();
|
|
||||||
}
|
|
||||||
} catch (const boost::bad_lexical_cast& ) {
|
|
||||||
int r = 0;
|
|
||||||
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 = 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;
|
|
||||||
}),
|
|
||||||
|
|
||||||
Option("rbd_op_threads", Option::TYPE_INT, Option::LEVEL_ADVANCED)
|
Option("rbd_op_threads", Option::TYPE_INT, Option::LEVEL_ADVANCED)
|
||||||
.set_default(1)
|
.set_default(1)
|
||||||
|
105
src/librbd/Features.cc
Normal file
105
src/librbd/Features.cc
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
// -*- 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},
|
||||||
|
};
|
||||||
|
static_assert((RBD_FEATURE_OPERATIONS << 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 internal_features = (features & RBD_FEATURES_INTERNAL);
|
||||||
|
if (internal_features != 0ULL) {
|
||||||
|
features &= ~RBD_FEATURES_INTERNAL;
|
||||||
|
if (err) {
|
||||||
|
*err << "ignoring internal feature mask 0x"
|
||||||
|
<< std::hex << internal_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
|
16
src/librbd/Features.h
Normal file
16
src/librbd/Features.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
|
||||||
|
// vim: ts=8 sw=2 smarttab
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
namespace librbd {
|
||||||
|
|
||||||
|
std::string rbd_features_to_string(uint64_t features,
|
||||||
|
std::ostream *err);
|
||||||
|
uint64_t rbd_features_from_string(const std::string& value,
|
||||||
|
std::ostream *err);
|
||||||
|
|
||||||
|
} // librbd
|
@ -10,6 +10,7 @@
|
|||||||
#include "include/rbd/features.h"
|
#include "include/rbd/features.h"
|
||||||
#include "common/dout.h"
|
#include "common/dout.h"
|
||||||
#include "librbd/ImageCtx.h"
|
#include "librbd/ImageCtx.h"
|
||||||
|
#include "librbd/Features.h"
|
||||||
|
|
||||||
#define dout_subsys ceph_subsys_rbd
|
#define dout_subsys ceph_subsys_rbd
|
||||||
#undef dout_prefix
|
#undef dout_prefix
|
||||||
@ -66,10 +67,11 @@ std::string generate_image_id(librados::IoCtx &ioctx) {
|
|||||||
|
|
||||||
uint64_t get_rbd_default_features(CephContext* cct)
|
uint64_t get_rbd_default_features(CephContext* cct)
|
||||||
{
|
{
|
||||||
auto str_val = cct->_conf->get_val<std::string>("rbd_default_features");
|
auto value = cct->_conf->get_val<std::string>("rbd_default_features");
|
||||||
return boost::lexical_cast<uint64_t>(str_val);
|
return librbd::rbd_features_from_string(value, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool calc_sparse_extent(const bufferptr &bp,
|
bool calc_sparse_extent(const bufferptr &bp,
|
||||||
size_t sparse_size,
|
size_t sparse_size,
|
||||||
uint64_t length,
|
uint64_t length,
|
||||||
|
Loading…
Reference in New Issue
Block a user