1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include <boost/algorithm/string.hpp>
5 #include <boost/lexical_cast.hpp>
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"
18 #include <boost/algorithm/string/predicate.hpp>
22 #define dout_subsys ceph_subsys_rbd
24 #define dout_prefix *_dout << "librbd::util::" << __func__ << ": "
30 const std::string CONFIG_KEY_URI_PREFIX
{"config://"};
32 } // anonymous namespace
34 const std::string
group_header_name(const std::string
&group_id
)
36 return RBD_GROUP_HEADER_PREFIX
+ group_id
;
39 const std::string
id_obj_name(const std::string
&name
)
41 return RBD_ID_PREFIX
+ name
;
44 const std::string
header_name(const std::string
&image_id
)
46 return RBD_HEADER_PREFIX
+ image_id
;
49 const std::string
old_header_name(const std::string
&image_name
)
51 return image_name
+ RBD_SUFFIX
;
54 std::string
unique_lock_name(const std::string
&name
, void *address
) {
55 return name
+ " (" + stringify(address
) + ")";
58 librados::AioCompletion
*create_rados_callback(Context
*on_finish
) {
59 return create_rados_callback
<Context
, &Context::complete
>(on_finish
);
62 std::string
generate_image_id(librados::IoCtx
&ioctx
) {
63 librados::Rados
rados(ioctx
);
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
);
70 std::ostringstream bid_ss
;
71 bid_ss
<< std::hex
<< bid
<< std::hex
<< extra
;
72 std::string id
= bid_ss
.str();
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
);
82 uint64_t get_rbd_default_features(CephContext
* cct
)
84 auto value
= cct
->_conf
.get_val
<std::string
>("rbd_default_features");
85 return librbd::rbd_features_from_string(value
, nullptr);
89 bool calc_sparse_extent(const bufferptr
&bp
,
96 if (*offset
+ sparse_size
> length
) {
97 extent_size
= length
- *offset
;
99 extent_size
= sparse_size
;
102 bufferptr
extent(bp
, *offset
, extent_size
);
103 *offset
+= extent_size
;
105 bool extent_is_zero
= extent
.is_zero();
106 if (!extent_is_zero
) {
107 *write_length
+= extent_size
;
109 if (extent_is_zero
&& *write_length
== 0) {
110 *write_offset
+= extent_size
;
113 if ((extent_is_zero
|| *offset
== length
) && *write_length
!= 0) {
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
);
132 int create_ioctx(librados::IoCtx
& src_io_ctx
, const std::string
& pool_desc
,
134 const std::optional
<std::string
>& pool_namespace
,
135 librados::IoCtx
* dst_io_ctx
) {
136 auto cct
= (CephContext
*)src_io_ctx
.cct();
138 librados::Rados
rados(src_io_ctx
);
139 int r
= rados
.ioctx_create2(pool_id
, *dst_io_ctx
);
141 ldout(cct
, 1) << pool_desc
<< " pool " << pool_id
<< " no longer exists"
145 lderr(cct
) << "error accessing " << pool_desc
<< " pool " << pool_id
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();
158 int snap_create_flags_api_to_internal(CephContext
*cct
, uint32_t api_flags
,
159 uint64_t *internal_flags
) {
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
;
170 if (api_flags
!= 0) {
171 lderr(cct
) << "invalid snap create flags: "
172 << std::bitset
<32>(api_flags
) << dendl
;
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");
183 if (mode
== "required") {
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
;
190 ceph_abort_msg("invalid rbd_default_snapshot_quiesce_mode");
194 SnapContext
get_snap_context(
196 std::pair
<std::uint64_t,
197 std::vector
<std::uint64_t>>>& write_snap_context
) {
199 if (write_snap_context
) {
200 snapc
= SnapContext
{write_snap_context
->first
,
201 {write_snap_context
->second
.begin(),
202 write_snap_context
->second
.end()}};
207 uint64_t reserve_async_request_id() {
208 static std::atomic
<uint64_t> async_request_seq
= 0;
210 return ++async_request_seq
;
213 bool is_config_key_uri(const std::string
& uri
) {
214 return boost::starts_with(uri
, CONFIG_KEY_URI_PREFIX
);
217 int get_config_key(librados::Rados
& rados
, const std::string
& uri
,
218 std::string
* value
) {
219 auto cct
= reinterpret_cast<CephContext
*>(rados
.cct());
221 if (!is_config_key_uri(uri
)) {
225 std::string key
= uri
.substr(CONFIG_KEY_URI_PREFIX
.size());
228 "\"prefix\": \"config-key get\", "
229 "\"key\": \"" + key
+ "\""
234 int r
= rados
.mon_command(cmd
, in_bl
, &out_bl
, nullptr);
236 lderr(cct
) << "failed to retrieve MON config key " << key
<< ": "
237 << cpp_strerror(r
) << dendl
;
241 *value
= std::string(out_bl
.c_str(), out_bl
.length());
246 } // namespace librbd