]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #include <boost/lexical_cast.hpp> | |
5 | #include <boost/algorithm/string.hpp> | |
6 | ||
7 | #include "librbd/Features.h" | |
8 | #include "include/rbd/features.h" | |
9 | ||
10 | #include <map> | |
11 | #include <vector> | |
12 | ||
13 | static const std::map<std::string, uint64_t> RBD_FEATURE_MAP = { | |
14 | {RBD_FEATURE_NAME_LAYERING, RBD_FEATURE_LAYERING}, | |
15 | {RBD_FEATURE_NAME_STRIPINGV2, RBD_FEATURE_STRIPINGV2}, | |
16 | {RBD_FEATURE_NAME_EXCLUSIVE_LOCK, RBD_FEATURE_EXCLUSIVE_LOCK}, | |
17 | {RBD_FEATURE_NAME_OBJECT_MAP, RBD_FEATURE_OBJECT_MAP}, | |
18 | {RBD_FEATURE_NAME_FAST_DIFF, RBD_FEATURE_FAST_DIFF}, | |
19 | {RBD_FEATURE_NAME_DEEP_FLATTEN, RBD_FEATURE_DEEP_FLATTEN}, | |
20 | {RBD_FEATURE_NAME_JOURNALING, RBD_FEATURE_JOURNALING}, | |
21 | {RBD_FEATURE_NAME_DATA_POOL, RBD_FEATURE_DATA_POOL}, | |
22 | {RBD_FEATURE_NAME_OPERATIONS, RBD_FEATURE_OPERATIONS}, | |
23 | {RBD_FEATURE_NAME_MIGRATING, RBD_FEATURE_MIGRATING}, | |
9f95a23c | 24 | {RBD_FEATURE_NAME_NON_PRIMARY, RBD_FEATURE_NON_PRIMARY}, |
11fdf7f2 | 25 | }; |
9f95a23c | 26 | static_assert((RBD_FEATURE_NON_PRIMARY << 1) > RBD_FEATURES_ALL, |
11fdf7f2 TL |
27 | "new RBD feature added"); |
28 | ||
29 | ||
30 | namespace librbd { | |
31 | ||
32 | std::string rbd_features_to_string(uint64_t features, | |
33 | std::ostream *err) | |
34 | { | |
35 | std::string r; | |
36 | for (auto& i : RBD_FEATURE_MAP) { | |
37 | if (features & i.second) { | |
9f95a23c TL |
38 | if (!r.empty()) { |
39 | r += ","; | |
11fdf7f2 TL |
40 | } |
41 | r += i.first; | |
42 | features &= ~i.second; | |
43 | } | |
44 | } | |
45 | if (err && features) { | |
46 | *err << "ignoring unknown feature mask 0x" | |
47 | << std::hex << features << std::dec; | |
48 | } | |
49 | return r; | |
50 | } | |
51 | ||
52 | uint64_t rbd_features_from_string(const std::string& orig_value, | |
53 | std::ostream *err) | |
54 | { | |
55 | uint64_t features = 0; | |
56 | std::string value = orig_value; | |
57 | boost::trim(value); | |
58 | ||
59 | // empty string means default features | |
60 | if (!value.size()) { | |
61 | return RBD_FEATURES_DEFAULT; | |
62 | } | |
63 | ||
64 | try { | |
65 | // numeric? | |
66 | features = boost::lexical_cast<uint64_t>(value); | |
67 | ||
68 | // drop unrecognized bits | |
69 | uint64_t unsupported_features = (features & ~RBD_FEATURES_ALL); | |
70 | if (unsupported_features != 0ull) { | |
71 | features &= RBD_FEATURES_ALL; | |
72 | if (err) { | |
73 | *err << "ignoring unknown feature mask 0x" | |
74 | << std::hex << unsupported_features << std::dec; | |
75 | } | |
76 | } | |
9f95a23c TL |
77 | |
78 | uint64_t ignore_features_mask = ( | |
79 | RBD_FEATURES_INTERNAL | RBD_FEATURES_MUTABLE_INTERNAL); | |
80 | uint64_t ignored_features = (features & ignore_features_mask); | |
81 | if (ignored_features != 0ULL) { | |
82 | features &= ~ignore_features_mask; | |
11fdf7f2 | 83 | if (err) { |
9f95a23c | 84 | *err << "ignoring feature mask 0x" << std::hex << ignored_features; |
11fdf7f2 TL |
85 | } |
86 | } | |
87 | } catch (boost::bad_lexical_cast&) { | |
88 | // feature name list? | |
89 | bool errors = false; | |
90 | std::vector<std::string> feature_names; | |
91 | boost::split(feature_names, value, boost::is_any_of(",")); | |
92 | for (auto feature_name: feature_names) { | |
93 | boost::trim(feature_name); | |
94 | auto feature_it = RBD_FEATURE_MAP.find(feature_name); | |
95 | if (feature_it != RBD_FEATURE_MAP.end()) { | |
96 | features += feature_it->second; | |
97 | } else if (err) { | |
98 | if (errors) { | |
99 | *err << ", "; | |
100 | } else { | |
101 | errors = true; | |
102 | } | |
103 | *err << "ignoring unknown feature " << feature_name; | |
104 | } | |
105 | } | |
106 | } | |
107 | return features; | |
108 | } | |
109 | ||
110 | } // namespace librbd |