]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/Utils.cc
import ceph quincy 17.2.1
[ceph.git] / ceph / src / librbd / Utils.cc
CommitLineData
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
26namespace librbd {
27namespace util {
f67539c2
TL
28namespace {
29
30const std::string CONFIG_KEY_URI_PREFIX{"config://"};
31
32} // anonymous namespace
7c673cae
FG
33
34const std::string group_header_name(const std::string &group_id)
35{
36 return RBD_GROUP_HEADER_PREFIX + group_id;
37}
38
39const std::string id_obj_name(const std::string &name)
40{
41 return RBD_ID_PREFIX + name;
42}
43
44const std::string header_name(const std::string &image_id)
45{
46 return RBD_HEADER_PREFIX + image_id;
47}
48
49const std::string old_header_name(const std::string &image_name)
50{
51 return image_name + RBD_SUFFIX;
52}
53
54std::string unique_lock_name(const std::string &name, void *address) {
55 return name + " (" + stringify(address) + ")";
56}
57
58librados::AioCompletion *create_rados_callback(Context *on_finish) {
59 return create_rados_callback<Context, &Context::complete>(on_finish);
60}
61
62std::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
82uint64_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
89bool 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
119bool 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
132int 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
158int 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
179uint32_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
194SnapContext 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
207uint64_t reserve_async_request_id() {
208 static std::atomic<uint64_t> async_request_seq = 0;
209
210 return ++async_request_seq;
211}
212
213bool is_config_key_uri(const std::string& uri) {
214 return boost::starts_with(uri, CONFIG_KEY_URI_PREFIX);
215}
216
217int 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