// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include #include #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 #include #include #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(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 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("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& 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( "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>>& 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 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(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