summaryrefslogtreecommitdiffstats
path: root/src/librbd/Utils.cc
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/librbd/Utils.cc246
1 files changed, 246 insertions, 0 deletions
diff --git a/src/librbd/Utils.cc b/src/librbd/Utils.cc
new file mode 100644
index 000000000..0ea31fc1c
--- /dev/null
+++ b/src/librbd/Utils.cc
@@ -0,0 +1,246 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include <boost/algorithm/string.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include "librbd/Utils.h"
+#include "include/random.h"
+#include "include/rbd_types.h"
+#include "include/stringify.h"
+#include "include/neorados/RADOS.hpp"
+#include "include/rbd/features.h"
+#include "common/dout.h"
+#include "common/errno.h"
+#include "librbd/ImageCtx.h"
+#include "librbd/Features.h"
+
+#include <boost/algorithm/string/predicate.hpp>
+#include <bitset>
+#include <random>
+
+#define dout_subsys ceph_subsys_rbd
+#undef dout_prefix
+#define dout_prefix *_dout << "librbd::util::" << __func__ << ": "
+
+namespace librbd {
+namespace util {
+namespace {
+
+const std::string CONFIG_KEY_URI_PREFIX{"config://"};
+
+} // anonymous namespace
+
+const std::string group_header_name(const std::string &group_id)
+{
+ return RBD_GROUP_HEADER_PREFIX + group_id;
+}
+
+const std::string id_obj_name(const std::string &name)
+{
+ return RBD_ID_PREFIX + name;
+}
+
+const std::string header_name(const std::string &image_id)
+{
+ return RBD_HEADER_PREFIX + image_id;
+}
+
+const std::string old_header_name(const std::string &image_name)
+{
+ return image_name + RBD_SUFFIX;
+}
+
+std::string unique_lock_name(const std::string &name, void *address) {
+ return name + " (" + stringify(address) + ")";
+}
+
+librados::AioCompletion *create_rados_callback(Context *on_finish) {
+ return create_rados_callback<Context, &Context::complete>(on_finish);
+}
+
+std::string generate_image_id(librados::IoCtx &ioctx) {
+ librados::Rados rados(ioctx);
+
+ uint64_t bid = rados.get_instance_id();
+ std::mt19937 generator{random_device_t{}()};
+ std::uniform_int_distribution<uint32_t> distribution{0, 0xFFFFFFFF};
+ uint32_t extra = distribution(generator);
+
+ std::ostringstream bid_ss;
+ bid_ss << std::hex << bid << std::hex << extra;
+ std::string id = bid_ss.str();
+
+ // ensure the image id won't overflow the fixed block name size
+ if (id.length() > RBD_MAX_IMAGE_ID_LENGTH) {
+ id = id.substr(id.length() - RBD_MAX_IMAGE_ID_LENGTH);
+ }
+
+ return id;
+}
+
+uint64_t get_rbd_default_features(CephContext* cct)
+{
+ auto value = cct->_conf.get_val<std::string>("rbd_default_features");
+ return librbd::rbd_features_from_string(value, nullptr);
+}
+
+
+bool calc_sparse_extent(const bufferptr &bp,
+ size_t sparse_size,
+ uint64_t length,
+ size_t *write_offset,
+ size_t *write_length,
+ size_t *offset) {
+ size_t extent_size;
+ if (*offset + sparse_size > length) {
+ extent_size = length - *offset;
+ } else {
+ extent_size = sparse_size;
+ }
+
+ bufferptr extent(bp, *offset, extent_size);
+ *offset += extent_size;
+
+ bool extent_is_zero = extent.is_zero();
+ if (!extent_is_zero) {
+ *write_length += extent_size;
+ }
+ if (extent_is_zero && *write_length == 0) {
+ *write_offset += extent_size;
+ }
+
+ if ((extent_is_zero || *offset == length) && *write_length != 0) {
+ return true;
+ }
+ return false;
+}
+
+bool is_metadata_config_override(const std::string& metadata_key,
+ std::string* config_key) {
+ size_t prefix_len = librbd::ImageCtx::METADATA_CONF_PREFIX.size();
+ if (metadata_key.size() > prefix_len &&
+ metadata_key.compare(0, prefix_len,
+ librbd::ImageCtx::METADATA_CONF_PREFIX) == 0) {
+ *config_key = metadata_key.substr(prefix_len,
+ metadata_key.size() - prefix_len);
+ return true;
+ }
+ return false;
+}
+
+int create_ioctx(librados::IoCtx& src_io_ctx, const std::string& pool_desc,
+ int64_t pool_id,
+ const std::optional<std::string>& pool_namespace,
+ librados::IoCtx* dst_io_ctx) {
+ auto cct = (CephContext *)src_io_ctx.cct();
+
+ librados::Rados rados(src_io_ctx);
+ int r = rados.ioctx_create2(pool_id, *dst_io_ctx);
+ if (r == -ENOENT) {
+ ldout(cct, 1) << pool_desc << " pool " << pool_id << " no longer exists"
+ << dendl;
+ return r;
+ } else if (r < 0) {
+ lderr(cct) << "error accessing " << pool_desc << " pool " << pool_id
+ << dendl;
+ return r;
+ }
+
+ dst_io_ctx->set_namespace(
+ pool_namespace ? *pool_namespace : src_io_ctx.get_namespace());
+ if (src_io_ctx.get_pool_full_try()) {
+ dst_io_ctx->set_pool_full_try();
+ }
+ return 0;
+}
+
+int snap_create_flags_api_to_internal(CephContext *cct, uint32_t api_flags,
+ uint64_t *internal_flags) {
+ *internal_flags = 0;
+
+ if (api_flags & RBD_SNAP_CREATE_SKIP_QUIESCE) {
+ *internal_flags |= SNAP_CREATE_FLAG_SKIP_NOTIFY_QUIESCE;
+ api_flags &= ~RBD_SNAP_CREATE_SKIP_QUIESCE;
+ } else if (api_flags & RBD_SNAP_CREATE_IGNORE_QUIESCE_ERROR) {
+ *internal_flags |= SNAP_CREATE_FLAG_IGNORE_NOTIFY_QUIESCE_ERROR;
+ api_flags &= ~RBD_SNAP_CREATE_IGNORE_QUIESCE_ERROR;
+ }
+
+ if (api_flags != 0) {
+ lderr(cct) << "invalid snap create flags: "
+ << std::bitset<32>(api_flags) << dendl;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+uint32_t get_default_snap_create_flags(ImageCtx *ictx) {
+ auto mode = ictx->config.get_val<std::string>(
+ "rbd_default_snapshot_quiesce_mode");
+
+ if (mode == "required") {
+ return 0;
+ } else if (mode == "ignore-error") {
+ return RBD_SNAP_CREATE_IGNORE_QUIESCE_ERROR;
+ } else if (mode == "skip") {
+ return RBD_SNAP_CREATE_SKIP_QUIESCE;
+ } else {
+ ceph_abort_msg("invalid rbd_default_snapshot_quiesce_mode");
+ }
+}
+
+SnapContext get_snap_context(
+ const std::optional<
+ std::pair<std::uint64_t,
+ std::vector<std::uint64_t>>>& write_snap_context) {
+ SnapContext snapc;
+ if (write_snap_context) {
+ snapc = SnapContext{write_snap_context->first,
+ {write_snap_context->second.begin(),
+ write_snap_context->second.end()}};
+ }
+ return snapc;
+}
+
+uint64_t reserve_async_request_id() {
+ static std::atomic<uint64_t> async_request_seq = 0;
+
+ return ++async_request_seq;
+}
+
+bool is_config_key_uri(const std::string& uri) {
+ return boost::starts_with(uri, CONFIG_KEY_URI_PREFIX);
+}
+
+int get_config_key(librados::Rados& rados, const std::string& uri,
+ std::string* value) {
+ auto cct = reinterpret_cast<CephContext*>(rados.cct());
+
+ if (!is_config_key_uri(uri)) {
+ return -EINVAL;
+ }
+
+ std::string key = uri.substr(CONFIG_KEY_URI_PREFIX.size());
+ std::string cmd =
+ "{"
+ "\"prefix\": \"config-key get\", "
+ "\"key\": \"" + key + "\""
+ "}";
+
+ bufferlist in_bl;
+ bufferlist out_bl;
+ int r = rados.mon_command(cmd, in_bl, &out_bl, nullptr);
+ if (r < 0) {
+ lderr(cct) << "failed to retrieve MON config key " << key << ": "
+ << cpp_strerror(r) << dendl;
+ return r;
+ }
+
+ *value = std::string(out_bl.c_str(), out_bl.length());
+ return 0;
+}
+
+} // namespace util
+} // namespace librbd