#include "common/dout.h"
#include "common/errno.h"
#include "cls/journal/cls_journal_client.h"
-#include "cls/rbd/cls_rbd_client.h"
#include "journal/Journaler.h"
+#include "librbd/ImageCtx.h"
#include "librbd/ImageState.h"
#include "librbd/Journal.h"
-#include "librbd/MirroringWatcher.h"
#include "librbd/Operations.h"
#include "librbd/Utils.h"
#include "librbd/journal/PromoteRequest.h"
+#include "librbd/mirror/GetInfoRequest.h"
+#include "librbd/mirror/ImageRemoveRequest.h"
+#include "librbd/mirror/ImageStateUpdateRequest.h"
+#include "librbd/mirror/snapshot/PromoteRequest.h"
#define dout_subsys ceph_subsys_rbd
#undef dout_prefix
-#define dout_prefix *_dout << "librbd::mirror::DisableRequest: "
+#define dout_prefix *_dout << "librbd::mirror::DisableRequest: " \
+ << this << " " << __func__ << ": "
namespace librbd {
namespace mirror {
DisableRequest<I>::DisableRequest(I *image_ctx, bool force, bool remove,
Context *on_finish)
: m_image_ctx(image_ctx), m_force(force), m_remove(remove),
- m_on_finish(on_finish), m_lock("mirror::DisableRequest::m_lock") {
+ m_on_finish(on_finish) {
}
template <typename I>
void DisableRequest<I>::send() {
- send_get_mirror_image();
+ send_get_mirror_info();
}
template <typename I>
-void DisableRequest<I>::send_get_mirror_image() {
+void DisableRequest<I>::send_get_mirror_info() {
CephContext *cct = m_image_ctx->cct;
- ldout(cct, 10) << this << " " << __func__ << dendl;
+ ldout(cct, 10) << dendl;
- librados::ObjectReadOperation op;
- cls_client::mirror_image_get_start(&op, m_image_ctx->id);
using klass = DisableRequest<I>;
- librados::AioCompletion *comp =
- create_rados_callback<klass, &klass::handle_get_mirror_image>(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<I>::create(*m_image_ctx, &m_mirror_image,
+ &m_promotion_state,
+ &m_primary_mirror_uuid, ctx);
+ req->send();
}
template <typename I>
-Context *DisableRequest<I>::handle_get_mirror_image(int *result) {
+Context *DisableRequest<I>::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);
- }
+ ldout(cct, 10) << "r=" << *result << dendl;
if (*result < 0) {
if (*result == -ENOENT) {
- ldout(cct, 20) << this << " " << __func__
- << ": mirroring is not enabled for this image" << dendl;
+ ldout(cct, 20) << "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 <typename I>
-void DisableRequest<I>::send_get_tag_owner() {
- CephContext *cct = m_image_ctx->cct;
- ldout(cct, 10) << this << " " << __func__ << dendl;
-
- using klass = DisableRequest<I>;
- Context *ctx = util::create_context_callback<
- klass, &klass::handle_get_tag_owner>(this);
-
- Journal<I>::is_tag_owner(m_image_ctx, &m_is_primary, ctx);
-}
-
-template <typename I>
-Context *DisableRequest<I>::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 ||
+ m_promotion_state == PROMOTION_STATE_UNKNOWN);
if (!m_is_primary && !m_force) {
lderr(cct) << "mirrored image is not primary, "
return m_on_finish;
}
- send_set_mirror_image();
+ send_image_state_update();
return nullptr;
}
template <typename I>
-void DisableRequest<I>::send_set_mirror_image() {
+void DisableRequest<I>::send_image_state_update() {
CephContext *cct = m_image_ctx->cct;
- ldout(cct, 10) << this << " " << __func__ << dendl;
-
- m_mirror_image.state = cls::rbd::MIRROR_IMAGE_STATE_DISABLING;
-
- librados::ObjectWriteOperation op;
- cls_client::mirror_image_set(&op, m_image_ctx->id, m_mirror_image);
-
- using klass = DisableRequest<I>;
- librados::AioCompletion *comp =
- create_rados_callback<klass, &klass::handle_set_mirror_image>(this);
- m_out_bl.clear();
- int r = m_image_ctx->md_ctx.aio_operate(RBD_MIRRORING, comp, &op);
- ceph_assert(r == 0);
- comp->release();
+ ldout(cct, 10) << dendl;
+
+ auto ctx = util::create_context_callback<
+ DisableRequest<I>,
+ &DisableRequest<I>::handle_image_state_update>(this);
+ auto req = ImageStateUpdateRequest<I>::create(
+ m_image_ctx->md_ctx, m_image_ctx->id,
+ cls::rbd::MIRROR_IMAGE_STATE_DISABLING, m_mirror_image, ctx);
+ req->send();
}
template <typename I>
-Context *DisableRequest<I>::handle_set_mirror_image(int *result) {
+Context *DisableRequest<I>::handle_image_state_update(int *result) {
CephContext *cct = m_image_ctx->cct;
- ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
+ ldout(cct, 10) << "r=" << *result << dendl;
if (*result < 0) {
lderr(cct) << "failed to disable mirroring: " << cpp_strerror(*result)
return m_on_finish;
}
- send_notify_mirroring_watcher();
+ send_promote_image();
return nullptr;
}
template <typename I>
-void DisableRequest<I>::send_notify_mirroring_watcher() {
- CephContext *cct = m_image_ctx->cct;
- ldout(cct, 10) << this << " " << __func__ << dendl;
-
- using klass = DisableRequest<I>;
- Context *ctx = util::create_context_callback<
- klass, &klass::handle_notify_mirroring_watcher>(this);
+void DisableRequest<I>::send_promote_image() {
+ if (m_is_primary) {
+ clean_mirror_state();
+ return;
+ }
- MirroringWatcher<I>::notify_image_updated(
- m_image_ctx->md_ctx, cls::rbd::MIRROR_IMAGE_STATE_DISABLING,
- m_image_ctx->id, m_mirror_image.global_image_id, ctx);
+ CephContext *cct = m_image_ctx->cct;
+ ldout(cct, 10) << dendl;
+
+ auto ctx = util::create_context_callback<
+ DisableRequest<I>, &DisableRequest<I>::handle_promote_image>(this);
+ if (m_mirror_image.mode == cls::rbd::MIRROR_IMAGE_MODE_JOURNAL) {
+ // Not primary -- shouldn't have the journal open
+ ceph_assert(m_image_ctx->journal == nullptr);
+
+ auto req = journal::PromoteRequest<I>::create(m_image_ctx, true, ctx);
+ req->send();
+ } else if (m_mirror_image.mode == cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT) {
+ auto req = mirror::snapshot::PromoteRequest<I>::create(
+ m_image_ctx, m_mirror_image.global_image_id, ctx);
+ req->send();
+ } else {
+ lderr(cct) << "unknown image mirror mode: " << m_mirror_image.mode << dendl;
+ ctx->complete(-EOPNOTSUPP);
+ }
}
template <typename I>
-Context *DisableRequest<I>::handle_notify_mirroring_watcher(int *result) {
+Context *DisableRequest<I>::handle_promote_image(int *result) {
CephContext *cct = m_image_ctx->cct;
- ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
+ ldout(cct, 10) << "r=" << *result << dendl;
if (*result < 0) {
- lderr(cct) << "failed to send update notification: "
- << cpp_strerror(*result) << dendl;
- *result = 0;
+ lderr(cct) << "failed to promote image: " << cpp_strerror(*result) << dendl;
+ return m_on_finish;
}
- send_promote_image();
+ send_refresh_image();
return nullptr;
}
template <typename I>
-void DisableRequest<I>::send_promote_image() {
- if (m_is_primary) {
- send_get_clients();
+void DisableRequest<I>::send_refresh_image() {
+ if (!m_image_ctx->state->is_refresh_required()) {
+ clean_mirror_state();
return;
}
CephContext *cct = m_image_ctx->cct;
- ldout(cct, 10) << this << " " << __func__ << dendl;
-
- // Not primary -- shouldn't have the journal open
- ceph_assert(m_image_ctx->journal == nullptr);
+ ldout(cct, 10) << dendl;
- using klass = DisableRequest<I>;
- Context *ctx = util::create_context_callback<
- klass, &klass::handle_promote_image>(this);
- auto req = journal::PromoteRequest<I>::create(m_image_ctx, true, ctx);
- req->send();
+ auto ctx = util::create_context_callback<
+ DisableRequest<I>,
+ &DisableRequest<I>::handle_refresh_image>(this);
+ m_image_ctx->state->refresh(ctx);
}
template <typename I>
-Context *DisableRequest<I>::handle_promote_image(int *result) {
+Context *DisableRequest<I>::handle_refresh_image(int* result) {
CephContext *cct = m_image_ctx->cct;
- ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
+ ldout(cct, 10) << "r=" << *result << dendl;
if (*result < 0) {
- lderr(cct) << "failed to promote image: " << cpp_strerror(*result) << dendl;
+ lderr(cct) << "failed to refresh image: " << cpp_strerror(*result) << dendl;
return m_on_finish;
}
- send_get_clients();
+ clean_mirror_state();
return nullptr;
}
+template <typename I>
+void DisableRequest<I>::clean_mirror_state() {
+ CephContext *cct = m_image_ctx->cct;
+ ldout(cct, 10) << dendl;
+
+ if (m_mirror_image.mode == cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT) {
+ remove_mirror_snapshots();
+ } else {
+ send_get_clients();
+ }
+}
+
template <typename I>
void DisableRequest<I>::send_get_clients() {
CephContext *cct = m_image_ctx->cct;
- ldout(cct, 10) << this << " " << __func__ << dendl;
+ ldout(cct, 10) << dendl;
using klass = DisableRequest<I>;
Context *ctx = util::create_context_callback<
template <typename I>
Context *DisableRequest<I>::handle_get_clients(int *result) {
CephContext *cct = m_image_ctx->cct;
- ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
+ ldout(cct, 10) << "r=" << *result << dendl;
if (*result < 0) {
lderr(cct) << "failed to get registered clients: " << cpp_strerror(*result)
return m_on_finish;
}
- Mutex::Locker locker(m_lock);
+ std::lock_guard locker{m_lock};
ceph_assert(m_current_ops.empty());
if (m_current_ops.find(client.id) != m_current_ops.end()) {
// Should not happen.
- lderr(cct) << this << " " << __func__ << ": clients with the same id "
+ lderr(cct) << "clients with the same id "
<< client.id << dendl;
continue;
}
}
template <typename I>
-void DisableRequest<I>::send_remove_snap(const std::string &client_id,
- const cls::rbd::SnapshotNamespace &snap_namespace,
- const std::string &snap_name) {
+void DisableRequest<I>::remove_mirror_snapshots() {
CephContext *cct = m_image_ctx->cct;
- ldout(cct, 10) << this << " " << __func__ << ": client_id=" << client_id
+ ldout(cct, 10) << dendl;
+
+ // remove snapshot-based 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) {
+ send_remove_snap("", snap_info.snap_namespace, snap_info.name);
+ removing_snapshots = true;
+ }
+ }
+ }
+
+ if (!removing_snapshots) {
+ send_remove_mirror_image();
+ }
+}
+
+template <typename I>
+void DisableRequest<I>::send_remove_snap(
+ const std::string &client_id,
+ const cls::rbd::SnapshotNamespace &snap_namespace,
+ const std::string &snap_name) {
+ CephContext *cct = m_image_ctx->cct;
+ ldout(cct, 10) << "client_id=" << client_id
<< ", snap_name=" << snap_name << dendl;
- ceph_assert(m_lock.is_locked());
+ ceph_assert(ceph_mutex_is_locked(m_lock));
m_current_ops[client_id]++;
Context *ctx = create_context_callback(
&DisableRequest<I>::handle_remove_snap, client_id);
- ctx = new FunctionContext([this, snap_namespace, snap_name, ctx](int r) {
+ ctx = new LambdaContext([this, snap_namespace, snap_name, ctx](int r) {
m_image_ctx->operations->snap_remove(snap_namespace,
snap_name.c_str(),
ctx);
Context *DisableRequest<I>::handle_remove_snap(int *result,
const std::string &client_id) {
CephContext *cct = m_image_ctx->cct;
- ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
+ ldout(cct, 10) << "r=" << *result << dendl;
- Mutex::Locker locker(m_lock);
+ std::lock_guard locker{m_lock};
ceph_assert(m_current_ops[client_id] > 0);
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);
}
void DisableRequest<I>::send_unregister_client(
const std::string &client_id) {
CephContext *cct = m_image_ctx->cct;
- ldout(cct, 10) << this << " " << __func__ << dendl;
+ ldout(cct, 10) << dendl;
- ceph_assert(m_lock.is_locked());
+ ceph_assert(ceph_mutex_is_locked(m_lock));
ceph_assert(m_current_ops[client_id] == 0);
Context *ctx = create_context_callback(
int *result, const std::string &client_id) {
CephContext *cct = m_image_ctx->cct;
- ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
+ ldout(cct, 10) << "r=" << *result << dendl;
- Mutex::Locker locker(m_lock);
+ std::lock_guard locker{m_lock};
ceph_assert(m_current_ops[client_id] == 0);
m_current_ops.erase(client_id);
template <typename I>
void DisableRequest<I>::send_remove_mirror_image() {
CephContext *cct = m_image_ctx->cct;
- ldout(cct, 10) << this << " " << __func__ << dendl;
-
- librados::ObjectWriteOperation op;
- cls_client::mirror_image_remove(&op, m_image_ctx->id);
-
- using klass = DisableRequest<I>;
- librados::AioCompletion *comp =
- create_rados_callback<klass, &klass::handle_remove_mirror_image>(this);
- m_out_bl.clear();
- int r = m_image_ctx->md_ctx.aio_operate(RBD_MIRRORING, comp, &op);
- ceph_assert(r == 0);
- comp->release();
+ ldout(cct, 10) << dendl;
+
+ auto ctx = util::create_context_callback<
+ DisableRequest<I>,
+ &DisableRequest<I>::handle_remove_mirror_image>(this);
+ auto req = ImageRemoveRequest<I>::create(
+ m_image_ctx->md_ctx, m_mirror_image.global_image_id, m_image_ctx->id,
+ ctx);
+ req->send();
}
template <typename I>
Context *DisableRequest<I>::handle_remove_mirror_image(int *result) {
CephContext *cct = m_image_ctx->cct;
- ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
-
- if (*result == -ENOENT) {
- *result = 0;
- }
+ ldout(cct, 10) << "r=" << *result << dendl;
if (*result < 0) {
lderr(cct) << "failed to remove mirror image: " << cpp_strerror(*result)
return m_on_finish;
}
- ldout(cct, 20) << this << " " << __func__
- << ": removed image state from rbd_mirroring object" << dendl;
-
- send_notify_mirroring_watcher_removed();
- return nullptr;
-}
-
-template <typename I>
-void DisableRequest<I>::send_notify_mirroring_watcher_removed() {
- CephContext *cct = m_image_ctx->cct;
- ldout(cct, 10) << this << " " << __func__ << dendl;
-
- using klass = DisableRequest<I>;
- Context *ctx = util::create_context_callback<
- klass, &klass::handle_notify_mirroring_watcher_removed>(this);
-
- MirroringWatcher<I>::notify_image_updated(
- m_image_ctx->md_ctx, cls::rbd::MIRROR_IMAGE_STATE_DISABLED, m_image_ctx->id,
- m_mirror_image.global_image_id, ctx);
-}
-
-template <typename I>
-Context *DisableRequest<I>::handle_notify_mirroring_watcher_removed(
- int *result) {
- CephContext *cct = m_image_ctx->cct;
- ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
-
- if (*result < 0) {
- lderr(cct) << "failed to send update notification: "
- << cpp_strerror(*result) << dendl;
- *result = 0;
- }
-
+ ldout(cct, 20) << "removed image state from rbd_mirroring object" << dendl;
return m_on_finish;
}
Context*(DisableRequest<I>::*handle)(int*, const std::string &client_id),
const std::string &client_id) {
- return new FunctionContext([this, handle, client_id](int r) {
+ return new LambdaContext([this, handle, client_id](int r) {
Context *on_finish = (this->*handle)(&r, client_id);
if (on_finish != nullptr) {
on_finish->complete(r);