]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/librbd/mirror/EnableRequest.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / librbd / mirror / EnableRequest.cc
index a5c5b1255fac8c57dddb233981ac9833267994e2..c2cbbbd322c7facfc1f5b453437bac3fe26de450 100644 (file)
@@ -7,12 +7,14 @@
 #include "cls/rbd/cls_rbd_client.h"
 #include "librbd/ImageState.h"
 #include "librbd/Journal.h"
-#include "librbd/MirroringWatcher.h"
 #include "librbd/Utils.h"
+#include "librbd/mirror/ImageStateUpdateRequest.h"
+#include "librbd/mirror/snapshot/CreatePrimaryRequest.h"
 
 #define dout_subsys ceph_subsys_rbd
 #undef dout_prefix
-#define dout_prefix *_dout << "librbd::mirror::EnableRequest: "
+#define dout_prefix *_dout << "librbd::mirror::EnableRequest: " \
+                           << this << " " << __func__ << ": "
 
 namespace librbd {
 namespace mirror {
@@ -23,22 +25,24 @@ using util::create_rados_callback;
 template <typename I>
 EnableRequest<I>::EnableRequest(librados::IoCtx &io_ctx,
                                 const std::string &image_id,
+                                I* image_ctx,
+                                cls::rbd::MirrorImageMode mode,
                                 const std::string &non_primary_global_image_id,
                                 ContextWQ *op_work_queue, Context *on_finish)
-  : m_io_ctx(io_ctx), m_image_id(image_id),
-    m_non_primary_global_image_id(non_primary_global_image_id),
+  : m_io_ctx(io_ctx), m_image_id(image_id), m_image_ctx(image_ctx),
+    m_mode(mode), m_non_primary_global_image_id(non_primary_global_image_id),
     m_op_work_queue(op_work_queue), m_on_finish(on_finish),
     m_cct(reinterpret_cast<CephContext*>(io_ctx.cct())) {
 }
 
 template <typename I>
 void EnableRequest<I>::send() {
-  send_get_mirror_image();
+  get_mirror_image();
 }
 
 template <typename I>
-void EnableRequest<I>::send_get_mirror_image() {
-  ldout(m_cct, 10) << this << " " << __func__ << dendl;
+void EnableRequest<I>::get_mirror_image() {
+  ldout(m_cct, 10) << dendl;
 
   librados::ObjectReadOperation op;
   cls_client::mirror_image_get_start(&op, m_image_id);
@@ -53,33 +57,41 @@ void EnableRequest<I>::send_get_mirror_image() {
 }
 
 template <typename I>
-Context *EnableRequest<I>::handle_get_mirror_image(int *result) {
-  ldout(m_cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
+void EnableRequest<I>::handle_get_mirror_image(int r) {
+  ldout(m_cct, 10) << "r=" << r << dendl;
 
-  if (*result == 0) {
+  if (r == 0) {
     auto iter = m_out_bl.cbegin();
-    *result = cls_client::mirror_image_get_finish(&iter, &m_mirror_image);
+    r = cls_client::mirror_image_get_finish(&iter, &m_mirror_image);
   }
 
-  if (*result == 0) {
-    if (m_mirror_image.state == cls::rbd::MIRROR_IMAGE_STATE_ENABLED) {
-      ldout(m_cct, 10) << this << " " << __func__
-                       << ": mirroring is already enabled" << dendl;
+  if (r == 0 && m_mirror_image.state == cls::rbd::MIRROR_IMAGE_STATE_CREATING &&
+      !m_non_primary_global_image_id.empty()) {
+    // special case where rbd-mirror injects a disabled record to record the
+    // local image id prior to creating ther image
+    ldout(m_cct, 10) << "enabling mirroring on in-progress image replication"
+                     << dendl;
+  } else if (r == 0) {
+    if (m_mirror_image.mode != m_mode) {
+      lderr(m_cct) << "invalid current image mirror mode" << dendl;
+      r = -EINVAL;
+    } else if (m_mirror_image.state == cls::rbd::MIRROR_IMAGE_STATE_ENABLED) {
+      ldout(m_cct, 10) << "mirroring is already enabled" << dendl;
     } else {
       lderr(m_cct) << "currently disabling" << dendl;
-      *result = -EINVAL;
+      r = -EINVAL;
     }
-    return m_on_finish;
-  }
-
-  if (*result != -ENOENT) {
-    lderr(m_cct) << "failed to retrieve mirror image: " << cpp_strerror(*result)
+    finish(r);
+    return;
+  } else if (r != -ENOENT) {
+    lderr(m_cct) << "failed to retrieve mirror image: " << cpp_strerror(r)
                  << dendl;
-    return m_on_finish;
+    finish(r);
+    return;
   }
 
-  *result = 0;
-  m_mirror_image.state = cls::rbd::MIRROR_IMAGE_STATE_ENABLED;
+  r = 0;
+  m_mirror_image.mode = m_mode;
   if (m_non_primary_global_image_id.empty()) {
     uuid_d uuid_gen;
     uuid_gen.generate_random();
@@ -88,17 +100,20 @@ Context *EnableRequest<I>::handle_get_mirror_image(int *result) {
     m_mirror_image.global_image_id = m_non_primary_global_image_id;
   }
 
-  send_get_tag_owner();
-  return nullptr;
+  get_tag_owner();
 }
 
 template <typename I>
-void EnableRequest<I>::send_get_tag_owner() {
-  if (!m_non_primary_global_image_id.empty()) {
-    send_set_mirror_image();
+void EnableRequest<I>::get_tag_owner() {
+  if (m_mirror_image.mode == cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT) {
+    create_primary_snapshot();
+    return;
+  } else if (!m_non_primary_global_image_id.empty()) {
+    image_state_update();
     return;
   }
-  ldout(m_cct, 10) << this << " " << __func__ << dendl;
+
+  ldout(m_cct, 10)  << dendl;
 
   using klass = EnableRequest<I>;
   Context *ctx = create_context_callback<
@@ -108,80 +123,126 @@ void EnableRequest<I>::send_get_tag_owner() {
 }
 
 template <typename I>
-Context *EnableRequest<I>::handle_get_tag_owner(int *result) {
-  ldout(m_cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
+void EnableRequest<I>::handle_get_tag_owner(int r) {
+  ldout(m_cct, 10) << "r=" << r << dendl;
 
-  if (*result < 0) {
-    lderr(m_cct) << "failed to check tag ownership: " << cpp_strerror(*result)
+  if (r < 0) {
+    lderr(m_cct) << "failed to check tag ownership: " << cpp_strerror(r)
                  << dendl;
-    return m_on_finish;
+    finish(r);
+    return;
   }
 
   if (!m_is_primary) {
     lderr(m_cct) << "last journal tag not owned by local cluster" << dendl;
-    *result = -EINVAL;
-    return m_on_finish;
+    finish(-EINVAL);
+    return;
   }
 
-  send_set_mirror_image();
-  return nullptr;
+  image_state_update();
 }
 
 template <typename I>
-void EnableRequest<I>::send_set_mirror_image() {
-  ldout(m_cct, 10) << this << " " << __func__ << dendl;
+void EnableRequest<I>::create_primary_snapshot() {
+  if (!m_non_primary_global_image_id.empty()) {
+    // special case for rbd-mirror creating a non-primary image
+    enable_non_primary_feature();
+    return;
+  }
 
-  librados::ObjectWriteOperation op;
-  cls_client::mirror_image_set(&op, m_image_id, m_mirror_image);
+  ldout(m_cct, 10) << dendl;
 
-  using klass = EnableRequest<I>;
-  librados::AioCompletion *comp =
-    create_rados_callback<klass, &klass::handle_set_mirror_image>(this);
-  m_out_bl.clear();
-  int r = m_io_ctx.aio_operate(RBD_MIRRORING, comp, &op);
-  ceph_assert(r == 0);
-  comp->release();
+  ceph_assert(m_image_ctx != nullptr);
+  auto ctx = create_context_callback<
+    EnableRequest<I>,
+    &EnableRequest<I>::handle_create_primary_snapshot>(this);
+  auto req = snapshot::CreatePrimaryRequest<I>::create(
+    m_image_ctx, m_mirror_image.global_image_id,
+    snapshot::CREATE_PRIMARY_FLAG_IGNORE_EMPTY_PEERS, &m_snap_id, ctx);
+  req->send();
 }
 
 template <typename I>
-Context *EnableRequest<I>::handle_set_mirror_image(int *result) {
-  ldout(m_cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
+void EnableRequest<I>::handle_create_primary_snapshot(int r) {
+  ldout(m_cct, 10) << "r=" << r << dendl;
 
-  if (*result < 0) {
-    lderr(m_cct) << "failed to enable mirroring: " << cpp_strerror(*result)
-                 << dendl;
-    return m_on_finish;
+  if (r < 0) {
+    lderr(m_cct) << "failed to create initial primary snapshot: "
+                 << cpp_strerror(r) << dendl;
+    finish(r);
+    return;
+  }
+
+  image_state_update();
+}
+
+template <typename I>
+void EnableRequest<I>::enable_non_primary_feature() {
+  if (m_mirror_image.mode != cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT) {
+    image_state_update();
+    return;
   }
 
-  send_notify_mirroring_watcher();
-  return nullptr;
+  ldout(m_cct, 10) << dendl;
+
+  // ensure image is flagged with non-primary feature so that
+  // standard RBD clients cannot write to it.
+  librados::ObjectWriteOperation op;
+  cls_client::set_features(&op, RBD_FEATURE_NON_PRIMARY,
+                           RBD_FEATURE_NON_PRIMARY);
+
+  auto aio_comp = create_rados_callback<
+    EnableRequest<I>,
+    &EnableRequest<I>::handle_enable_non_primary_feature>(this);
+  int r = m_io_ctx.aio_operate(util::header_name(m_image_id), aio_comp, &op);
+  ceph_assert(r == 0);
+  aio_comp->release();
 }
 
 template <typename I>
-void EnableRequest<I>::send_notify_mirroring_watcher() {
-  ldout(m_cct, 10) << this << " " << __func__ << dendl;
+void EnableRequest<I>::handle_enable_non_primary_feature(int r) {
+  ldout(m_cct, 10) << "r=" << r << dendl;
 
-  using klass = EnableRequest<I>;
-  Context *ctx = create_context_callback<
-    klass, &klass::handle_notify_mirroring_watcher>(this);
+  if (r < 0) {
+    lderr(m_cct) << "failed to enable non-primary feature: "
+                 << cpp_strerror(r) << dendl;
+    finish(r);
+    return;
+  }
 
-  MirroringWatcher<>::notify_image_updated(m_io_ctx,
-                                           cls::rbd::MIRROR_IMAGE_STATE_ENABLED,
-                                           m_image_id,
-                                           m_mirror_image.global_image_id, ctx);
+  image_state_update();
+}
+
+template <typename I>
+void EnableRequest<I>::image_state_update() {
+  ldout(m_cct, 10) << dendl;
+
+  auto ctx = create_context_callback<
+    EnableRequest<I>, &EnableRequest<I>::handle_image_state_update>(this);
+  auto req = ImageStateUpdateRequest<I>::create(
+    m_io_ctx, m_image_id, cls::rbd::MIRROR_IMAGE_STATE_ENABLED,
+    m_mirror_image, ctx);
+  req->send();
 }
 
 template <typename I>
-Context *EnableRequest<I>::handle_notify_mirroring_watcher(int *result) {
-  ldout(m_cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
+void EnableRequest<I>::handle_image_state_update(int r) {
+  ldout(m_cct, 10) << "r=" << r << dendl;
 
-  if (*result < 0) {
-    lderr(m_cct) << "failed to send update notification: "
-                 << cpp_strerror(*result) << dendl;
-    *result = 0;
+  if (r < 0) {
+    lderr(m_cct) << "failed to enable mirroring: " << cpp_strerror(r)
+                 << dendl;
   }
 
-  return m_on_finish;
+  finish(r);
+}
+
+template <typename I>
+void EnableRequest<I>::finish(int r) {
+  ldout(m_cct, 10) << "r=" << r << dendl;
+
+  m_on_finish->complete(r);
+  delete this;
 }
 
 } // namespace mirror