]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/Utils.cc
bump version to 18.2.4-pve3
[ceph.git] / ceph / src / librbd / Utils.cc
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"
8 #include "include/random.h"
9 #include "include/rbd_types.h"
10 #include "include/stringify.h"
11 #include "include/neorados/RADOS.hpp"
12 #include "include/rbd/features.h"
13 #include "common/dout.h"
14 #include "common/errno.h"
15 #include "librbd/ImageCtx.h"
16 #include "librbd/Features.h"
17
18 #include <boost/algorithm/string/predicate.hpp>
19 #include <bitset>
20 #include <random>
21
22 #define dout_subsys ceph_subsys_rbd
23 #undef dout_prefix
24 #define dout_prefix *_dout << "librbd::util::" << __func__ << ": "
25
26 namespace librbd {
27 namespace util {
28 namespace {
29
30 const std::string CONFIG_KEY_URI_PREFIX{"config://"};
31
32 } // anonymous namespace
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();
66 std::mt19937 generator{random_device_t{}()};
67 std::uniform_int_distribution<uint32_t> distribution{0, 0xFFFFFFFF};
68 uint32_t extra = distribution(generator);
69
70 std::ostringstream bid_ss;
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 {
84 auto value = cct->_conf.get_val<std::string>("rbd_default_features");
85 return librbd::rbd_features_from_string(value, nullptr);
86 }
87
88
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 }
118
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
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) {
141 ldout(cct, 1) << pool_desc << " pool " << pool_id << " no longer exists"
142 << dendl;
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());
152 if (src_io_ctx.get_pool_full_try()) {
153 dst_io_ctx->set_pool_full_try();
154 }
155 return 0;
156 }
157
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
245 } // namespace util
246 } // namespace librbd