1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
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
|