char *keys, size_t *key_len, char *values, size_t *vals_len);
+CEPH_RBD_API int rbd_mirror_image_enable(rbd_image_t image);
+
#ifdef __cplusplus
}
#endif
*/
int metadata_list(const std::string &start, uint64_t max, std::map<std::string, ceph::bufferlist> *pairs);
+ int mirror_image_enable();
+
private:
friend class RBD;
return 0;
}
+template <typename I>
+int Journal<I>::is_tag_owner(ImageCtx *image_ctx, bool *is_tag_owner) {
+
+ cls::journal::Client client;
+ librbd::journal::ClientData client_data;
+ bufferlist::iterator bl;
+ journal::TagData tag_data;
+ uint64_t tag_class;
+ librbd::journal::ImageClientMeta *image_client_meta;
+ Mutex lock("lock");
+ C_SaferCond get_tags_ctx;
+ C_DecodeTags *tags_ctx;
+
+ Journaler journaler(image_ctx->md_ctx, image_ctx->id, IMAGE_CLIENT_ID,
+ image_ctx->cct->_conf->rbd_journal_commit_age);
+
+ C_SaferCond init_ctx;
+ journaler.init(&init_ctx);
+ int r = init_ctx.wait();
+ if (r < 0) {
+ return r;
+ }
+
+ r = journaler.get_cached_client(Journal<ImageCtx>::IMAGE_CLIENT_ID, &client);
+ if (r < 0) {
+ goto clean_up;
+ }
+
+ bl = client.data.begin();
+ try {
+ ::decode(client_data, bl);
+ } catch (const buffer::error &err) {
+ r = -EINVAL;
+ goto clean_up;
+ }
+
+ image_client_meta =
+ boost::get<librbd::journal::ImageClientMeta>(&client_data.client_meta);
+ if (image_client_meta == nullptr) {
+ r = -EINVAL;
+ goto clean_up;
+ }
+
+ tag_class = image_client_meta->tag_class;
+ uint64_t tag_tid;
+ tags_ctx = new C_DecodeTags(
+ image_ctx->cct, &lock, &tag_tid, &tag_data, &get_tags_ctx);
+ journaler.get_tags(tag_class, &tags_ctx->tags, tags_ctx);
+
+ r = get_tags_ctx.wait();
+ if (r < 0) {
+ goto clean_up;
+ }
+
+ *is_tag_owner = (tag_data.mirror_uuid == LOCAL_MIRROR_UUID);
+
+clean_up:
+ journaler.shut_down();
+
+ return r;
+}
+
template <typename I>
bool Journal<I>::is_journal_ready() const {
Mutex::Locker locker(m_lock);
static int remove(librados::IoCtx &io_ctx, const std::string &image_id);
static int reset(librados::IoCtx &io_ctx, const std::string &image_id);
+ static int is_tag_owner(ImageCtx *image_ctx, bool *is_tag_owner);
+
bool is_journal_ready() const;
bool is_journal_replaying() const;
return cls_client::metadata_list(&ictx->md_ctx, ictx->header_oid, start, max, pairs);
}
+ int mirror_image_enable(ImageCtx *ictx) {
+ CephContext *cct = ictx->cct;
+ ldout(cct, 20) << "mirror_image_enable " << ictx << dendl;
+
+ if ((ictx->features & RBD_FEATURE_JOURNALING) == 0) {
+ lderr(cct) << "cannot enable mirroring: journaling is not enabled"
+ << dendl;
+ return -EINVAL;
+ }
+
+ bool is_primary;
+ int r = Journal<>::is_tag_owner(ictx, &is_primary);
+ if (r < 0) {
+ lderr(cct) << "cannot enable mirroring: failed to check tag ownership: "
+ << cpp_strerror(r) << dendl;
+ return r;
+ }
+
+ if (!is_primary) {
+ lderr(cct) <<
+ "cannot enable mirroring: last journal tag not owned by local cluster"
+ << dendl;
+ return -EINVAL;
+ }
+
+ cls::rbd::MirrorImage mirror_image_internal;
+ r = cls_client::mirror_image_get(&ictx->md_ctx, ictx->id,
+ &mirror_image_internal);
+ if (r < 0 && r != -ENOENT) {
+ lderr(cct) << "cannot enable mirroring: " << cpp_strerror(r) << dendl;
+ return r;
+ }
+
+ if (mirror_image_internal.state ==
+ cls::rbd::MirrorImageState::MIRROR_IMAGE_STATE_ENABLED) {
+ // mirroring is already enabled
+ return 0;
+ }
+ else if (r != -ENOENT) {
+ lderr(cct) << "cannot enable mirroring: mirroring image is in "
+ "disabling state" << dendl;
+ return -EINVAL;
+ }
+
+ mirror_image_internal.state =
+ cls::rbd::MirrorImageState::MIRROR_IMAGE_STATE_ENABLED;
+
+ uuid_d uuid_gen;
+ uuid_gen.generate_random();
+ mirror_image_internal.global_image_id = uuid_gen.to_string();
+
+ r = cls_client::mirror_image_set(&ictx->md_ctx, ictx->id,
+ mirror_image_internal);
+ if (r < 0) {
+ lderr(cct) << "cannot enable mirroring: " << cpp_strerror(r) << dendl;
+ return r;
+ }
+
+ ldout(cct, 20) << "image mirroring is enabled: global_id=" <<
+ mirror_image_internal.global_image_id << dendl;
+
+ return 0;
+ }
+
int mirror_mode_get(IoCtx& io_ctx, rbd_mirror_mode_t *mirror_mode) {
CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
ldout(cct, 20) << __func__ << dendl;
int mirror_peer_set_cluster(IoCtx& io_ctx, const std::string &uuid,
const std::string &cluster_name);
+ int mirror_image_enable(ImageCtx *ictx);
}
#endif
return r;
}
+ int Image::mirror_image_enable() {
+ ImageCtx *ictx = (ImageCtx *)ctx;
+ return librbd::mirror_image_enable(ictx);
+ }
+
} // namespace librbd
extern "C" void rbd_version(int *major, int *minor, int *extra)
return r;
}
+extern "C" int rbd_mirror_image_enable(rbd_image_t image)
+{
+ librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
+ return librbd::mirror_image_enable(ictx);
+}
+
extern "C" int rbd_aio_is_complete(rbd_completion_t c)
{
librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;