]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/librbd/mirror/DisableRequest.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / librbd / mirror / DisableRequest.cc
index 6a21c5608d7a470087431f139352c3b4292a6a66..2d2dd874a80a4093b659c9f7a457aee46c6673a2 100644 (file)
@@ -6,18 +6,22 @@
 #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 {
@@ -28,82 +32,48 @@ template <typename I>
 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, "
@@ -112,33 +82,28 @@ Context *DisableRequest<I>::handle_get_tag_owner(int *result) {
     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)
@@ -146,77 +111,98 @@ Context *DisableRequest<I>::handle_set_mirror_image(int *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<
@@ -231,7 +217,7 @@ void DisableRequest<I>::send_get_clients() {
 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)
@@ -239,7 +225,7 @@ Context *DisableRequest<I>::handle_get_clients(int *result) {
     return m_on_finish;
   }
 
-  Mutex::Locker locker(m_lock);
+  std::lock_guard locker{m_lock};
 
   ceph_assert(m_current_ops.empty());
 
@@ -262,7 +248,7 @@ Context *DisableRequest<I>::handle_get_clients(int *result) {
 
     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;
     }
@@ -299,21 +285,49 @@ Context *DisableRequest<I>::handle_get_clients(int *result) {
 }
 
 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);
@@ -326,21 +340,30 @@ template <typename I>
 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);
   }
 
@@ -351,9 +374,9 @@ template <typename I>
 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(
@@ -379,9 +402,9 @@ Context *DisableRequest<I>::handle_unregister_client(
   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);
 
@@ -407,28 +430,21 @@ Context *DisableRequest<I>::handle_unregister_client(
 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)
@@ -436,39 +452,7 @@ Context *DisableRequest<I>::handle_remove_mirror_image(int *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;
 }
 
@@ -477,7 +461,7 @@ Context *DisableRequest<I>::create_context_callback(
   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);