diff options
Diffstat (limited to 'src/librbd/Utils.cc')
-rw-r--r-- | src/librbd/Utils.cc | 246 |
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 |