From c9c8852f6ec6e1f6ba22a190cbde6a767a8c0dfc Mon Sep 17 00:00:00 2001 From: Mykola Golub Date: Sun, 1 Sep 2019 09:48:16 +0100 Subject: [PATCH] librbd: snapshot mirror mode Enabling mirroring for an image that does not support journaling assumes snapshot based mirroring, which is supported only when the pool is in the "image" mirror mode. Also for the pool in the "image" mirror mode disabling/enabling journaling feature for a mirroring image will switch snapshot/journal mirror mode. Signed-off-by: Mykola Golub --- qa/workunits/rbd/rbd_mirror.sh | 2 - src/librbd/api/Migration.cc | 9 - src/librbd/api/Mirror.cc | 33 +-- src/librbd/api/Trash.cc | 8 - src/librbd/image/PreRemoveRequest.cc | 2 + src/librbd/mirror/DemoteRequest.cc | 22 +- src/librbd/mirror/DisableRequest.cc | 100 ++++---- src/librbd/mirror/DisableRequest.h | 16 +- src/librbd/mirror/EnableRequest.cc | 48 +++- src/librbd/mirror/EnableRequest.h | 8 +- src/librbd/mirror/GetInfoRequest.cc | 56 ++++- src/librbd/mirror/GetInfoRequest.h | 8 +- src/librbd/mirror/PromoteRequest.cc | 11 +- src/librbd/mirror/snapshot/DemoteRequest.h | 10 +- src/librbd/mirror/snapshot/PromoteRequest.h | 10 +- src/librbd/operation/EnableFeaturesRequest.cc | 74 +++++- src/librbd/operation/EnableFeaturesRequest.h | 20 +- .../librbd/mirror/test_mock_DisableRequest.cc | 237 +++++++++--------- .../test_mock_DisableFeaturesRequest.cc | 58 ++++- .../test_mock_EnableFeaturesRequest.cc | 70 +++++- src/test/librbd/test_mirroring.cc | 37 ++- .../test_mock_BootstrapRequest.cc | 158 +++++++----- src/tools/rbd_mirror/CMakeLists.txt | 1 - .../image_replayer/BootstrapRequest.cc | 38 ++- .../image_replayer/BootstrapRequest.h | 12 +- .../image_replayer/IsPrimaryRequest.cc | 131 ---------- .../image_replayer/IsPrimaryRequest.h | 67 ----- .../image_replayer/OpenLocalImageRequest.cc | 30 ++- .../image_replayer/OpenLocalImageRequest.h | 12 +- 29 files changed, 701 insertions(+), 587 deletions(-) delete mode 100644 src/tools/rbd_mirror/image_replayer/IsPrimaryRequest.cc delete mode 100644 src/tools/rbd_mirror/image_replayer/IsPrimaryRequest.h diff --git a/qa/workunits/rbd/rbd_mirror.sh b/qa/workunits/rbd/rbd_mirror.sh index cf0d9f7e300..86af089f8a5 100755 --- a/qa/workunits/rbd/rbd_mirror.sh +++ b/qa/workunits/rbd/rbd_mirror.sh @@ -334,7 +334,6 @@ done set_pool_mirror_mode ${CLUSTER2} ${POOL} 'pool' for i in ${image2} ${image4}; do - enable_journaling ${CLUSTER2} ${POOL} ${i} wait_for_image_present ${CLUSTER1} ${POOL} ${i} 'present' wait_for_snap_present ${CLUSTER1} ${POOL} ${i} 'snap2' wait_for_image_replay_started ${CLUSTER1} ${POOL} ${i} @@ -390,7 +389,6 @@ fi start_mirrors ${CLUSTER1} wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'deleted' set_pool_mirror_mode ${CLUSTER2} ${POOL} 'pool' -enable_journaling ${CLUSTER2} ${POOL} ${image} wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'present' wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image} diff --git a/src/librbd/api/Migration.cc b/src/librbd/api/Migration.cc index 713b856804e..458d15254a7 100644 --- a/src/librbd/api/Migration.cc +++ b/src/librbd/api/Migration.cc @@ -1417,10 +1417,6 @@ template int Migration::disable_mirroring(I *image_ctx, bool *was_enabled) { *was_enabled = false; - if (!image_ctx->test_features(RBD_FEATURE_JOURNALING)) { - return 0; - } - cls::rbd::MirrorImage mirror_image; int r = cls_client::mirror_image_get(&image_ctx->md_ctx, image_ctx->id, &mirror_image); @@ -1458,11 +1454,6 @@ int Migration::disable_mirroring(I *image_ctx, bool *was_enabled) { template int Migration::enable_mirroring(I *image_ctx, bool was_enabled) { - - if (!image_ctx->test_features(RBD_FEATURE_JOURNALING)) { - return 0; - } - cls::rbd::MirrorMode mirror_mode; int r = cls_client::mirror_mode_get(&image_ctx->md_ctx, &mirror_mode); if (r < 0 && r != -ENOENT) { diff --git a/src/librbd/api/Mirror.cc b/src/librbd/api/Mirror.cc index 4f7cb215ea1..2fe16829140 100644 --- a/src/librbd/api/Mirror.cc +++ b/src/librbd/api/Mirror.cc @@ -281,7 +281,7 @@ struct C_ImageGetInfo : public Context { } void finish(int r) override { - if (r < 0) { + if (r < 0 && r != -ENOENT) { on_finish->complete(r); return; } @@ -311,7 +311,7 @@ struct C_ImageGetGlobalStatus : public C_ImageGetInfo { } void finish(int r) override { - if (r < 0) { + if (r < 0 && r != -ENOENT) { on_finish->complete(r); return; } @@ -363,13 +363,8 @@ int Mirror::image_enable(I *ictx, bool relax_same_pool_parent_check) { std::shared_lock image_locker{ictx->image_lock}; ImageCtx *parent = ictx->parent; if (parent) { - if (relax_same_pool_parent_check && - parent->md_ctx.get_id() == ictx->md_ctx.get_id()) { - if (!parent->test_features(RBD_FEATURE_JOURNALING)) { - lderr(cct) << "journaling is not enabled for the parent" << dendl; - return -EINVAL; - } - } else { + if (parent->md_ctx.get_id() != ictx->md_ctx.get_id() || + !relax_same_pool_parent_check) { cls::rbd::MirrorImage mirror_image_internal; r = cls_client::mirror_image_get(&(parent->md_ctx), parent->id, &mirror_image_internal); @@ -381,18 +376,6 @@ int Mirror::image_enable(I *ictx, bool relax_same_pool_parent_check) { } } - if (!ictx->test_features(RBD_FEATURE_JOURNALING)) { - uint64_t features = RBD_FEATURE_JOURNALING; - if (!ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) { - features |= RBD_FEATURE_EXCLUSIVE_LOCK; - } - r = ictx->operations->update_features(features, true); - if (r < 0) { - lderr(cct) << "cannot enable journaling: " << cpp_strerror(r) << dendl; - return r; - } - } - C_SaferCond ctx; auto req = mirror::EnableRequest::create(ictx, &ctx); req->send(); @@ -530,12 +513,6 @@ int Mirror::image_disable(I *ictx, bool force) { rollback = true; return r; } - - r = ictx->operations->update_features(RBD_FEATURE_JOURNALING, false); - if (r < 0) { - lderr(cct) << "cannot disable journaling: " << cpp_strerror(r) << dendl; - // not fatal - } } return 0; @@ -874,6 +851,8 @@ int Mirror::mode_set(librados::IoCtx& io_ctx, return r; } + // Enable only journal based mirroring + if ((features & RBD_FEATURE_JOURNALING) != 0) { I *img_ctx = I::create("", img_pair.second, nullptr, io_ctx, false); r = img_ctx->state->open(0); diff --git a/src/librbd/api/Trash.cc b/src/librbd/api/Trash.cc index 88de92e2d17..d37d3300579 100644 --- a/src/librbd/api/Trash.cc +++ b/src/librbd/api/Trash.cc @@ -43,10 +43,6 @@ namespace { template int disable_mirroring(I *ictx) { - if (!ictx->test_features(RBD_FEATURE_JOURNALING)) { - return 0; - } - cls::rbd::MirrorImage mirror_image; int r = cls_client::mirror_image_get(&ictx->md_ctx, ictx->id, &mirror_image); if (r == -ENOENT) { @@ -88,10 +84,6 @@ int enable_mirroring(IoCtx &io_ctx, const std::string &image_id) { return r; } - if ((features & RBD_FEATURE_JOURNALING) == 0) { - return 0; - } - cls::rbd::MirrorMode mirror_mode; r = cls_client::mirror_mode_get(&io_ctx, &mirror_mode); if (r < 0 && r != -ENOENT) { diff --git a/src/librbd/image/PreRemoveRequest.cc b/src/librbd/image/PreRemoveRequest.cc index f67ca99fd0b..5b1b7dd18dc 100644 --- a/src/librbd/image/PreRemoveRequest.cc +++ b/src/librbd/image/PreRemoveRequest.cc @@ -26,6 +26,8 @@ bool auto_delete_snapshot(const SnapInfo& snap_info) { snap_info.snap_namespace); switch (snap_namespace_type) { case cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH: + case cls::rbd::SNAPSHOT_NAMESPACE_TYPE_MIRROR_PRIMARY: + case cls::rbd::SNAPSHOT_NAMESPACE_TYPE_MIRROR_NON_PRIMARY: return true; default: return false; diff --git a/src/librbd/mirror/DemoteRequest.cc b/src/librbd/mirror/DemoteRequest.cc index f075076621e..171b86b1f89 100644 --- a/src/librbd/mirror/DemoteRequest.cc +++ b/src/librbd/mirror/DemoteRequest.cc @@ -11,6 +11,7 @@ #include "librbd/Journal.h" #include "librbd/Utils.h" #include "librbd/mirror/GetInfoRequest.h" +#include "librbd/mirror/snapshot/DemoteRequest.h" #define dout_subsys ceph_subsys_rbd #undef dout_prefix @@ -44,7 +45,7 @@ void DemoteRequest::handle_get_info(int r) { CephContext *cct = m_image_ctx.cct; ldout(cct, 20) << "r=" << r << dendl; - if (r < 0) { + if (r < 0 && r != -ENOENT) { lderr(cct) << "failed to retrieve mirroring state: " << cpp_strerror(r) << dendl; finish(r); @@ -69,8 +70,12 @@ void DemoteRequest::acquire_lock() { m_image_ctx.owner_lock.lock_shared(); if (m_image_ctx.exclusive_lock == nullptr) { m_image_ctx.owner_lock.unlock_shared(); - lderr(cct) << "exclusive lock is not active" << dendl; - finish(-EINVAL); + if (m_mirror_image.mode == cls::rbd::MIRROR_IMAGE_MODE_JOURNAL) { + lderr(cct) << "exclusive lock is not active" << dendl; + finish(-EINVAL); + } else { + demote(); + } return; } @@ -126,7 +131,16 @@ void DemoteRequest::demote() { auto ctx = create_context_callback< DemoteRequest, &DemoteRequest::handle_demote>(this); - Journal::demote(&m_image_ctx, ctx); + if (m_mirror_image.mode == cls::rbd::MIRROR_IMAGE_MODE_JOURNAL) { + Journal::demote(&m_image_ctx, ctx); + } else if (m_mirror_image.mode == cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT) { + auto req = mirror::snapshot::DemoteRequest::create(&m_image_ctx, ctx); + req->send(); + } else { + lderr(cct) << "unknown image mirror mode: " << m_mirror_image.mode << dendl; + m_ret_val = -EOPNOTSUPP; + release_lock(); + } } template diff --git a/src/librbd/mirror/DisableRequest.cc b/src/librbd/mirror/DisableRequest.cc index 929a09685bd..bdbb28504f6 100644 --- a/src/librbd/mirror/DisableRequest.cc +++ b/src/librbd/mirror/DisableRequest.cc @@ -14,6 +14,7 @@ #include "librbd/Operations.h" #include "librbd/Utils.h" #include "librbd/journal/PromoteRequest.h" +#include "librbd/mirror/GetInfoRequest.h" #define dout_subsys ceph_subsys_rbd #undef dout_prefix @@ -33,77 +34,42 @@ DisableRequest::DisableRequest(I *image_ctx, bool force, bool remove, template void DisableRequest::send() { - send_get_mirror_image(); + send_get_mirror_info(); } template -void DisableRequest::send_get_mirror_image() { +void DisableRequest::send_get_mirror_info() { CephContext *cct = m_image_ctx->cct; ldout(cct, 10) << this << " " << __func__ << dendl; - librados::ObjectReadOperation op; - cls_client::mirror_image_get_start(&op, m_image_ctx->id); using klass = DisableRequest; - librados::AioCompletion *comp = - create_rados_callback(this); - m_out_bl.clear(); - int r = m_image_ctx->md_ctx.aio_operate(RBD_MIRRORING, comp, &op, &m_out_bl); - ceph_assert(r == 0); - comp->release(); + Context *ctx = util::create_context_callback< + klass, &klass::handle_get_mirror_info>(this); + + auto req = GetInfoRequest::create(*m_image_ctx, &m_mirror_image, + &m_promotion_state, ctx); + req->send(); } template -Context *DisableRequest::handle_get_mirror_image(int *result) { +Context *DisableRequest::handle_get_mirror_info(int *result) { CephContext *cct = m_image_ctx->cct; ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl; - if (*result == 0) { - auto iter = m_out_bl.cbegin(); - *result = cls_client::mirror_image_get_finish(&iter, &m_mirror_image); - } - if (*result < 0) { if (*result == -ENOENT) { ldout(cct, 20) << this << " " << __func__ << ": mirroring is not enabled for this image" << dendl; *result = 0; - } else if (*result == -EOPNOTSUPP) { - ldout(cct, 5) << this << " " << __func__ - << ": mirroring is not supported by OSD" << dendl; } else { - lderr(cct) << "failed to retrieve mirror image: " << cpp_strerror(*result) + lderr(cct) << "failed to get mirroring info: " << cpp_strerror(*result) << dendl; } return m_on_finish; } - send_get_tag_owner(); - return nullptr; -} - -template -void DisableRequest::send_get_tag_owner() { - CephContext *cct = m_image_ctx->cct; - ldout(cct, 10) << this << " " << __func__ << dendl; - - using klass = DisableRequest; - Context *ctx = util::create_context_callback< - klass, &klass::handle_get_tag_owner>(this); - - Journal::is_tag_owner(m_image_ctx, &m_is_primary, ctx); -} - -template -Context *DisableRequest::handle_get_tag_owner(int *result) { - CephContext *cct = m_image_ctx->cct; - ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl; - - if (*result < 0) { - lderr(cct) << "failed to check tag ownership: " << cpp_strerror(*result) - << dendl; - return m_on_finish; - } + m_is_primary = (m_promotion_state == PROMOTION_STATE_PRIMARY); if (!m_is_primary && !m_force) { lderr(cct) << "mirrored image is not primary, " @@ -129,7 +95,6 @@ void DisableRequest::send_set_mirror_image() { using klass = DisableRequest; librados::AioCompletion *comp = create_rados_callback(this); - m_out_bl.clear(); int r = m_image_ctx->md_ctx.aio_operate(RBD_MIRRORING, comp, &op); ceph_assert(r == 0); comp->release(); @@ -175,6 +140,33 @@ Context *DisableRequest::handle_notify_mirroring_watcher(int *result) { *result = 0; } + if (m_mirror_image.mode == cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT) { + // remove mirroring snapshots + + bool removing_snapshots = false; + { + std::lock_guard locker{m_lock}; + std::shared_lock image_locker{m_image_ctx->image_lock}; + + for (auto &it : m_image_ctx->snap_info) { + auto &snap_info = it.second; + auto type = cls::rbd::get_snap_namespace_type( + snap_info.snap_namespace); + if (type == cls::rbd::SNAPSHOT_NAMESPACE_TYPE_MIRROR_PRIMARY || + type == cls::rbd::SNAPSHOT_NAMESPACE_TYPE_MIRROR_NON_PRIMARY) { + send_remove_snap("", snap_info.snap_namespace, snap_info.name); + removing_snapshots = true; + } + } + } + + if (!removing_snapshots) { + send_remove_mirror_image(); + } + + return nullptr; + } + send_promote_image(); return nullptr; } @@ -334,13 +326,22 @@ Context *DisableRequest::handle_remove_snap(int *result, m_current_ops[client_id]--; if (*result < 0 && *result != -ENOENT) { - lderr(cct) << - "failed to remove temporary snapshot created by remote peer: " + lderr(cct) << "failed to remove mirroring snapshot: " << cpp_strerror(*result) << dendl; m_ret[client_id] = *result; } if (m_current_ops[client_id] == 0) { + if (m_mirror_image.mode == cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT) { + ceph_assert(client_id.empty()); + m_current_ops.erase(client_id); + if (m_ret[client_id] < 0) { + return m_on_finish; + } + send_remove_mirror_image(); + return nullptr; + } + send_unregister_client(client_id); } @@ -415,7 +416,6 @@ void DisableRequest::send_remove_mirror_image() { using klass = DisableRequest; librados::AioCompletion *comp = create_rados_callback(this); - m_out_bl.clear(); int r = m_image_ctx->md_ctx.aio_operate(RBD_MIRRORING, comp, &op); ceph_assert(r == 0); comp->release(); diff --git a/src/librbd/mirror/DisableRequest.h b/src/librbd/mirror/DisableRequest.h index a3eeee78676..1434d3f3ee8 100644 --- a/src/librbd/mirror/DisableRequest.h +++ b/src/librbd/mirror/DisableRequest.h @@ -8,6 +8,8 @@ #include "common/ceph_mutex.h" #include "cls/journal/cls_journal_types.h" #include "cls/rbd/cls_rbd_types.h" +#include "librbd/mirror/Types.h" + #include #include @@ -39,10 +41,7 @@ private: * * | * v - * GET_MIRROR_IMAGE * * * * * * * * * * * * * * * * * * * * * * * - * | * - * v * - * GET_TAG_OWNER * * * * * * * * * * * * * * * * * * * * * * * * + * GET_MIRROR_INFO * * * * * * * * * * * * * * * * * * * * * * * * | * * v * * SET_MIRROR_IMAGE * * * * * * * * * * * * * * * * * * * * * * * @@ -86,8 +85,8 @@ private: Context *m_on_finish; bool m_is_primary = false; - bufferlist m_out_bl; cls::rbd::MirrorImage m_mirror_image; + PromotionState m_promotion_state = PROMOTION_STATE_NON_PRIMARY; std::set m_clients; std::map m_ret; std::map m_current_ops; @@ -95,11 +94,8 @@ private: mutable ceph::mutex m_lock = ceph::make_mutex("mirror::DisableRequest::m_lock"); - void send_get_mirror_image(); - Context *handle_get_mirror_image(int *result); - - void send_get_tag_owner(); - Context *handle_get_tag_owner(int *result); + void send_get_mirror_info(); + Context *handle_get_mirror_info(int *result); void send_set_mirror_image(); Context *handle_set_mirror_image(int *result); diff --git a/src/librbd/mirror/EnableRequest.cc b/src/librbd/mirror/EnableRequest.cc index b0f7ea18725..c94ad43bd59 100644 --- a/src/librbd/mirror/EnableRequest.cc +++ b/src/librbd/mirror/EnableRequest.cc @@ -79,7 +79,6 @@ Context *EnableRequest::handle_get_mirror_image(int *result) { } *result = 0; - m_mirror_image.state = cls::rbd::MIRROR_IMAGE_STATE_ENABLED; if (m_non_primary_global_image_id.empty()) { uuid_d uuid_gen; uuid_gen.generate_random(); @@ -88,13 +87,58 @@ Context *EnableRequest::handle_get_mirror_image(int *result) { m_mirror_image.global_image_id = m_non_primary_global_image_id; } + send_get_features(); + return nullptr; +} + +template +void EnableRequest::send_get_features() { + ldout(m_cct, 10) << this << " " << __func__ << dendl; + + librados::ObjectReadOperation op; + cls_client::get_features_start(&op, true); + + using klass = EnableRequest; + librados::AioCompletion *comp = + create_rados_callback(this); + m_out_bl.clear(); + int r = m_io_ctx.aio_operate(util::header_name(m_image_id), comp, &op, + &m_out_bl); + ceph_assert(r == 0); + comp->release(); +} + +template +Context *EnableRequest::handle_get_features(int *result) { + ldout(m_cct, 10) << this << " " << __func__ << ": r=" << *result << dendl; + + uint64_t features, incompatible_features; + if (*result == 0) { + auto iter = m_out_bl.cbegin(); + *result = cls_client::get_features_finish(&iter, &features, + &incompatible_features); + } + + if (*result != 0) { + lderr(m_cct) << "failed to retrieve image features: " + << cpp_strerror(*result) << dendl; + return m_on_finish; + } + + // TODO: be explicit about the image mirror mode + + m_mirror_image.mode = (features & RBD_FEATURE_JOURNALING) != 0 ? + cls::rbd::MIRROR_IMAGE_MODE_JOURNAL : cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT; + m_mirror_image.state = cls::rbd::MIRROR_IMAGE_STATE_ENABLED; + send_get_tag_owner(); return nullptr; } template void EnableRequest::send_get_tag_owner() { - if (!m_non_primary_global_image_id.empty()) { + if (m_mirror_image.mode == cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT || + !m_non_primary_global_image_id.empty()) { send_set_mirror_image(); return; } diff --git a/src/librbd/mirror/EnableRequest.h b/src/librbd/mirror/EnableRequest.h index 965c2a36b8c..66b0c1f6859 100644 --- a/src/librbd/mirror/EnableRequest.h +++ b/src/librbd/mirror/EnableRequest.h @@ -46,9 +46,12 @@ private: * GET_MIRROR_IMAGE * * * * * * * * | * (on error) * v * - * GET_TAG_OWNER * * * * * * * * + * GET_FEATURES * * * * * * * * * * | * * v * + * GET_TAG_OWNER * * * * * * * * + * | (skip if not needed) * + * v * * SET_MIRROR_IMAGE * * * * * * * * | * * v * @@ -78,6 +81,9 @@ private: void send_get_mirror_image(); Context *handle_get_mirror_image(int *result); + void send_get_features(); + Context *handle_get_features(int *result); + void send_get_tag_owner(); Context *handle_get_tag_owner(int *result); diff --git a/src/librbd/mirror/GetInfoRequest.cc b/src/librbd/mirror/GetInfoRequest.cc index 1bd692ae3ea..74ca27c5918 100644 --- a/src/librbd/mirror/GetInfoRequest.cc +++ b/src/librbd/mirror/GetInfoRequest.cc @@ -82,10 +82,9 @@ void GetInfoRequest::handle_get_mirror_image(int r) { r = cls_client::mirror_image_get_finish(&iter, m_mirror_image); } - if (r == -ENOENT || - m_mirror_image->state != cls::rbd::MIRROR_IMAGE_STATE_ENABLED) { + if (r == -ENOENT) { ldout(cct, 20) << "mirroring is disabled" << dendl; - finish(0); + finish(r); return; } else if (r < 0) { lderr(cct) << "failed to retrieve mirroring state: " << cpp_strerror(r) @@ -94,22 +93,30 @@ void GetInfoRequest::handle_get_mirror_image(int r) { return; } - get_tag_owner(); + if (m_mirror_image->mode == cls::rbd::MIRROR_IMAGE_MODE_JOURNAL) { + get_journal_tag_owner(); + } else if (m_mirror_image->mode == cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT) { + get_snapshot_promotion_state(); + } else { + ldout(cct, 20) << "unknown mirror image mode: " << m_mirror_image->mode + << dendl; + finish(-EOPNOTSUPP); + } } template -void GetInfoRequest::get_tag_owner() { +void GetInfoRequest::get_journal_tag_owner() { CephContext *cct = m_image_ctx.cct; ldout(cct, 20) << dendl; auto ctx = create_context_callback< - GetInfoRequest, &GetInfoRequest::handle_get_tag_owner>(this); + GetInfoRequest, &GetInfoRequest::handle_get_journal_tag_owner>(this); Journal::get_tag_owner(m_image_ctx.md_ctx, m_image_ctx.id, &m_mirror_uuid, m_image_ctx.op_work_queue, ctx); } template -void GetInfoRequest::handle_get_tag_owner(int r) { +void GetInfoRequest::handle_get_journal_tag_owner(int r) { CephContext *cct = m_image_ctx.cct; ldout(cct, 20) << "r=" << r << dendl; @@ -129,6 +136,41 @@ void GetInfoRequest::handle_get_tag_owner(int r) { finish(0); } +template +void GetInfoRequest::get_snapshot_promotion_state() { + CephContext *cct = m_image_ctx.cct; + ldout(cct, 20) << dendl; + + *m_promotion_state = PROMOTION_STATE_PRIMARY; + { + std::shared_lock image_locker{m_image_ctx.image_lock}; + for (auto it = m_image_ctx.snap_info.rbegin(); + it != m_image_ctx.snap_info.rend(); it++) { + auto primary = boost::get( + &it->second.snap_namespace); + if (primary != nullptr) { + if (primary->demoted) { + *m_promotion_state = PROMOTION_STATE_ORPHAN; + } + break; + } + auto non_primary = + boost::get( + &it->second.snap_namespace); + if (non_primary != nullptr) { + if (non_primary->primary_mirror_uuid.empty()) { + *m_promotion_state = PROMOTION_STATE_ORPHAN; + } else { + *m_promotion_state = PROMOTION_STATE_NON_PRIMARY; + } + break; + } + } + } + finish(0); +} + + template void GetInfoRequest::finish(int r) { CephContext *cct = m_image_ctx.cct; diff --git a/src/librbd/mirror/GetInfoRequest.h b/src/librbd/mirror/GetInfoRequest.h index c37ea581836..d694bbd3920 100644 --- a/src/librbd/mirror/GetInfoRequest.h +++ b/src/librbd/mirror/GetInfoRequest.h @@ -49,7 +49,7 @@ private: * GET_MIRROR_IMAGE * | * v - * GET_TAG_OWNER + * GET_JOURNAL_TAG_OWNER (if journal) * | * v * @@ -71,8 +71,10 @@ private: void get_mirror_image(); void handle_get_mirror_image(int r); - void get_tag_owner(); - void handle_get_tag_owner(int r); + void get_journal_tag_owner(); + void handle_get_journal_tag_owner(int r); + + void get_snapshot_promotion_state(); void finish(int r); diff --git a/src/librbd/mirror/PromoteRequest.cc b/src/librbd/mirror/PromoteRequest.cc index 5603cb13423..2905d13bff6 100644 --- a/src/librbd/mirror/PromoteRequest.cc +++ b/src/librbd/mirror/PromoteRequest.cc @@ -10,6 +10,7 @@ #include "librbd/Journal.h" #include "librbd/Utils.h" #include "librbd/mirror/GetInfoRequest.h" +#include "librbd/mirror/snapshot/PromoteRequest.h" #define dout_subsys ceph_subsys_rbd #undef dout_prefix @@ -72,7 +73,15 @@ void PromoteRequest::promote() { auto ctx = create_context_callback< PromoteRequest, &PromoteRequest::handle_promote>(this); - Journal::promote(&m_image_ctx, ctx); + if (m_mirror_image.mode == cls::rbd::MIRROR_IMAGE_MODE_JOURNAL) { + Journal::promote(&m_image_ctx, ctx); + } else if (m_mirror_image.mode == cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT) { + auto req = mirror::snapshot::PromoteRequest::create(&m_image_ctx, ctx); + req->send(); + } else { + lderr(cct) << "unknown image mirror mode: " << m_mirror_image.mode << dendl; + finish(-EOPNOTSUPP); + } } template diff --git a/src/librbd/mirror/snapshot/DemoteRequest.h b/src/librbd/mirror/snapshot/DemoteRequest.h index 054a9dce12d..f075561e3ef 100644 --- a/src/librbd/mirror/snapshot/DemoteRequest.h +++ b/src/librbd/mirror/snapshot/DemoteRequest.h @@ -21,13 +21,12 @@ namespace snapshot { template class DemoteRequest { public: - static DemoteRequest *create(ImageCtxT *image_ctx, bool force, - Context *on_finish) { - return new DemoteRequest(image_ctx, force, on_finish); + static DemoteRequest *create(ImageCtxT *image_ctx, Context *on_finish) { + return new DemoteRequest(image_ctx, on_finish); } - DemoteRequest(ImageCtxT *image_ctx, bool force, Context *on_finish) - : m_image_ctx(image_ctx), m_force(force), m_on_finish(on_finish) { + DemoteRequest(ImageCtxT *image_ctx, Context *on_finish) + : m_image_ctx(image_ctx), m_on_finish(on_finish) { } void send(); @@ -51,7 +50,6 @@ private: */ ImageCtxT *m_image_ctx; - bool m_force; Context *m_on_finish; void refresh_image(); diff --git a/src/librbd/mirror/snapshot/PromoteRequest.h b/src/librbd/mirror/snapshot/PromoteRequest.h index ef6e93301d7..7efd921d8d1 100644 --- a/src/librbd/mirror/snapshot/PromoteRequest.h +++ b/src/librbd/mirror/snapshot/PromoteRequest.h @@ -21,13 +21,12 @@ namespace snapshot { template class PromoteRequest { public: - static PromoteRequest *create(ImageCtxT *image_ctx, bool force, - Context *on_finish) { - return new PromoteRequest(image_ctx, force, on_finish); + static PromoteRequest *create(ImageCtxT *image_ctx, Context *on_finish) { + return new PromoteRequest(image_ctx, on_finish); } - PromoteRequest(ImageCtxT *image_ctx, bool force, Context *on_finish) - : m_image_ctx(image_ctx), m_force(force), m_on_finish(on_finish) { + PromoteRequest(ImageCtxT *image_ctx, Context *on_finish) + : m_image_ctx(image_ctx), m_on_finish(on_finish) { } void send(); @@ -51,7 +50,6 @@ private: */ ImageCtxT *m_image_ctx; - bool m_force; Context *m_on_finish; void refresh_image(); diff --git a/src/librbd/operation/EnableFeaturesRequest.cc b/src/librbd/operation/EnableFeaturesRequest.cc index c01cca7ecdc..c85c56f86d4 100644 --- a/src/librbd/operation/EnableFeaturesRequest.cc +++ b/src/librbd/operation/EnableFeaturesRequest.cc @@ -12,6 +12,7 @@ #include "librbd/image/SetFlagsRequest.h" #include "librbd/io/ImageRequestWQ.h" #include "librbd/journal/CreateRequest.h" +#include "librbd/mirror/DisableRequest.h" #include "librbd/mirror/EnableRequest.h" #include "librbd/object_map/CreateRequest.h" @@ -118,10 +119,7 @@ void EnableFeaturesRequest::send_get_mirror_mode() { CephContext *cct = image_ctx.cct; if ((m_features & RBD_FEATURE_JOURNALING) == 0) { - Context *ctx = create_context_callback< - EnableFeaturesRequest, - &EnableFeaturesRequest::handle_get_mirror_mode>(this); - ctx->complete(-ENOENT); + send_get_mirror_image(); return; } @@ -145,10 +143,9 @@ Context *EnableFeaturesRequest::handle_get_mirror_mode(int *result) { CephContext *cct = image_ctx.cct; ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; - cls::rbd::MirrorMode mirror_mode = cls::rbd::MIRROR_MODE_DISABLED; if (*result == 0) { auto it = m_out_bl.cbegin(); - *result = cls_client::mirror_mode_get_finish(&it, &mirror_mode); + *result = cls_client::mirror_mode_get_finish(&it, &m_mirror_mode); } else if (*result == -ENOENT) { *result = 0; } @@ -159,7 +156,67 @@ Context *EnableFeaturesRequest::handle_get_mirror_mode(int *result) { return handle_finish(*result); } - m_enable_mirroring = (mirror_mode == cls::rbd::MIRROR_MODE_POOL); + if (m_mirror_mode == cls::rbd::MIRROR_MODE_POOL) { + m_enable_mirroring = true; + } + + send_get_mirror_image(); + return nullptr; +} + +template +void EnableFeaturesRequest::send_get_mirror_image() { + I &image_ctx = this->m_image_ctx; + CephContext *cct = image_ctx.cct; + + if (m_mirror_mode != cls::rbd::MIRROR_MODE_IMAGE) { + Context *ctx = create_context_callback< + EnableFeaturesRequest, + &EnableFeaturesRequest::handle_get_mirror_image>(this); + ctx->complete(-ENOENT); + return; + } + + ldout(cct, 20) << this << " " << __func__ << dendl; + + librados::ObjectReadOperation op; + cls_client::mirror_image_get_start(&op, image_ctx.id); + + using klass = EnableFeaturesRequest; + librados::AioCompletion *comp = + create_rados_callback(this); + m_out_bl.clear(); + int r = image_ctx.md_ctx.aio_operate(RBD_MIRRORING, comp, &op, &m_out_bl); + ceph_assert(r == 0); + comp->release(); +} + +template +Context *EnableFeaturesRequest::handle_get_mirror_image(int *result) { + I &image_ctx = this->m_image_ctx; + CephContext *cct = image_ctx.cct; + ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; + + cls::rbd::MirrorImage mirror_image; + if (*result == 0) { + auto it = m_out_bl.cbegin(); + *result = cls_client::mirror_image_get_finish(&it, &mirror_image); + } else if (*result == -ENOENT) { + *result = 0; + } + + if (*result < 0) { + lderr(cct) << "failed to retrieve mirror image info: " + << cpp_strerror(*result) << dendl; + return handle_finish(*result); + } + + if (mirror_image.mode == cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT) { + lderr(cct) << "cannot enable journaling: image snapshot mirroring enabled" + << dendl; + *result = -EINVAL; + return handle_finish(*result); + } bool create_journal = false; do { @@ -408,13 +465,14 @@ template void EnableFeaturesRequest::send_enable_mirror_image() { I &image_ctx = this->m_image_ctx; CephContext *cct = image_ctx.cct; - ldout(cct, 20) << this << " " << __func__ << dendl; if (!m_enable_mirroring) { send_notify_update(); return; } + ldout(cct, 20) << this << " " << __func__ << dendl; + Context *ctx = create_context_callback< EnableFeaturesRequest, &EnableFeaturesRequest::handle_enable_mirror_image>(this); diff --git a/src/librbd/operation/EnableFeaturesRequest.h b/src/librbd/operation/EnableFeaturesRequest.h index 1c91b4dc72a..d1bfe4ad424 100644 --- a/src/librbd/operation/EnableFeaturesRequest.h +++ b/src/librbd/operation/EnableFeaturesRequest.h @@ -4,6 +4,8 @@ #ifndef CEPH_LIBRBD_OPERATION_ENABLE_FEATURES_REQUEST_H #define CEPH_LIBRBD_OPERATION_ENABLE_FEATURES_REQUEST_H +#include "cls/rbd/cls_rbd_types.h" + #include "librbd/operation/Request.h" class Context; @@ -52,8 +54,11 @@ private: * STATE_BLOCK_WRITES * | * v - * STATE_GET_MIRROR_MODE - * | + * STATE_GET_MIRROR_MODE (skip if not + * | enabling journaling) + * v + * STATE_GET_MIRROR_IMAGE (skip if mirror mode + * | is not IMAGE) * v * STATE_CREATE_JOURNAL (skip if not * | required) @@ -70,9 +75,9 @@ private: * STATE_CREATE_OBJECT_MAP (skip if not * | required) * v - * STATE_ENABLE_MIRROR_IMAGE - * | - * V + * STATE_ENABLE_MIRROR_IMAGE (skip if not + * | required) + * v * STATE_NOTIFY_UPDATE * | * | (unblock writes) @@ -82,6 +87,8 @@ private: * */ + cls::rbd::MirrorMode m_mirror_mode = cls::rbd::MIRROR_MODE_DISABLED; + uint64_t m_features; bool m_enable_mirroring = false; @@ -103,6 +110,9 @@ private: void send_get_mirror_mode(); Context *handle_get_mirror_mode(int *result); + void send_get_mirror_image(); + Context *handle_get_mirror_image(int *result); + void send_create_journal(); Context *handle_create_journal(int *result); diff --git a/src/test/librbd/mirror/test_mock_DisableRequest.cc b/src/test/librbd/mirror/test_mock_DisableRequest.cc index 84ef7cab2c6..688bddb99dc 100644 --- a/src/test/librbd/mirror/test_mock_DisableRequest.cc +++ b/src/test/librbd/mirror/test_mock_DisableRequest.cc @@ -10,6 +10,7 @@ #include "librbd/MirroringWatcher.h" #include "librbd/journal/PromoteRequest.h" #include "librbd/mirror/DisableRequest.h" +#include "librbd/mirror/GetInfoRequest.h" namespace librbd { @@ -22,24 +23,6 @@ struct MockTestImageCtx : public MockImageCtx { } // anonymous namespace -template <> -struct Journal { - static Journal *s_instance; - static void is_tag_owner(librbd::MockTestImageCtx *, bool *is_primary, - Context *on_finish) { - ceph_assert(s_instance != nullptr); - s_instance->is_tag_owner(is_primary, on_finish); - } - - Journal() { - s_instance = this; - } - - MOCK_METHOD2(is_tag_owner, void(bool*, Context*)); -}; - -Journal *Journal::s_instance = nullptr; - template <> struct MirroringWatcher { static MirroringWatcher *s_instance; @@ -89,20 +72,53 @@ PromoteRequest *PromoteRequest +struct GetInfoRequest { + cls::rbd::MirrorImage *mirror_image; + PromotionState *promotion_state; + Context *on_finish = nullptr; + static GetInfoRequest *s_instance; + static GetInfoRequest *create(librbd::MockTestImageCtx &, + cls::rbd::MirrorImage *mirror_image, + PromotionState *promotion_state, + Context *on_finish) { + ceph_assert(s_instance != nullptr); + s_instance->mirror_image = mirror_image; + s_instance->promotion_state = promotion_state; + s_instance->on_finish = on_finish; + return s_instance; + } + + GetInfoRequest() { + s_instance = this; + } + + MOCK_METHOD0(send, void()); +}; + +GetInfoRequest *GetInfoRequest::s_instance = nullptr; + +} // namespace mirror } // namespace librbd // template definitions #include "librbd/mirror/DisableRequest.cc" template class librbd::mirror::DisableRequest; +ACTION_P(TestFeatures, image_ctx) { + return ((image_ctx->features & arg0) != 0); +} + namespace librbd { namespace mirror { using ::testing::_; using ::testing::DoAll; using ::testing::InSequence; +using ::testing::Invoke; using ::testing::Return; -using ::testing::SetArgPointee; using ::testing::StrEq; using ::testing::WithArg; @@ -112,27 +128,24 @@ public: typedef Journal MockJournal; typedef MirroringWatcher MockMirroringWatcher; typedef journal::PromoteRequest MockPromoteRequest; - - void expect_get_mirror_image(MockTestImageCtx &mock_image_ctx, - const cls::rbd::MirrorImage &mirror_image, - int r) { - using ceph::encode; - bufferlist bl; - encode(mirror_image, bl); - - EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), - exec(RBD_MIRRORING, _, StrEq("rbd"), StrEq("mirror_image_get"), - _, _, _)) - .WillOnce(DoAll(WithArg<5>(CopyInBufferlist(bl)), - Return(r))); - } - - void expect_is_tag_owner(MockTestImageCtx &mock_image_ctx, - MockJournal &mock_journal, - bool is_primary, int r) { - EXPECT_CALL(mock_journal, is_tag_owner(_, _)) - .WillOnce(DoAll(SetArgPointee<0>(is_primary), - WithArg<1>(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)))); + typedef mirror::GetInfoRequest MockGetInfoRequest; + + void expect_get_mirror_info(MockTestImageCtx &mock_image_ctx, + MockGetInfoRequest &mock_get_info_request, + const cls::rbd::MirrorImage &mirror_image, + PromotionState promotion_state, int r) { + + EXPECT_CALL(mock_get_info_request, send()) + .WillOnce( + Invoke([this, &mock_image_ctx, &mock_get_info_request, mirror_image, + promotion_state, r]() { + if (r == 0) { + *mock_get_info_request.mirror_image = mirror_image; + *mock_get_info_request.promotion_state = promotion_state; + } + mock_image_ctx.op_work_queue->queue( + mock_get_info_request.on_finish, r); + })); } void expect_set_mirror_image(MockTestImageCtx &mock_image_ctx, int r) { @@ -215,7 +228,6 @@ TEST_F(TestMockMirrorDisableRequest, Success) { ASSERT_EQ(0, open_image(m_image_name, &ictx)); MockTestImageCtx mock_image_ctx(*ictx); - MockJournal mock_journal; MockMirroringWatcher mock_mirroring_watcher; expect_op_work_queue(mock_image_ctx); @@ -223,10 +235,12 @@ TEST_F(TestMockMirrorDisableRequest, Success) { expect_snap_remove(mock_image_ctx, "snap 2", 0); InSequence seq; - expect_get_mirror_image( - mock_image_ctx, {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id", - cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, 0); - expect_is_tag_owner(mock_image_ctx, mock_journal, true, 0); + + MockGetInfoRequest mock_get_info_request; + expect_get_mirror_info( + mock_image_ctx, mock_get_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, PROMOTION_STATE_PRIMARY, 0); expect_set_mirror_image(mock_image_ctx, 0); expect_notify_image_updated(mock_image_ctx, mock_mirroring_watcher, cls::rbd::MIRROR_IMAGE_STATE_DISABLING, @@ -261,16 +275,17 @@ TEST_F(TestMockMirrorDisableRequest, SuccessNoRemove) { ASSERT_EQ(0, open_image(m_image_name, &ictx)); MockTestImageCtx mock_image_ctx(*ictx); - MockJournal mock_journal; MockMirroringWatcher mock_mirroring_watcher; expect_op_work_queue(mock_image_ctx); InSequence seq; - expect_get_mirror_image( - mock_image_ctx, {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id", - cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, 0); - expect_is_tag_owner(mock_image_ctx, mock_journal, true, 0); + + MockGetInfoRequest mock_get_info_request; + expect_get_mirror_info( + mock_image_ctx, mock_get_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, PROMOTION_STATE_PRIMARY, 0); expect_set_mirror_image(mock_image_ctx, 0); expect_notify_image_updated(mock_image_ctx, mock_mirroring_watcher, cls::rbd::MIRROR_IMAGE_STATE_DISABLING, @@ -290,17 +305,18 @@ TEST_F(TestMockMirrorDisableRequest, SuccessNonPrimary) { ASSERT_EQ(0, open_image(m_image_name, &ictx)); MockTestImageCtx mock_image_ctx(*ictx); - MockJournal mock_journal; MockMirroringWatcher mock_mirroring_watcher; MockPromoteRequest mock_promote_request; expect_op_work_queue(mock_image_ctx); InSequence seq; - expect_get_mirror_image( - mock_image_ctx, {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id", - cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, 0); - expect_is_tag_owner(mock_image_ctx, mock_journal, false, 0); + + MockGetInfoRequest mock_get_info_request; + expect_get_mirror_info( + mock_image_ctx, mock_get_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, PROMOTION_STATE_NON_PRIMARY, 0); expect_set_mirror_image(mock_image_ctx, 0); expect_notify_image_updated(mock_image_ctx, mock_mirroring_watcher, cls::rbd::MIRROR_IMAGE_STATE_DISABLING, @@ -325,16 +341,17 @@ TEST_F(TestMockMirrorDisableRequest, NonPrimaryError) { ASSERT_EQ(0, open_image(m_image_name, &ictx)); MockTestImageCtx mock_image_ctx(*ictx); - MockJournal mock_journal; MockMirroringWatcher mock_mirroring_watcher; expect_op_work_queue(mock_image_ctx); InSequence seq; - expect_get_mirror_image( - mock_image_ctx, {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id", - cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, 0); - expect_is_tag_owner(mock_image_ctx, mock_journal, false, 0); + + MockGetInfoRequest mock_get_info_request; + expect_get_mirror_info( + mock_image_ctx, mock_get_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, PROMOTION_STATE_NON_PRIMARY, 0); C_SaferCond ctx; auto req = new MockDisableRequest(&mock_image_ctx, false, false, &ctx); @@ -342,47 +359,28 @@ TEST_F(TestMockMirrorDisableRequest, NonPrimaryError) { ASSERT_EQ(-EINVAL, ctx.wait()); } -TEST_F(TestMockMirrorDisableRequest, MirrorImageGetError) { +TEST_F(TestMockMirrorDisableRequest, GetMirrorInfoError) { REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); librbd::ImageCtx *ictx; ASSERT_EQ(0, open_image(m_image_name, &ictx)); MockTestImageCtx mock_image_ctx(*ictx); - MockJournal mock_journal; expect_op_work_queue(mock_image_ctx); InSequence seq; - expect_get_mirror_image(mock_image_ctx, {}, -EBADMSG); - - C_SaferCond ctx; - auto req = new MockDisableRequest(&mock_image_ctx, false, true, &ctx); - req->send(); - ASSERT_EQ(-EBADMSG, ctx.wait()); -} - -TEST_F(TestMockMirrorDisableRequest, IsTagOwnerError) { - REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); - librbd::ImageCtx *ictx; - ASSERT_EQ(0, open_image(m_image_name, &ictx)); - - MockTestImageCtx mock_image_ctx(*ictx); - MockJournal mock_journal; - - expect_op_work_queue(mock_image_ctx); - - InSequence seq; - expect_get_mirror_image( - mock_image_ctx, {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id", - cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, 0); - expect_is_tag_owner(mock_image_ctx, mock_journal, true, -EBADMSG); + MockGetInfoRequest mock_get_info_request; + expect_get_mirror_info( + mock_image_ctx, mock_get_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, PROMOTION_STATE_PRIMARY, -EINVAL); C_SaferCond ctx; auto req = new MockDisableRequest(&mock_image_ctx, false, true, &ctx); req->send(); - ASSERT_EQ(-EBADMSG, ctx.wait()); + ASSERT_EQ(-EINVAL, ctx.wait()); } TEST_F(TestMockMirrorDisableRequest, MirrorImageSetError) { @@ -392,15 +390,16 @@ TEST_F(TestMockMirrorDisableRequest, MirrorImageSetError) { ASSERT_EQ(0, open_image(m_image_name, &ictx)); MockTestImageCtx mock_image_ctx(*ictx); - MockJournal mock_journal; expect_op_work_queue(mock_image_ctx); InSequence seq; - expect_get_mirror_image( - mock_image_ctx, {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id", - cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, 0); - expect_is_tag_owner(mock_image_ctx, mock_journal, true, 0); + + MockGetInfoRequest mock_get_info_request; + expect_get_mirror_info( + mock_image_ctx, mock_get_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, PROMOTION_STATE_PRIMARY, 0); expect_set_mirror_image(mock_image_ctx, -ENOENT); C_SaferCond ctx; @@ -416,17 +415,18 @@ TEST_F(TestMockMirrorDisableRequest, JournalPromoteError) { ASSERT_EQ(0, open_image(m_image_name, &ictx)); MockTestImageCtx mock_image_ctx(*ictx); - MockJournal mock_journal; MockMirroringWatcher mock_mirroring_watcher; MockPromoteRequest mock_promote_request; expect_op_work_queue(mock_image_ctx); InSequence seq; - expect_get_mirror_image( - mock_image_ctx, {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id", - cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, 0); - expect_is_tag_owner(mock_image_ctx, mock_journal, false, 0); + + MockGetInfoRequest mock_get_info_request; + expect_get_mirror_info( + mock_image_ctx, mock_get_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, PROMOTION_STATE_NON_PRIMARY, 0); expect_set_mirror_image(mock_image_ctx, 0); expect_notify_image_updated(mock_image_ctx, mock_mirroring_watcher, cls::rbd::MIRROR_IMAGE_STATE_DISABLING, @@ -446,16 +446,17 @@ TEST_F(TestMockMirrorDisableRequest, JournalClientListError) { ASSERT_EQ(0, open_image(m_image_name, &ictx)); MockTestImageCtx mock_image_ctx(*ictx); - MockJournal mock_journal; MockMirroringWatcher mock_mirroring_watcher; expect_op_work_queue(mock_image_ctx); InSequence seq; - expect_get_mirror_image( - mock_image_ctx, {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id", - cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, 0); - expect_is_tag_owner(mock_image_ctx, mock_journal, true, 0); + + MockGetInfoRequest mock_get_info_request; + expect_get_mirror_info( + mock_image_ctx, mock_get_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, PROMOTION_STATE_PRIMARY, 0); expect_set_mirror_image(mock_image_ctx, 0); expect_notify_image_updated(mock_image_ctx, mock_mirroring_watcher, cls::rbd::MIRROR_IMAGE_STATE_DISABLING, @@ -475,7 +476,6 @@ TEST_F(TestMockMirrorDisableRequest, SnapRemoveError) { ASSERT_EQ(0, open_image(m_image_name, &ictx)); MockTestImageCtx mock_image_ctx(*ictx); - MockJournal mock_journal; MockMirroringWatcher mock_mirroring_watcher; expect_op_work_queue(mock_image_ctx); @@ -483,10 +483,12 @@ TEST_F(TestMockMirrorDisableRequest, SnapRemoveError) { expect_snap_remove(mock_image_ctx, "snap 2", -EPERM); InSequence seq; - expect_get_mirror_image( - mock_image_ctx, {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id", - cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, 0); - expect_is_tag_owner(mock_image_ctx, mock_journal, true, 0); + + MockGetInfoRequest mock_get_info_request; + expect_get_mirror_info( + mock_image_ctx, mock_get_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, PROMOTION_STATE_PRIMARY, 0); expect_set_mirror_image(mock_image_ctx, 0); expect_notify_image_updated(mock_image_ctx, mock_mirroring_watcher, cls::rbd::MIRROR_IMAGE_STATE_DISABLING, @@ -515,7 +517,6 @@ TEST_F(TestMockMirrorDisableRequest, JournalClientUnregisterError) { ASSERT_EQ(0, open_image(m_image_name, &ictx)); MockTestImageCtx mock_image_ctx(*ictx); - MockJournal mock_journal; MockMirroringWatcher mock_mirroring_watcher; expect_op_work_queue(mock_image_ctx); @@ -523,10 +524,12 @@ TEST_F(TestMockMirrorDisableRequest, JournalClientUnregisterError) { expect_snap_remove(mock_image_ctx, "snap 2", 0); InSequence seq; - expect_get_mirror_image( - mock_image_ctx, {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id", - cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, 0); - expect_is_tag_owner(mock_image_ctx, mock_journal, true, 0); + + MockGetInfoRequest mock_get_info_request; + expect_get_mirror_info( + mock_image_ctx, mock_get_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, PROMOTION_STATE_PRIMARY, 0); expect_set_mirror_image(mock_image_ctx, 0); expect_notify_image_updated(mock_image_ctx, mock_mirroring_watcher, cls::rbd::MIRROR_IMAGE_STATE_DISABLING, @@ -556,16 +559,17 @@ TEST_F(TestMockMirrorDisableRequest, MirrorImageRemoveError) { ASSERT_EQ(0, open_image(m_image_name, &ictx)); MockTestImageCtx mock_image_ctx(*ictx); - MockJournal mock_journal; MockMirroringWatcher mock_mirroring_watcher; expect_op_work_queue(mock_image_ctx); InSequence seq; - expect_get_mirror_image( - mock_image_ctx, {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id", - cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, 0); - expect_is_tag_owner(mock_image_ctx, mock_journal, true, 0); + + MockGetInfoRequest mock_get_info_request; + expect_get_mirror_info( + mock_image_ctx, mock_get_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, PROMOTION_STATE_PRIMARY, 0); expect_set_mirror_image(mock_image_ctx, 0); expect_notify_image_updated(mock_image_ctx, mock_mirroring_watcher, cls::rbd::MIRROR_IMAGE_STATE_DISABLING, @@ -581,4 +585,3 @@ TEST_F(TestMockMirrorDisableRequest, MirrorImageRemoveError) { } // namespace mirror } // namespace librbd - diff --git a/src/test/librbd/operation/test_mock_DisableFeaturesRequest.cc b/src/test/librbd/operation/test_mock_DisableFeaturesRequest.cc index b437f55b736..78977ae7655 100644 --- a/src/test/librbd/operation/test_mock_DisableFeaturesRequest.cc +++ b/src/test/librbd/operation/test_mock_DisableFeaturesRequest.cc @@ -6,6 +6,7 @@ #include "test/librbd/mock/MockImageCtx.h" #include "test/librbd/mock/MockJournalPolicy.h" #include "cls/rbd/cls_rbd_client.h" +#include "librbd/api/Mirror.h" #include "librbd/internal.h" #include "librbd/image/SetFlagsRequest.h" #include "librbd/io/AioCompletion.h" @@ -174,20 +175,21 @@ public: typedef librbd::object_map::RemoveRequest MockRemoveObjectMapRequest; typedef DisableFeaturesRequest MockDisableFeaturesRequest; - class PoolMirrorModeEnabler { + class MirrorModeEnabler { public: - PoolMirrorModeEnabler(librados::IoCtx &ioctx) : m_ioctx(ioctx) { + MirrorModeEnabler(librados::IoCtx &ioctx, cls::rbd::MirrorMode mirror_mode) + : m_ioctx(ioctx), m_mirror_mode(mirror_mode) { EXPECT_EQ(0, librbd::cls_client::mirror_uuid_set(&m_ioctx, "test-uuid")); - EXPECT_EQ(0, librbd::cls_client::mirror_mode_set( - &m_ioctx, cls::rbd::MIRROR_MODE_POOL)); + EXPECT_EQ(0, librbd::cls_client::mirror_mode_set(&m_ioctx, m_mirror_mode)); } - ~PoolMirrorModeEnabler() { + ~MirrorModeEnabler() { EXPECT_EQ(0, librbd::cls_client::mirror_mode_set( - &m_ioctx, cls::rbd::MIRROR_MODE_DISABLED)); + &m_ioctx, cls::rbd::MIRROR_MODE_DISABLED)); } private: librados::IoCtx &m_ioctx; + cls::rbd::MirrorMode m_mirror_mode; }; void expect_prepare_lock(MockOperationImageCtx &mock_image_ctx) { @@ -432,9 +434,11 @@ TEST_F(TestMockOperationDisableFeaturesRequest, ObjectMapError) { ASSERT_EQ(-EINVAL, cond_ctx.wait()); } -TEST_F(TestMockOperationDisableFeaturesRequest, Mirroring) { +TEST_F(TestMockOperationDisableFeaturesRequest, PoolMirroring) { REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); + MirrorModeEnabler mirror_mode_enabler(m_ioctx, cls::rbd::MIRROR_MODE_POOL); + librbd::ImageCtx *ictx; ASSERT_EQ(0, open_image(m_image_name, &ictx)); @@ -475,6 +479,46 @@ TEST_F(TestMockOperationDisableFeaturesRequest, Mirroring) { ASSERT_EQ(0, cond_ctx.wait()); } +TEST_F(TestMockOperationDisableFeaturesRequest, ImageMirroring) { + REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); + + MirrorModeEnabler mirror_mode_enabler(m_ioctx, cls::rbd::MIRROR_MODE_IMAGE); + + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + ASSERT_EQ(0, librbd::api::Mirror<>::image_enable(ictx, false)); + + MockOperationImageCtx mock_image_ctx(*ictx); + MockExclusiveLock mock_exclusive_lock; + MockJournal mock_journal; + MockObjectMap mock_object_map; + initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal, + mock_object_map); + + expect_verify_lock_ownership(mock_image_ctx); + + MockRemoveJournalRequest mock_remove_journal_request; + MockDisableMirrorRequest mock_disable_mirror_request; + + ::testing::InSequence seq; + expect_prepare_lock(mock_image_ctx); + expect_block_writes(mock_image_ctx); + expect_is_journal_replaying(*mock_image_ctx.journal); + expect_block_requests(mock_image_ctx); + expect_unblock_requests(mock_image_ctx); + expect_unblock_writes(mock_image_ctx); + expect_handle_prepare_lock_complete(mock_image_ctx); + + C_SaferCond cond_ctx; + MockDisableFeaturesRequest *req = new MockDisableFeaturesRequest( + mock_image_ctx, &cond_ctx, 0, RBD_FEATURE_JOURNALING, false); + { + std::shared_lock owner_locker{mock_image_ctx.owner_lock}; + req->send(); + } + ASSERT_EQ(-EINVAL, cond_ctx.wait()); +} + TEST_F(TestMockOperationDisableFeaturesRequest, MirroringError) { REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); diff --git a/src/test/librbd/operation/test_mock_EnableFeaturesRequest.cc b/src/test/librbd/operation/test_mock_EnableFeaturesRequest.cc index 86458c75ac8..f4c4fc5d442 100644 --- a/src/test/librbd/operation/test_mock_EnableFeaturesRequest.cc +++ b/src/test/librbd/operation/test_mock_EnableFeaturesRequest.cc @@ -6,9 +6,11 @@ #include "test/librbd/mock/MockImageCtx.h" #include "cls/rbd/cls_rbd_client.h" #include "librbd/Operations.h" +#include "librbd/api/Mirror.h" #include "librbd/internal.h" #include "librbd/image/SetFlagsRequest.h" #include "librbd/io/AioCompletion.h" +#include "librbd/mirror/DisableRequest.h" #include "librbd/mirror/EnableRequest.h" #include "librbd/journal/CreateRequest.h" #include "librbd/journal/Types.h" @@ -169,20 +171,21 @@ public: typedef librbd::object_map::CreateRequest MockCreateObjectMapRequest; typedef EnableFeaturesRequest MockEnableFeaturesRequest; - class PoolMirrorModeEnabler { + class MirrorModeEnabler { public: - PoolMirrorModeEnabler(librados::IoCtx &ioctx) : m_ioctx(ioctx) { + MirrorModeEnabler(librados::IoCtx &ioctx, cls::rbd::MirrorMode mirror_mode) + : m_ioctx(ioctx), m_mirror_mode(mirror_mode) { EXPECT_EQ(0, librbd::cls_client::mirror_uuid_set(&m_ioctx, "test-uuid")); - EXPECT_EQ(0, librbd::cls_client::mirror_mode_set( - &m_ioctx, cls::rbd::MIRROR_MODE_POOL)); + EXPECT_EQ(0, librbd::cls_client::mirror_mode_set(&m_ioctx, m_mirror_mode)); } - ~PoolMirrorModeEnabler() { + ~MirrorModeEnabler() { EXPECT_EQ(0, librbd::cls_client::mirror_mode_set( &m_ioctx, cls::rbd::MIRROR_MODE_DISABLED)); } private: librados::IoCtx &m_ioctx; + cls::rbd::MirrorMode m_mirror_mode; }; void ensure_features_disabled(librbd::ImageCtx *ictx, @@ -482,9 +485,11 @@ TEST_F(TestMockOperationEnableFeaturesRequest, SetFlagsError) { ASSERT_EQ(-EINVAL, cond_ctx.wait()); } -TEST_F(TestMockOperationEnableFeaturesRequest, Mirroring) { +TEST_F(TestMockOperationEnableFeaturesRequest, PoolMirroring) { REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); + MirrorModeEnabler mirror_mode_enabler(m_ioctx, cls::rbd::MIRROR_MODE_POOL); + librbd::ImageCtx *ictx; ASSERT_EQ(0, open_image(m_image_name, &ictx)); @@ -493,8 +498,6 @@ TEST_F(TestMockOperationEnableFeaturesRequest, Mirroring) { ensure_features_disabled(ictx, RBD_FEATURE_JOURNALING); - PoolMirrorModeEnabler enabler(m_ioctx); - MockOperationImageCtx mock_image_ctx(*ictx); MockExclusiveLock mock_exclusive_lock; MockJournal mock_journal; @@ -530,9 +533,53 @@ TEST_F(TestMockOperationEnableFeaturesRequest, Mirroring) { ASSERT_EQ(0, cond_ctx.wait()); } +TEST_F(TestMockOperationEnableFeaturesRequest, ImageMirroring) { + REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); + + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + ensure_features_disabled(ictx, RBD_FEATURE_JOURNALING); + + MirrorModeEnabler mirror_mode_enabler(m_ioctx, cls::rbd::MIRROR_MODE_IMAGE); + + ASSERT_EQ(0, librbd::api::Mirror<>::image_enable(ictx, false)); // snapshot mode + + uint64_t features; + ASSERT_EQ(0, librbd::get_features(ictx, &features)); + + MockOperationImageCtx mock_image_ctx(*ictx); + MockExclusiveLock mock_exclusive_lock; + MockJournal mock_journal; + MockObjectMap mock_object_map; + initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal, + mock_object_map); + + expect_verify_lock_ownership(mock_image_ctx); + + MockCreateJournalRequest mock_create_journal_request; + MockEnableMirrorRequest mock_enable_mirror_request; + + ::testing::InSequence seq; + expect_prepare_lock(mock_image_ctx); + expect_block_writes(mock_image_ctx); + expect_unblock_writes(mock_image_ctx); + expect_handle_prepare_lock_complete(mock_image_ctx); + + C_SaferCond cond_ctx; + MockEnableFeaturesRequest *req = new MockEnableFeaturesRequest( + mock_image_ctx, &cond_ctx, 0, RBD_FEATURE_JOURNALING); + { + std::shared_lock owner_locker{mock_image_ctx.owner_lock}; + req->send(); + } + ASSERT_EQ(-EINVAL, cond_ctx.wait()); +} + TEST_F(TestMockOperationEnableFeaturesRequest, JournalingError) { REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); + MirrorModeEnabler mirror_mode_enabler(m_ioctx, cls::rbd::MIRROR_MODE_POOL); + librbd::ImageCtx *ictx; ASSERT_EQ(0, open_image(m_image_name, &ictx)); @@ -541,8 +588,6 @@ TEST_F(TestMockOperationEnableFeaturesRequest, JournalingError) { ensure_features_disabled(ictx, RBD_FEATURE_JOURNALING); - PoolMirrorModeEnabler enabler(m_ioctx); - MockOperationImageCtx mock_image_ctx(*ictx); MockExclusiveLock mock_exclusive_lock; MockJournal mock_journal; @@ -553,7 +598,6 @@ TEST_F(TestMockOperationEnableFeaturesRequest, JournalingError) { expect_verify_lock_ownership(mock_image_ctx); MockCreateJournalRequest mock_create_journal_request; - MockEnableMirrorRequest mock_enable_mirror_request; ::testing::InSequence seq; expect_prepare_lock(mock_image_ctx); @@ -578,6 +622,8 @@ TEST_F(TestMockOperationEnableFeaturesRequest, JournalingError) { TEST_F(TestMockOperationEnableFeaturesRequest, MirroringError) { REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); + MirrorModeEnabler mirror_mode_enabler(m_ioctx, cls::rbd::MIRROR_MODE_POOL); + librbd::ImageCtx *ictx; ASSERT_EQ(0, open_image(m_image_name, &ictx)); @@ -586,8 +632,6 @@ TEST_F(TestMockOperationEnableFeaturesRequest, MirroringError) { ensure_features_disabled(ictx, RBD_FEATURE_JOURNALING); - PoolMirrorModeEnabler enabler(m_ioctx); - MockOperationImageCtx mock_image_ctx(*ictx); MockExclusiveLock mock_exclusive_lock; MockJournal mock_journal; diff --git a/src/test/librbd/test_mirroring.cc b/src/test/librbd/test_mirroring.cc index 4970f675821..fab41185daf 100644 --- a/src/test/librbd/test_mirroring.cc +++ b/src/test/librbd/test_mirroring.cc @@ -92,10 +92,9 @@ public: return 0; } - void check_mirror_image_enable(rbd_mirror_mode_t mirror_mode, - uint64_t features, - int expected_r, - rbd_mirror_image_state_t mirror_state) { + void check_mirror_image_enable( + rbd_mirror_mode_t mirror_mode, uint64_t features, int expected_r, + rbd_mirror_image_state_t mirror_state) { ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, RBD_MIRROR_MODE_DISABLED)); @@ -157,14 +156,6 @@ public: ASSERT_EQ(mirror_state == RBD_MIRROR_IMAGE_ENABLED ? -ENOENT : -EINVAL, image.mirror_image_get_instance_id(&instance_id)); - if (mirror_mode == RBD_MIRROR_MODE_IMAGE && - mirror_state == RBD_MIRROR_IMAGE_DISABLED) { - // disabling image mirroring automatically disables journaling feature - uint64_t new_features; - ASSERT_EQ(0, image.features(&new_features)); - ASSERT_EQ(0, new_features & RBD_FEATURE_JOURNALING); - } - ASSERT_EQ(0, image.close()); ASSERT_EQ(0, m_rbd.remove(m_ioctx, image_name.c_str())); ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, RBD_MIRROR_MODE_DISABLED)); @@ -232,11 +223,10 @@ public: ASSERT_EQ(mirror_images_new_count, mirror_images_count); } - void check_mirroring_on_update_features(uint64_t init_features, - bool enable, bool enable_mirroring, - uint64_t features, int expected_r, - rbd_mirror_mode_t mirror_mode, - rbd_mirror_image_state_t mirror_state) { + void check_mirroring_on_update_features( + uint64_t init_features, bool enable, bool enable_mirroring, + uint64_t features, int expected_r, rbd_mirror_mode_t mirror_mode, + rbd_mirror_image_state_t mirror_state) { ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, mirror_mode)); @@ -633,6 +623,15 @@ TEST_F(TestMirroring, EnableJournaling_In_MirrorModeImage) { RBD_MIRROR_MODE_IMAGE, RBD_MIRROR_IMAGE_DISABLED); } +TEST_F(TestMirroring, EnableJournaling_In_MirrorModeImage_MirroringEnabled) { + uint64_t init_features = 0; + init_features |= RBD_FEATURE_OBJECT_MAP; + init_features |= RBD_FEATURE_EXCLUSIVE_LOCK; + uint64_t features = RBD_FEATURE_JOURNALING; + check_mirroring_on_update_features(init_features, true, true, features, + -EINVAL, RBD_MIRROR_MODE_IMAGE, RBD_MIRROR_IMAGE_ENABLED); +} + TEST_F(TestMirroring, EnableJournaling_In_MirrorModePool) { uint64_t init_features = 0; init_features |= RBD_FEATURE_OBJECT_MAP; @@ -658,8 +657,8 @@ TEST_F(TestMirroring, DisableJournaling_In_MirrorModeImage) { init_features |= RBD_FEATURE_EXCLUSIVE_LOCK; init_features |= RBD_FEATURE_JOURNALING; uint64_t features = RBD_FEATURE_JOURNALING; - check_mirroring_on_update_features(init_features, false, true, features, -EINVAL, - RBD_MIRROR_MODE_IMAGE, RBD_MIRROR_IMAGE_ENABLED); + check_mirroring_on_update_features(init_features, false, true, features, + -EINVAL, RBD_MIRROR_MODE_IMAGE, RBD_MIRROR_IMAGE_ENABLED); } TEST_F(TestMirroring, MirrorModeSet_DisabledMode_To_PoolMode) { diff --git a/src/test/rbd_mirror/image_replayer/test_mock_BootstrapRequest.cc b/src/test/rbd_mirror/image_replayer/test_mock_BootstrapRequest.cc index 341c6373f61..5f6bb43a0d1 100644 --- a/src/test/rbd_mirror/image_replayer/test_mock_BootstrapRequest.cc +++ b/src/test/rbd_mirror/image_replayer/test_mock_BootstrapRequest.cc @@ -3,12 +3,12 @@ #include "test/rbd_mirror/test_mock_fixture.h" #include "librbd/journal/TypeTraits.h" +#include "librbd/mirror/GetInfoRequest.h" #include "tools/rbd_mirror/InstanceWatcher.h" #include "tools/rbd_mirror/Threads.h" #include "tools/rbd_mirror/image_replayer/BootstrapRequest.h" #include "tools/rbd_mirror/image_replayer/CloseImageRequest.h" #include "tools/rbd_mirror/image_replayer/CreateImageRequest.h" -#include "tools/rbd_mirror/image_replayer/IsPrimaryRequest.h" #include "tools/rbd_mirror/image_replayer/OpenImageRequest.h" #include "tools/rbd_mirror/image_replayer/OpenLocalImageRequest.h" #include "test/journal/mock/MockJournaler.h" @@ -37,6 +37,41 @@ struct TypeTraits { } // namespace journal +namespace mirror { + +template<> +struct GetInfoRequest { + static GetInfoRequest* s_instance; + cls::rbd::MirrorImage *mirror_image; + PromotionState *promotion_state; + Context *on_finish = nullptr; + + static GetInfoRequest* create(librbd::MockTestImageCtx &image_ctx, + cls::rbd::MirrorImage *mirror_image, + PromotionState *promotion_state, + Context *on_finish) { + ceph_assert(s_instance != nullptr); + s_instance->mirror_image = mirror_image; + s_instance->promotion_state = promotion_state; + s_instance->on_finish = on_finish; + return s_instance; + } + + GetInfoRequest() { + ceph_assert(s_instance == nullptr); + s_instance = this; + } + ~GetInfoRequest() { + s_instance = nullptr; + } + + MOCK_METHOD0(send, void()); +}; + +GetInfoRequest* GetInfoRequest::s_instance = nullptr; + +} // namespace mirror + namespace util { static std::string s_image_id; @@ -166,31 +201,6 @@ struct CreateImageRequest { MOCK_METHOD0(send, void()); }; -template<> -struct IsPrimaryRequest { - static IsPrimaryRequest* s_instance; - bool *primary = nullptr; - Context *on_finish = nullptr; - - static IsPrimaryRequest* create(librbd::MockTestImageCtx *image_ctx, - bool *primary, Context *on_finish) { - ceph_assert(s_instance != nullptr); - s_instance->primary = primary; - s_instance->on_finish = on_finish; - return s_instance; - } - - IsPrimaryRequest() { - ceph_assert(s_instance == nullptr); - s_instance = this; - } - ~IsPrimaryRequest() { - s_instance = nullptr; - } - - MOCK_METHOD0(send, void()); -}; - template<> struct OpenImageRequest { static OpenImageRequest* s_instance; @@ -256,8 +266,6 @@ CloseImageRequest* CloseImageRequest::s_instance = nullptr; CreateImageRequest* CreateImageRequest::s_instance = nullptr; -IsPrimaryRequest* - IsPrimaryRequest::s_instance = nullptr; OpenImageRequest* OpenImageRequest::s_instance = nullptr; OpenLocalImageRequest* @@ -295,9 +303,9 @@ public: typedef CreateImageRequest MockCreateImageRequest; typedef ImageSync MockImageSync; typedef InstanceWatcher MockInstanceWatcher; - typedef IsPrimaryRequest MockIsPrimaryRequest; typedef OpenImageRequest MockOpenImageRequest; typedef OpenLocalImageRequest MockOpenLocalImageRequest; + typedef librbd::mirror::GetInfoRequest MockGetMirrorInfoRequest; typedef std::list Tags; void SetUp() override { @@ -404,12 +412,17 @@ public: })); } - void expect_is_primary(MockIsPrimaryRequest &mock_is_primary_request, - bool primary, int r) { - EXPECT_CALL(mock_is_primary_request, send()) - .WillOnce(Invoke([this, &mock_is_primary_request, primary, r]() { - *mock_is_primary_request.primary = primary; - m_threads->work_queue->queue(mock_is_primary_request.on_finish, r); + void expect_get_remote_mirror_info( + MockGetMirrorInfoRequest &mock_get_mirror_info_request, + const cls::rbd::MirrorImage &mirror_image, + librbd::mirror::PromotionState promotion_state, int r) { + EXPECT_CALL(mock_get_mirror_info_request, send()) + .WillOnce(Invoke([this, &mock_get_mirror_info_request, mirror_image, + promotion_state, r]() { + *mock_get_mirror_info_request.mirror_image = mirror_image; + *mock_get_mirror_info_request.promotion_state = promotion_state; + m_threads->work_queue->queue( + mock_get_mirror_info_request.on_finish, r); })); } @@ -508,8 +521,11 @@ TEST_F(TestMockImageReplayerBootstrapRequest, NonPrimaryRemoteSyncingState) { mock_remote_image_ctx.id, mock_remote_image_ctx, 0); // test if remote image is primary - MockIsPrimaryRequest mock_is_primary_request; - expect_is_primary(mock_is_primary_request, false, 0); + MockGetMirrorInfoRequest mock_get_mirror_info_request; + expect_get_remote_mirror_info(mock_get_mirror_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "uuid", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, + librbd::mirror::PROMOTION_STATE_NON_PRIMARY, 0); // switch the state to replaying librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); @@ -559,8 +575,11 @@ TEST_F(TestMockImageReplayerBootstrapRequest, NonPrimaryRemoteNotTagOwner) { mock_remote_image_ctx.id, mock_remote_image_ctx, 0); // test if remote image is primary - MockIsPrimaryRequest mock_is_primary_request; - expect_is_primary(mock_is_primary_request, false, 0); + MockGetMirrorInfoRequest mock_get_mirror_info_request; + expect_get_remote_mirror_info(mock_get_mirror_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "uuid", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, + librbd::mirror::PROMOTION_STATE_NON_PRIMARY, 0); // open the local image librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); @@ -618,8 +637,11 @@ TEST_F(TestMockImageReplayerBootstrapRequest, RemoteDemotePromote) { mock_remote_image_ctx.id, mock_remote_image_ctx, 0); // test if remote image is primary - MockIsPrimaryRequest mock_is_primary_request; - expect_is_primary(mock_is_primary_request, false, 0); + MockGetMirrorInfoRequest mock_get_mirror_info_request; + expect_get_remote_mirror_info(mock_get_mirror_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "uuid", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, + librbd::mirror::PROMOTION_STATE_NON_PRIMARY, 0); // open the local image librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); @@ -691,8 +713,11 @@ TEST_F(TestMockImageReplayerBootstrapRequest, MultipleRemoteDemotePromotes) { mock_remote_image_ctx.id, mock_remote_image_ctx, 0); // test if remote image is primary - MockIsPrimaryRequest mock_is_primary_request; - expect_is_primary(mock_is_primary_request, true, 0); + MockGetMirrorInfoRequest mock_get_mirror_info_request; + expect_get_remote_mirror_info(mock_get_mirror_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "uuid", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, + librbd::mirror::PROMOTION_STATE_PRIMARY, 0); // open the local image librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); @@ -774,8 +799,11 @@ TEST_F(TestMockImageReplayerBootstrapRequest, LocalDemoteRemotePromote) { mock_remote_image_ctx.id, mock_remote_image_ctx, 0); // test if remote image is primary - MockIsPrimaryRequest mock_is_primary_request; - expect_is_primary(mock_is_primary_request, true, 0); + MockGetMirrorInfoRequest mock_get_mirror_info_request; + expect_get_remote_mirror_info(mock_get_mirror_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "uuid", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, + librbd::mirror::PROMOTION_STATE_PRIMARY, 0); // open the local image librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); @@ -845,8 +873,11 @@ TEST_F(TestMockImageReplayerBootstrapRequest, SplitBrainForcePromote) { mock_remote_image_ctx.id, mock_remote_image_ctx, 0); // test if remote image is primary - MockIsPrimaryRequest mock_is_primary_request; - expect_is_primary(mock_is_primary_request, true, 0); + MockGetMirrorInfoRequest mock_get_mirror_info_request; + expect_get_remote_mirror_info(mock_get_mirror_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "uuid", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, + librbd::mirror::PROMOTION_STATE_PRIMARY, 0); // open the local image librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); @@ -916,8 +947,11 @@ TEST_F(TestMockImageReplayerBootstrapRequest, ResyncRequested) { mock_remote_image_ctx.id, mock_remote_image_ctx, 0); // test if remote image is primary - MockIsPrimaryRequest mock_is_primary_request; - expect_is_primary(mock_is_primary_request, true, 0); + MockGetMirrorInfoRequest mock_get_mirror_info_request; + expect_get_remote_mirror_info(mock_get_mirror_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "uuid", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, + librbd::mirror::PROMOTION_STATE_PRIMARY, 0); // open the local image librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); @@ -976,8 +1010,11 @@ TEST_F(TestMockImageReplayerBootstrapRequest, PrimaryRemote) { mock_remote_image_ctx.id, mock_remote_image_ctx, 0); // test if remote image is primary - MockIsPrimaryRequest mock_is_primary_request; - expect_is_primary(mock_is_primary_request, true, 0); + MockGetMirrorInfoRequest mock_get_mirror_info_request; + expect_get_remote_mirror_info(mock_get_mirror_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "uuid", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, + librbd::mirror::PROMOTION_STATE_PRIMARY, 0); // update client state back to syncing librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); @@ -1049,8 +1086,11 @@ TEST_F(TestMockImageReplayerBootstrapRequest, PrimaryRemoteLocalDeleted) { mock_remote_image_ctx.id, mock_remote_image_ctx, 0); // test if remote image is primary - MockIsPrimaryRequest mock_is_primary_request; - expect_is_primary(mock_is_primary_request, true, 0); + MockGetMirrorInfoRequest mock_get_mirror_info_request; + expect_get_remote_mirror_info(mock_get_mirror_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "uuid", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, + librbd::mirror::PROMOTION_STATE_PRIMARY, 0); // open the missing local image MockOpenLocalImageRequest mock_open_local_image_request; @@ -1066,7 +1106,10 @@ TEST_F(TestMockImageReplayerBootstrapRequest, PrimaryRemoteLocalDeleted) { expect_journaler_register_client(mock_journaler, client_data, 0); // test if remote image is primary - expect_is_primary(mock_is_primary_request, true, 0); + expect_get_remote_mirror_info(mock_get_mirror_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "uuid", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, + librbd::mirror::PROMOTION_STATE_PRIMARY, 0); // update client state back to syncing librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); @@ -1136,8 +1179,11 @@ TEST_F(TestMockImageReplayerBootstrapRequest, LocalImageIdCollision) { mock_remote_image_ctx.id, mock_remote_image_ctx, 0); // test if remote image is primary - MockIsPrimaryRequest mock_is_primary_request; - expect_is_primary(mock_is_primary_request, true, 0); + MockGetMirrorInfoRequest mock_get_mirror_info_request; + expect_get_remote_mirror_info(mock_get_mirror_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "uuid", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, + librbd::mirror::PROMOTION_STATE_PRIMARY, 0); // update client state back to syncing librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); diff --git a/src/tools/rbd_mirror/CMakeLists.txt b/src/tools/rbd_mirror/CMakeLists.txt index e5b4fd681e2..d38353bcf17 100644 --- a/src/tools/rbd_mirror/CMakeLists.txt +++ b/src/tools/rbd_mirror/CMakeLists.txt @@ -37,7 +37,6 @@ set(rbd_mirror_internal image_replayer/CreateImageRequest.cc image_replayer/EventPreprocessor.cc image_replayer/GetMirrorImageIdRequest.cc - image_replayer/IsPrimaryRequest.cc image_replayer/OpenImageRequest.cc image_replayer/OpenLocalImageRequest.cc image_replayer/PrepareLocalImageRequest.cc diff --git a/src/tools/rbd_mirror/image_replayer/BootstrapRequest.cc b/src/tools/rbd_mirror/image_replayer/BootstrapRequest.cc index dd66f9d964a..6b1ea3bcf3f 100644 --- a/src/tools/rbd_mirror/image_replayer/BootstrapRequest.cc +++ b/src/tools/rbd_mirror/image_replayer/BootstrapRequest.cc @@ -5,7 +5,6 @@ #include "BootstrapRequest.h" #include "CloseImageRequest.h" #include "CreateImageRequest.h" -#include "IsPrimaryRequest.h" #include "OpenImageRequest.h" #include "OpenLocalImageRequest.h" #include "common/debug.h" @@ -20,6 +19,7 @@ #include "librbd/Journal.h" #include "librbd/Utils.h" #include "librbd/journal/Types.h" +#include "librbd/mirror/GetInfoRequest.h" #include "tools/rbd_mirror/ProgressContext.h" #include "tools/rbd_mirror/ImageSync.h" #include "tools/rbd_mirror/Threads.h" @@ -173,25 +173,25 @@ void BootstrapRequest::handle_open_remote_image(int r) { return; } - is_primary(); + get_remote_mirror_info(); } template -void BootstrapRequest::is_primary() { +void BootstrapRequest::get_remote_mirror_info() { dout(15) << dendl; - update_progress("OPEN_REMOTE_IMAGE"); + update_progress("GET_REMOTE_MIRROR_INFO"); Context *ctx = create_context_callback< - BootstrapRequest, &BootstrapRequest::handle_is_primary>( + BootstrapRequest, &BootstrapRequest::handle_get_remote_mirror_info>( this); - IsPrimaryRequest *request = IsPrimaryRequest::create(m_remote_image_ctx, - &m_primary, ctx); + auto request = librbd::mirror::GetInfoRequest::create( + *m_remote_image_ctx, &m_mirror_image, &m_promotion_state, ctx); request->send(); } template -void BootstrapRequest::handle_is_primary(int r) { +void BootstrapRequest::handle_get_remote_mirror_info(int r) { dout(15) << "r=" << r << dendl; if (r == -ENOENT) { @@ -207,7 +207,22 @@ void BootstrapRequest::handle_is_primary(int r) { return; } - if (!m_primary) { + if (m_mirror_image.state == cls::rbd::MIRROR_IMAGE_STATE_DISABLING) { + dout(5) << "remote image mirroring is being disabled" << dendl; + m_ret_val = -EREMOTEIO; + close_remote_image(); + return; + } + + if (m_mirror_image.mode != cls::rbd::MIRROR_IMAGE_MODE_JOURNAL) { + dout(5) << ": remote image is in unsupported mode: " << m_mirror_image.mode + << dendl; + m_ret_val = -EOPNOTSUPP; + close_remote_image(); + return; + } + + if (m_promotion_state != librbd::mirror::PROMOTION_STATE_PRIMARY) { if (m_local_image_id.empty()) { // no local image and remote isn't primary -- don't sync it dout(5) << "remote image is not primary -- not syncing" @@ -338,7 +353,8 @@ void BootstrapRequest::handle_open_local_image(int r) { local_image_ctx->image_lock.unlock_shared(); } - if (m_local_tag_data.mirror_uuid != m_remote_mirror_uuid && !m_primary) { + if (m_local_tag_data.mirror_uuid != m_remote_mirror_uuid && + m_promotion_state != librbd::mirror::PROMOTION_STATE_PRIMARY) { // if the local mirror is not linked to the (now) non-primary image, // stop the replay. Otherwise, we ignore that the remote is non-primary // so that we can replay the demotion @@ -428,7 +444,7 @@ void BootstrapRequest::handle_register_client(int r) { *m_client_meta = librbd::journal::MirrorPeerClientMeta(); m_client_meta->state = librbd::journal::MIRROR_PEER_STATE_REPLAYING; - is_primary(); + get_remote_mirror_info(); } template diff --git a/src/tools/rbd_mirror/image_replayer/BootstrapRequest.h b/src/tools/rbd_mirror/image_replayer/BootstrapRequest.h index cc55040a825..93d9c4c75a8 100644 --- a/src/tools/rbd_mirror/image_replayer/BootstrapRequest.h +++ b/src/tools/rbd_mirror/image_replayer/BootstrapRequest.h @@ -8,8 +8,10 @@ #include "include/rados/librados.hpp" #include "common/ceph_mutex.h" #include "cls/journal/cls_journal_types.h" +#include "cls/rbd/cls_rbd_types.h" #include "librbd/journal/Types.h" #include "librbd/journal/TypeTraits.h" +#include "librbd/mirror/Types.h" #include "tools/rbd_mirror/BaseRequest.h" #include "tools/rbd_mirror/Types.h" #include @@ -101,7 +103,7 @@ private: * | * * |/--------------------------------------------------*---\ * v * | - * IS_PRIMARY * * * * * * * * * * * * * * * * * * * * * * | + * GET_REMOTE_MIRROR_INFO * * * * * * * * * * * * * * * * | * | * * | * | (remote image primary, no local image id) * * | * \----> UPDATE_CLIENT_IMAGE * * * * * * * * * * * * | @@ -169,7 +171,9 @@ private: cls::journal::Client m_client; uint64_t m_remote_tag_class = 0; ImageCtxT *m_remote_image_ctx = nullptr; - bool m_primary = false; + cls::rbd::MirrorImage m_mirror_image; + librbd::mirror::PromotionState m_promotion_state = + librbd::mirror::PROMOTION_STATE_NON_PRIMARY; int m_ret_val = 0; ImageSync *m_image_sync = nullptr; @@ -184,8 +188,8 @@ private: void open_remote_image(); void handle_open_remote_image(int r); - void is_primary(); - void handle_is_primary(int r); + void get_remote_mirror_info(); + void handle_get_remote_mirror_info(int r); void update_client_state(); void handle_update_client_state(int r); diff --git a/src/tools/rbd_mirror/image_replayer/IsPrimaryRequest.cc b/src/tools/rbd_mirror/image_replayer/IsPrimaryRequest.cc deleted file mode 100644 index 67cfade97e8..00000000000 --- a/src/tools/rbd_mirror/image_replayer/IsPrimaryRequest.cc +++ /dev/null @@ -1,131 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab - -#include "IsPrimaryRequest.h" -#include "common/debug.h" -#include "common/errno.h" -#include "common/WorkQueue.h" -#include "cls/rbd/cls_rbd_client.h" -#include "librbd/ImageCtx.h" -#include "librbd/Journal.h" -#include "librbd/Utils.h" -#include - -#define dout_context g_ceph_context -#define dout_subsys ceph_subsys_rbd_mirror -#undef dout_prefix -#define dout_prefix *_dout << "rbd::mirror::image_replayer::IsPrimaryRequest: " \ - << this << " " << __func__ << " " - -namespace rbd { -namespace mirror { -namespace image_replayer { - -using librbd::util::create_context_callback; -using librbd::util::create_rados_callback; - -template -IsPrimaryRequest::IsPrimaryRequest(I *image_ctx, bool *primary, - Context *on_finish) - : m_image_ctx(image_ctx), m_primary(primary), m_on_finish(on_finish) { -} - -template -void IsPrimaryRequest::send() { - send_get_mirror_state(); -} - -template -void IsPrimaryRequest::send_get_mirror_state() { - dout(20) << dendl; - - librados::ObjectReadOperation op; - librbd::cls_client::mirror_image_get_start(&op, m_image_ctx->id); - - librados::AioCompletion *aio_comp = create_rados_callback< - IsPrimaryRequest, &IsPrimaryRequest::handle_get_mirror_state>(this); - int r = m_image_ctx->md_ctx.aio_operate(RBD_MIRRORING, aio_comp, &op, - &m_out_bl); - ceph_assert(r == 0); - aio_comp->release(); -} - -template -void IsPrimaryRequest::handle_get_mirror_state(int r) { - dout(20) << ": r=" << r << dendl; - - cls::rbd::MirrorImage mirror_image; - if (r == 0) { - auto iter = m_out_bl.cbegin(); - r = librbd::cls_client::mirror_image_get_finish(&iter, &mirror_image); - if (r == 0) { - if (mirror_image.state == cls::rbd::MIRROR_IMAGE_STATE_ENABLED) { - if (mirror_image.mode == cls::rbd::MIRROR_IMAGE_MODE_JOURNAL) { - send_is_tag_owner(); - } else if (mirror_image.mode == cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT) { - // TODO: get primary state from mirroring snapshots - ceph_abort(); - finish(0); - } - return; - } else if (mirror_image.state == cls::rbd::MIRROR_IMAGE_STATE_DISABLING) { - dout(5) << ": image mirroring is being disabled" << dendl; - r = -ENOENT; - } else { - derr << ": image mirroring is disabled" << dendl; - r = -EINVAL; - } - } else { - derr << ": failed to decode image mirror state: " << cpp_strerror(r) - << dendl; - } - } else if (r == -ENOENT) { - dout(5) << ": image is not mirrored" << dendl; - } else { - derr << ": failed to retrieve image mirror state: " << cpp_strerror(r) - << dendl; - } - - finish(r); -} - -template -void IsPrimaryRequest::send_is_tag_owner() { - // deduce the class type for the journal to support unit tests - using Journal = typename std::decay< - typename std::remove_pointer().journal)> - ::type>::type; - - dout(20) << dendl; - - Context *ctx = create_context_callback< - IsPrimaryRequest, &IsPrimaryRequest::handle_is_tag_owner>(this); - - Journal::is_tag_owner(m_image_ctx, m_primary, ctx); -} - -template -void IsPrimaryRequest::handle_is_tag_owner(int r) { - dout(20) << ": r=" << r << dendl; - - if (r < 0) { - derr << ": failed to query remote image tag owner: " << cpp_strerror(r) - << dendl; - } - - finish(r); -} - -template -void IsPrimaryRequest::finish(int r) { - dout(20) << ": r=" << r << dendl; - - m_on_finish->complete(r); - delete this; -} - -} // namespace image_replayer -} // namespace mirror -} // namespace rbd - -template class rbd::mirror::image_replayer::IsPrimaryRequest; diff --git a/src/tools/rbd_mirror/image_replayer/IsPrimaryRequest.h b/src/tools/rbd_mirror/image_replayer/IsPrimaryRequest.h deleted file mode 100644 index ddb332cbfe6..00000000000 --- a/src/tools/rbd_mirror/image_replayer/IsPrimaryRequest.h +++ /dev/null @@ -1,67 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab - -#ifndef RBD_MIRROR_IMAGE_REPLAYER_IS_PRIMARY_REQUEST_H -#define RBD_MIRROR_IMAGE_REPLAYER_IS_PRIMARY_REQUEST_H - -#include "include/buffer.h" - -class Context; -class ContextWQ; -namespace librbd { class ImageCtx; } - -namespace rbd { -namespace mirror { -namespace image_replayer { - -template -class IsPrimaryRequest { -public: - static IsPrimaryRequest* create(ImageCtxT *image_ctx, bool *primary, - Context *on_finish) { - return new IsPrimaryRequest(image_ctx, primary, on_finish); - } - - IsPrimaryRequest(ImageCtxT *image_ctx, bool *primary, Context *on_finish); - - void send(); - -private: - /** - * @verbatim - * - * - * | - * v - * GET_MIRROR_STATE * * * * * - * | * - * v * - * IS_TAG_OWNER * * * * * * * (error) - * | * - * v * - * < * * * * * * * * - * - * @endverbatim - */ - ImageCtxT *m_image_ctx; - bool *m_primary; - Context *m_on_finish; - - bufferlist m_out_bl; - - void send_get_mirror_state(); - void handle_get_mirror_state(int r); - - void send_is_tag_owner(); - void handle_is_tag_owner(int r); - - void finish(int r); -}; - -} // namespace image_replayer -} // namespace mirror -} // namespace rbd - -extern template class rbd::mirror::image_replayer::IsPrimaryRequest; - -#endif // RBD_MIRROR_IMAGE_REPLAYER_IS_PRIMARY_REQUEST_H diff --git a/src/tools/rbd_mirror/image_replayer/OpenLocalImageRequest.cc b/src/tools/rbd_mirror/image_replayer/OpenLocalImageRequest.cc index f0f0e3e5252..a4969ef6ec1 100644 --- a/src/tools/rbd_mirror/image_replayer/OpenLocalImageRequest.cc +++ b/src/tools/rbd_mirror/image_replayer/OpenLocalImageRequest.cc @@ -3,7 +3,6 @@ #include "include/compat.h" #include "CloseImageRequest.h" -#include "IsPrimaryRequest.h" #include "OpenLocalImageRequest.h" #include "common/debug.h" #include "common/errno.h" @@ -15,6 +14,7 @@ #include "librbd/Utils.h" #include "librbd/exclusive_lock/Policy.h" #include "librbd/journal/Policy.h" +#include "librbd/mirror/GetInfoRequest.h" #include #define dout_context g_ceph_context @@ -146,23 +146,24 @@ void OpenLocalImageRequest::handle_open_image(int r) { return; } - send_is_primary(); + send_get_mirror_info(); } template -void OpenLocalImageRequest::send_is_primary() { +void OpenLocalImageRequest::send_get_mirror_info() { dout(20) << dendl; Context *ctx = create_context_callback< - OpenLocalImageRequest, &OpenLocalImageRequest::handle_is_primary>( + OpenLocalImageRequest, + &OpenLocalImageRequest::handle_get_mirror_info>( this); - IsPrimaryRequest *request = IsPrimaryRequest::create(*m_local_image_ctx, - &m_primary, ctx); + auto request = librbd::mirror::GetInfoRequest::create( + **m_local_image_ctx, &m_mirror_image, &m_promotion_state, ctx); request->send(); } template -void OpenLocalImageRequest::handle_is_primary(int r) { +void OpenLocalImageRequest::handle_get_mirror_info(int r) { dout(20) << ": r=" << r << dendl; if (r == -ENOENT) { @@ -176,9 +177,22 @@ void OpenLocalImageRequest::handle_is_primary(int r) { return; } + if (m_mirror_image.state == cls::rbd::MIRROR_IMAGE_STATE_DISABLING) { + dout(5) << ": local image mirroring is being disabled" << dendl; + send_close_image(-ENOENT); + return; + } + + if (m_mirror_image.mode != cls::rbd::MIRROR_IMAGE_MODE_JOURNAL) { + dout(5) << ": local image is in unsupported mode: " << m_mirror_image.mode + << dendl; + send_close_image(-EOPNOTSUPP); + return; + } + // if the local image owns the tag -- don't steal the lock since // we aren't going to mirror peer data into this image anyway - if (m_primary) { + if (m_promotion_state == librbd::mirror::PROMOTION_STATE_PRIMARY) { dout(10) << ": local image is primary -- skipping image replay" << dendl; send_close_image(-EREMOTEIO); return; diff --git a/src/tools/rbd_mirror/image_replayer/OpenLocalImageRequest.h b/src/tools/rbd_mirror/image_replayer/OpenLocalImageRequest.h index 58de545fb3a..7acf349046b 100644 --- a/src/tools/rbd_mirror/image_replayer/OpenLocalImageRequest.h +++ b/src/tools/rbd_mirror/image_replayer/OpenLocalImageRequest.h @@ -5,7 +5,9 @@ #define RBD_MIRROR_IMAGE_REPLAYER_OPEN_LOCAL_IMAGE_REQUEST_H #include "include/int_types.h" +#include "cls/rbd/cls_rbd_types.h" #include "librbd/ImageCtx.h" +#include "librbd/mirror/Types.h" #include class Context; @@ -46,7 +48,7 @@ private: * OPEN_IMAGE * * * * * * * * * | * * v * - * IS_PRIMARY * * * * * * * * + * GET_MIRROR_INFO * * * * * * | * * v (skip if primary) v * LOCK_IMAGE * * * > CLOSE_IMAGE @@ -62,14 +64,16 @@ private: ContextWQ *m_work_queue; Context *m_on_finish; - bool m_primary = false; + cls::rbd::MirrorImage m_mirror_image; + librbd::mirror::PromotionState m_promotion_state = + librbd::mirror::PROMOTION_STATE_NON_PRIMARY; int m_ret_val = 0; void send_open_image(); void handle_open_image(int r); - void send_is_primary(); - void handle_is_primary(int r); + void send_get_mirror_info(); + void handle_get_mirror_info(int r); void send_lock_image(); void handle_lock_image(int r); -- 2.39.5