]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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/algorithm/string.hpp> | |
5 | #include <boost/lexical_cast.hpp> | |
6 | ||
7 | #include "librbd/Utils.h" | |
f67539c2 | 8 | #include "include/random.h" |
7c673cae FG |
9 | #include "include/rbd_types.h" |
10 | #include "include/stringify.h" | |
f67539c2 | 11 | #include "include/neorados/RADOS.hpp" |
7c673cae FG |
12 | #include "include/rbd/features.h" |
13 | #include "common/dout.h" | |
f67539c2 | 14 | #include "common/errno.h" |
b32b8144 | 15 | #include "librbd/ImageCtx.h" |
11fdf7f2 | 16 | #include "librbd/Features.h" |
f67539c2 TL |
17 | |
18 | #include <boost/algorithm/string/predicate.hpp> | |
19 | #include <bitset> | |
11fdf7f2 | 20 | #include <random> |
7c673cae FG |
21 | |
22 | #define dout_subsys ceph_subsys_rbd | |
23 | #undef dout_prefix | |
11fdf7f2 | 24 | #define dout_prefix *_dout << "librbd::util::" << __func__ << ": " |
7c673cae FG |
25 | |
26 | namespace librbd { | |
27 | namespace util { | |
f67539c2 TL |
28 | namespace { |
29 | ||
30 | const std::string CONFIG_KEY_URI_PREFIX{"config://"}; | |
31 | ||
32 | } // anonymous namespace | |
7c673cae FG |
33 | |
34 | const std::string group_header_name(const std::string &group_id) | |
35 | { | |
36 | return RBD_GROUP_HEADER_PREFIX + group_id; | |
37 | } | |
38 | ||
39 | const std::string id_obj_name(const std::string &name) | |
40 | { | |
41 | return RBD_ID_PREFIX + name; | |
42 | } | |
43 | ||
44 | const std::string header_name(const std::string &image_id) | |
45 | { | |
46 | return RBD_HEADER_PREFIX + image_id; | |
47 | } | |
48 | ||
49 | const std::string old_header_name(const std::string &image_name) | |
50 | { | |
51 | return image_name + RBD_SUFFIX; | |
52 | } | |
53 | ||
54 | std::string unique_lock_name(const std::string &name, void *address) { | |
55 | return name + " (" + stringify(address) + ")"; | |
56 | } | |
57 | ||
58 | librados::AioCompletion *create_rados_callback(Context *on_finish) { | |
59 | return create_rados_callback<Context, &Context::complete>(on_finish); | |
60 | } | |
61 | ||
62 | std::string generate_image_id(librados::IoCtx &ioctx) { | |
63 | librados::Rados rados(ioctx); | |
64 | ||
65 | uint64_t bid = rados.get_instance_id(); | |
f67539c2 | 66 | std::mt19937 generator{random_device_t{}()}; |
11fdf7f2 TL |
67 | std::uniform_int_distribution<uint32_t> distribution{0, 0xFFFFFFFF}; |
68 | uint32_t extra = distribution(generator); | |
7c673cae | 69 | |
20effc67 | 70 | std::ostringstream bid_ss; |
7c673cae FG |
71 | bid_ss << std::hex << bid << std::hex << extra; |
72 | std::string id = bid_ss.str(); | |
73 | ||
74 | // ensure the image id won't overflow the fixed block name size | |
75 | if (id.length() > RBD_MAX_IMAGE_ID_LENGTH) { | |
76 | id = id.substr(id.length() - RBD_MAX_IMAGE_ID_LENGTH); | |
77 | } | |
78 | ||
79 | return id; | |
80 | } | |
81 | ||
82 | uint64_t get_rbd_default_features(CephContext* cct) | |
83 | { | |
11fdf7f2 TL |
84 | auto value = cct->_conf.get_val<std::string>("rbd_default_features"); |
85 | return librbd::rbd_features_from_string(value, nullptr); | |
7c673cae FG |
86 | } |
87 | ||
11fdf7f2 | 88 | |
7c673cae FG |
89 | bool calc_sparse_extent(const bufferptr &bp, |
90 | size_t sparse_size, | |
91 | uint64_t length, | |
92 | size_t *write_offset, | |
93 | size_t *write_length, | |
94 | size_t *offset) { | |
95 | size_t extent_size; | |
96 | if (*offset + sparse_size > length) { | |
97 | extent_size = length - *offset; | |
98 | } else { | |
99 | extent_size = sparse_size; | |
100 | } | |
101 | ||
102 | bufferptr extent(bp, *offset, extent_size); | |
103 | *offset += extent_size; | |
104 | ||
105 | bool extent_is_zero = extent.is_zero(); | |
106 | if (!extent_is_zero) { | |
107 | *write_length += extent_size; | |
108 | } | |
109 | if (extent_is_zero && *write_length == 0) { | |
110 | *write_offset += extent_size; | |
111 | } | |
112 | ||
113 | if ((extent_is_zero || *offset == length) && *write_length != 0) { | |
114 | return true; | |
115 | } | |
116 | return false; | |
117 | } | |
7c673cae | 118 | |
b32b8144 FG |
119 | bool is_metadata_config_override(const std::string& metadata_key, |
120 | std::string* config_key) { | |
121 | size_t prefix_len = librbd::ImageCtx::METADATA_CONF_PREFIX.size(); | |
122 | if (metadata_key.size() > prefix_len && | |
123 | metadata_key.compare(0, prefix_len, | |
124 | librbd::ImageCtx::METADATA_CONF_PREFIX) == 0) { | |
125 | *config_key = metadata_key.substr(prefix_len, | |
126 | metadata_key.size() - prefix_len); | |
127 | return true; | |
128 | } | |
129 | return false; | |
130 | } | |
131 | ||
11fdf7f2 TL |
132 | int create_ioctx(librados::IoCtx& src_io_ctx, const std::string& pool_desc, |
133 | int64_t pool_id, | |
134 | const std::optional<std::string>& pool_namespace, | |
135 | librados::IoCtx* dst_io_ctx) { | |
136 | auto cct = (CephContext *)src_io_ctx.cct(); | |
137 | ||
138 | librados::Rados rados(src_io_ctx); | |
139 | int r = rados.ioctx_create2(pool_id, *dst_io_ctx); | |
140 | if (r == -ENOENT) { | |
92f5a8d4 TL |
141 | ldout(cct, 1) << pool_desc << " pool " << pool_id << " no longer exists" |
142 | << dendl; | |
11fdf7f2 TL |
143 | return r; |
144 | } else if (r < 0) { | |
145 | lderr(cct) << "error accessing " << pool_desc << " pool " << pool_id | |
146 | << dendl; | |
147 | return r; | |
148 | } | |
149 | ||
150 | dst_io_ctx->set_namespace( | |
151 | pool_namespace ? *pool_namespace : src_io_ctx.get_namespace()); | |
20effc67 TL |
152 | if (src_io_ctx.get_pool_full_try()) { |
153 | dst_io_ctx->set_pool_full_try(); | |
154 | } | |
11fdf7f2 TL |
155 | return 0; |
156 | } | |
157 | ||
f67539c2 TL |
158 | int snap_create_flags_api_to_internal(CephContext *cct, uint32_t api_flags, |
159 | uint64_t *internal_flags) { | |
160 | *internal_flags = 0; | |
161 | ||
162 | if (api_flags & RBD_SNAP_CREATE_SKIP_QUIESCE) { | |
163 | *internal_flags |= SNAP_CREATE_FLAG_SKIP_NOTIFY_QUIESCE; | |
164 | api_flags &= ~RBD_SNAP_CREATE_SKIP_QUIESCE; | |
165 | } else if (api_flags & RBD_SNAP_CREATE_IGNORE_QUIESCE_ERROR) { | |
166 | *internal_flags |= SNAP_CREATE_FLAG_IGNORE_NOTIFY_QUIESCE_ERROR; | |
167 | api_flags &= ~RBD_SNAP_CREATE_IGNORE_QUIESCE_ERROR; | |
168 | } | |
169 | ||
170 | if (api_flags != 0) { | |
171 | lderr(cct) << "invalid snap create flags: " | |
172 | << std::bitset<32>(api_flags) << dendl; | |
173 | return -EINVAL; | |
174 | } | |
175 | ||
176 | return 0; | |
177 | } | |
178 | ||
179 | uint32_t get_default_snap_create_flags(ImageCtx *ictx) { | |
180 | auto mode = ictx->config.get_val<std::string>( | |
181 | "rbd_default_snapshot_quiesce_mode"); | |
182 | ||
183 | if (mode == "required") { | |
184 | return 0; | |
185 | } else if (mode == "ignore-error") { | |
186 | return RBD_SNAP_CREATE_IGNORE_QUIESCE_ERROR; | |
187 | } else if (mode == "skip") { | |
188 | return RBD_SNAP_CREATE_SKIP_QUIESCE; | |
189 | } else { | |
190 | ceph_abort_msg("invalid rbd_default_snapshot_quiesce_mode"); | |
191 | } | |
192 | } | |
193 | ||
194 | SnapContext get_snap_context( | |
195 | const std::optional< | |
196 | std::pair<std::uint64_t, | |
197 | std::vector<std::uint64_t>>>& write_snap_context) { | |
198 | SnapContext snapc; | |
199 | if (write_snap_context) { | |
200 | snapc = SnapContext{write_snap_context->first, | |
201 | {write_snap_context->second.begin(), | |
202 | write_snap_context->second.end()}}; | |
203 | } | |
204 | return snapc; | |
205 | } | |
206 | ||
207 | uint64_t reserve_async_request_id() { | |
208 | static std::atomic<uint64_t> async_request_seq = 0; | |
209 | ||
210 | return ++async_request_seq; | |
211 | } | |
212 | ||
213 | bool is_config_key_uri(const std::string& uri) { | |
214 | return boost::starts_with(uri, CONFIG_KEY_URI_PREFIX); | |
215 | } | |
216 | ||
217 | int get_config_key(librados::Rados& rados, const std::string& uri, | |
218 | std::string* value) { | |
219 | auto cct = reinterpret_cast<CephContext*>(rados.cct()); | |
220 | ||
221 | if (!is_config_key_uri(uri)) { | |
222 | return -EINVAL; | |
223 | } | |
224 | ||
225 | std::string key = uri.substr(CONFIG_KEY_URI_PREFIX.size()); | |
226 | std::string cmd = | |
227 | "{" | |
228 | "\"prefix\": \"config-key get\", " | |
229 | "\"key\": \"" + key + "\"" | |
230 | "}"; | |
231 | ||
232 | bufferlist in_bl; | |
233 | bufferlist out_bl; | |
234 | int r = rados.mon_command(cmd, in_bl, &out_bl, nullptr); | |
235 | if (r < 0) { | |
236 | lderr(cct) << "failed to retrieve MON config key " << key << ": " | |
237 | << cpp_strerror(r) << dendl; | |
238 | return r; | |
239 | } | |
240 | ||
241 | *value = std::string(out_bl.c_str(), out_bl.length()); | |
242 | return 0; | |
243 | } | |
244 | ||
b32b8144 | 245 | } // namespace util |
7c673cae | 246 | } // namespace librbd |