]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: utilize new helper methods for updating mirror image records
authorJason Dillaman <dillaman@redhat.com>
Mon, 27 Jan 2020 22:35:46 +0000 (17:35 -0500)
committerJason Dillaman <dillaman@redhat.com>
Thu, 30 Jan 2020 15:26:36 +0000 (10:26 -0500)
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
src/librbd/image/RemoveRequest.cc
src/librbd/mirror/DisableRequest.cc
src/librbd/mirror/DisableRequest.h
src/librbd/mirror/EnableRequest.cc
src/librbd/mirror/EnableRequest.h
src/test/librbd/mirror/test_mock_DisableRequest.cc

index 7751fef62cb138f1d5d6ce981ad0c0bb4fd318c7..5a4f56adf518598e786c3bbabdd189a399893887 100644 (file)
@@ -8,7 +8,6 @@
 #include "librbd/ImageState.h"
 #include "librbd/Journal.h"
 #include "librbd/ObjectMap.h"
-#include "librbd/MirroringWatcher.h"
 #include "librbd/image/DetachChildRequest.h"
 #include "librbd/image/PreRemoveRequest.h"
 #include "librbd/journal/RemoveRequest.h"
index 2c0f669b3586b703d0d0c5bcc2f8de2f6bf1bc37..a436e7ebe46f64ceafc7b32cf25e1417cea498f8 100644 (file)
@@ -6,19 +6,20 @@
 #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/ImageState.h"
+#include "librbd/ImageCtx.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"
 
 #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 {
@@ -40,7 +41,7 @@ void DisableRequest<I>::send() {
 template <typename I>
 void DisableRequest<I>::send_get_mirror_info() {
   CephContext *cct = m_image_ctx->cct;
-  ldout(cct, 10) << this << " " << __func__ << dendl;
+  ldout(cct, 10) << dendl;
 
 
   using klass = DisableRequest<I>;
@@ -56,12 +57,11 @@ void DisableRequest<I>::send_get_mirror_info() {
 template <typename I>
 Context *DisableRequest<I>::handle_get_mirror_info(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) {
     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 {
       lderr(cct) << "failed to get mirroring info: " << cpp_strerror(*result)
@@ -79,32 +79,28 @@ Context *DisableRequest<I>::handle_get_mirror_info(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);
-  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)
@@ -112,35 +108,6 @@ Context *DisableRequest<I>::handle_set_mirror_image(int *result) {
     return m_on_finish;
   }
 
-  send_notify_mirroring_watcher();
-  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);
-
-  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);
-}
-
-template <typename I>
-Context *DisableRequest<I>::handle_notify_mirroring_watcher(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;
-  }
-
   if (m_mirror_image.mode == cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT) {
     // remove mirroring snapshots
 
@@ -180,7 +147,7 @@ void DisableRequest<I>::send_promote_image() {
   }
 
   CephContext *cct = m_image_ctx->cct;
-  ldout(cct, 10) << this << " " << __func__ << dendl;
+  ldout(cct, 10) << dendl;
 
   // Not primary -- shouldn't have the journal open
   ceph_assert(m_image_ctx->journal == nullptr);
@@ -195,7 +162,7 @@ void DisableRequest<I>::send_promote_image() {
 template <typename I>
 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 promote image: " << cpp_strerror(*result) << dendl;
@@ -209,7 +176,7 @@ Context *DisableRequest<I>::handle_promote_image(int *result) {
 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<
@@ -224,7 +191,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)
@@ -255,7 +222,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;
     }
@@ -292,11 +259,12 @@ 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>::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) << this << " " << __func__ << ": client_id=" << client_id
+  ldout(cct, 10) << "client_id=" << client_id
                  << ", snap_name=" << snap_name << dendl;
 
   ceph_assert(ceph_mutex_is_locked(m_lock));
@@ -319,7 +287,7 @@ 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;
 
   std::lock_guard locker{m_lock};
 
@@ -353,7 +321,7 @@ 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(ceph_mutex_is_locked(m_lock));
   ceph_assert(m_current_ops[client_id] == 0);
@@ -381,7 +349,7 @@ 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;
 
   std::lock_guard locker{m_lock};
   ceph_assert(m_current_ops[client_id] == 0);
@@ -409,27 +377,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);
-  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)
@@ -437,39 +399,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;
 }
 
index d753076243ad8fe65ae1699e22d4d482a2de0fb7..39cb2539f6620e50878fc8590d8ecb0522ac89aa 100644 (file)
@@ -44,10 +44,7 @@ private:
    * GET_MIRROR_INFO  * * * * * * * * * * * * * * * * * * * * * * *
    *    |                                                         *
    *    v                                                         *
-   * SET_MIRROR_IMAGE * * * * * * * * * * * * * * * * * * * * * * *
-   *    |                                                         *
-   *    v                                                         *
-   * NOTIFY_MIRRORING_WATCHER                                     *
+   * IMAGE_STATE_UPDATE * * * * * * * * * * * * * * * * * * * * * *
    *    |                                                         *
    *    v                                                         *
    * PROMOTE_IMAGE (skip if primary)                              *
@@ -71,9 +68,6 @@ private:
    * REMOVE_MIRROR_IMAGE  * * * * * * * * * * * * * * * * * * * * *
    *    |         (skip if no remove)                             *
    *    v                                                         *
-   * NOTIFY_MIRRORING_WATCHER_REMOVED                             *
-   *    |         (skip if not primary or no remove)              *
-   *    v                                                         *
    * <finish> < * * * * * * * * * * * * * * * * * * * * * * * * * *
    *
    * @endverbatim
@@ -98,8 +92,8 @@ private:
   void send_get_mirror_info();
   Context *handle_get_mirror_info(int *result);
 
-  void send_set_mirror_image();
-  Context *handle_set_mirror_image(int *result);
+  void send_image_state_update();
+  Context *handle_image_state_update(int *result);
 
   void send_notify_mirroring_watcher();
   Context *handle_notify_mirroring_watcher(int *result);
index beea237038fcdd176d567918f00cc32ef0ffede5..aa550e53913e880bbacdc6619398d06e031c2e58 100644 (file)
@@ -7,12 +7,13 @@
 #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"
 
 #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 {
@@ -40,7 +41,7 @@ void EnableRequest<I>::send() {
 
 template <typename I>
 void EnableRequest<I>::send_get_mirror_image() {
-  ldout(m_cct, 10) << this << " " << __func__ << dendl;
+  ldout(m_cct, 10) << dendl;
 
   librados::ObjectReadOperation op;
   cls_client::mirror_image_get_start(&op, m_image_id);
@@ -56,7 +57,7 @@ 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;
+  ldout(m_cct, 10) << "r=" << *result << dendl;
 
   if (*result == 0) {
     auto iter = m_out_bl.cbegin();
@@ -68,8 +69,7 @@ Context *EnableRequest<I>::handle_get_mirror_image(int *result) {
       lderr(m_cct) << "invalid current image mirror mode" << dendl;
       *result = -EINVAL;
     } else if (m_mirror_image.state == cls::rbd::MIRROR_IMAGE_STATE_ENABLED) {
-      ldout(m_cct, 10) << this << " " << __func__
-                       << ": mirroring is already enabled" << dendl;
+      ldout(m_cct, 10) << "mirroring is already enabled" << dendl;
     } else {
       lderr(m_cct) << "currently disabling" << dendl;
       *result = -EINVAL;
@@ -92,7 +92,6 @@ Context *EnableRequest<I>::handle_get_mirror_image(int *result) {
   } else {
     m_mirror_image.global_image_id = m_non_primary_global_image_id;
   }
-  m_mirror_image.state = cls::rbd::MIRROR_IMAGE_STATE_ENABLED;
 
   send_get_tag_owner();
   return nullptr;
@@ -102,10 +101,10 @@ template <typename I>
 void EnableRequest<I>::send_get_tag_owner() {
   if (m_mirror_image.mode == cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT ||
       !m_non_primary_global_image_id.empty()) {
-    send_set_mirror_image();
+    send_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<
@@ -116,7 +115,7 @@ 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;
+  ldout(m_cct, 10) << "r=" << *result << dendl;
 
   if (*result < 0) {
     lderr(m_cct) << "failed to check tag ownership: " << cpp_strerror(*result)
@@ -130,61 +129,29 @@ Context *EnableRequest<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 EnableRequest<I>::send_set_mirror_image() {
-  ldout(m_cct, 10) << this << " " << __func__ << dendl;
-
-  librados::ObjectWriteOperation op;
-  cls_client::mirror_image_set(&op, m_image_id, m_mirror_image);
-
-  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();
+void EnableRequest<I>::send_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_set_mirror_image(int *result) {
-  ldout(m_cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
+Context *EnableRequest<I>::handle_image_state_update(int *result) {
+  ldout(m_cct, 10) << "r=" << *result << dendl;
 
   if (*result < 0) {
     lderr(m_cct) << "failed to enable mirroring: " << cpp_strerror(*result)
                  << dendl;
-    return m_on_finish;
-  }
-
-  send_notify_mirroring_watcher();
-  return nullptr;
-}
-
-template <typename I>
-void EnableRequest<I>::send_notify_mirroring_watcher() {
-  ldout(m_cct, 10) << this << " " << __func__ << dendl;
-
-  using klass = EnableRequest<I>;
-  Context *ctx = create_context_callback<
-    klass, &klass::handle_notify_mirroring_watcher>(this);
-
-  MirroringWatcher<>::notify_image_updated(m_io_ctx,
-                                           m_mirror_image.state, m_image_id,
-                                           m_mirror_image.global_image_id, ctx);
-}
-
-template <typename I>
-Context *EnableRequest<I>::handle_notify_mirroring_watcher(int *result) {
-  ldout(m_cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
-
-  if (*result < 0) {
-    lderr(m_cct) << "failed to send update notification: "
-                 << cpp_strerror(*result) << dendl;
-    *result = 0;
   }
 
   return m_on_finish;
index 9fa3c63304c1134f9c9eca48b23acdc6a701dc80..ad3c2af171f7ea01a9f5d875048f057bb5a19c4d 100644 (file)
@@ -8,6 +8,7 @@
 #include "include/rados/librados_fwd.hpp"
 #include "include/rbd/librbd.hpp"
 #include "cls/rbd/cls_rbd_types.h"
+#include "librbd/ImageCtx.h"
 #include <map>
 #include <string>
 
@@ -15,9 +16,6 @@ class Context;
 class ContextWQ;
 
 namespace librbd {
-
-class ImageCtx;
-
 namespace mirror {
 
 template <typename ImageCtxT = ImageCtx>
@@ -53,10 +51,7 @@ private:
    * GET_TAG_OWNER  * * * * * * * *
    *    |  (skip if not needed)   *
    *    v                         *
-   * SET_MIRROR_IMAGE * * * * * * *
-   *    |                         *
-   *    v                         *
-   * NOTIFY_MIRRORING_WATCHER * * *
+   * IMAGE_STATE_UPDATE * * * * * *
    *    |                         *
    *    v                         *
    * <finish>   < * * * * * * * * *
@@ -90,11 +85,8 @@ private:
   void send_get_tag_owner();
   Context *handle_get_tag_owner(int *result);
 
-  void send_set_mirror_image();
-  Context *handle_set_mirror_image(int *result);
-
-  void send_notify_mirroring_watcher();
-  Context *handle_notify_mirroring_watcher(int *result);
+  void send_image_state_update();
+  Context *handle_image_state_update(int *result);
 };
 
 } // namespace mirror
index 684c05d100df2fbce99b8dbda0913c72e58f845d..37eed983b7b88be24b210f11b474e2708d7e2173 100644 (file)
@@ -7,10 +7,11 @@
 #include "test/librbd/mock/MockOperations.h"
 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
 #include "test/librados_test_stub/MockTestMemRadosClient.h"
-#include "librbd/MirroringWatcher.h"
 #include "librbd/journal/PromoteRequest.h"
 #include "librbd/mirror/DisableRequest.h"
 #include "librbd/mirror/GetInfoRequest.h"
+#include "librbd/mirror/ImageRemoveRequest.h"
+#include "librbd/mirror/ImageStateUpdateRequest.h"
 
 namespace librbd {
 
@@ -23,31 +24,6 @@ struct MockTestImageCtx : public MockImageCtx {
 
 } // anonymous namespace
 
-template <>
-struct MirroringWatcher<librbd::MockTestImageCtx> {
-  static MirroringWatcher *s_instance;
-  static void notify_image_updated(librados::IoCtx &io_ctx,
-                                   cls::rbd::MirrorImageState mirror_image_state,
-                                   const std::string &image_id,
-                                   const std::string &global_image_id,
-                                   Context *on_finish) {
-    ceph_assert(s_instance != nullptr);
-    s_instance->notify_image_updated(mirror_image_state, image_id,
-                                     global_image_id, on_finish);
-  }
-
-  MirroringWatcher() {
-    s_instance = this;
-  }
-
-  MOCK_METHOD4(notify_image_updated, void(cls::rbd::MirrorImageState,
-                                          const std::string &,
-                                          const std::string &,
-                                          Context *));
-};
-
-MirroringWatcher<librbd::MockTestImageCtx> *MirroringWatcher<librbd::MockTestImageCtx>::s_instance = nullptr;
-
 namespace journal {
 
 template <>
@@ -99,7 +75,54 @@ struct GetInfoRequest<librbd::MockTestImageCtx> {
   MOCK_METHOD0(send, void());
 };
 
+template <>
+struct ImageRemoveRequest<librbd::MockTestImageCtx> {
+  static ImageRemoveRequest* s_instance;
+  Context* on_finish = nullptr;
+
+  static ImageRemoveRequest* create(
+      librados::IoCtx& io_ctx,
+      const std::string& global_image_id,
+      const std::string& image_id,
+      Context* on_finish) {
+    ceph_assert(s_instance != nullptr);
+    s_instance->on_finish = on_finish;
+    return s_instance;
+  }
+
+  MOCK_METHOD0(send, void());
+
+  ImageRemoveRequest() {
+    s_instance = this;
+  }
+};
+
+template <>
+struct ImageStateUpdateRequest<librbd::MockTestImageCtx> {
+  static ImageStateUpdateRequest* s_instance;
+  Context* on_finish = nullptr;
+
+  static ImageStateUpdateRequest* create(
+      librados::IoCtx& io_ctx,
+      const std::string& image_id,
+      cls::rbd::MirrorImageState mirror_image_state,
+      const cls::rbd::MirrorImage& mirror_image,
+      Context* on_finish) {
+    ceph_assert(s_instance != nullptr);
+    s_instance->on_finish = on_finish;
+    return s_instance;
+  }
+
+  MOCK_METHOD0(send, void());
+
+  ImageStateUpdateRequest() {
+    s_instance = this;
+  }
+};
+
 GetInfoRequest<librbd::MockTestImageCtx> *GetInfoRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
+ImageRemoveRequest<librbd::MockTestImageCtx> *ImageRemoveRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
+ImageStateUpdateRequest<librbd::MockTestImageCtx> *ImageStateUpdateRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
 
 } // namespace mirror
 } // namespace librbd
@@ -127,9 +150,10 @@ class TestMockMirrorDisableRequest : public TestMockFixture {
 public:
   typedef DisableRequest<MockTestImageCtx> MockDisableRequest;
   typedef Journal<MockTestImageCtx> MockJournal;
-  typedef MirroringWatcher<MockTestImageCtx> MockMirroringWatcher;
   typedef journal::PromoteRequest<MockTestImageCtx> MockPromoteRequest;
   typedef mirror::GetInfoRequest<MockTestImageCtx> MockGetInfoRequest;
+  typedef mirror::ImageRemoveRequest<MockTestImageCtx> MockImageRemoveRequest;
+  typedef mirror::ImageStateUpdateRequest<MockTestImageCtx> MockImageStateUpdateRequest;
 
   void expect_get_mirror_info(MockTestImageCtx &mock_image_ctx,
                               MockGetInfoRequest &mock_get_info_request,
@@ -149,27 +173,24 @@ public:
                }));
   }
 
-  void expect_set_mirror_image(MockTestImageCtx &mock_image_ctx, int r) {
-    EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
-                exec(RBD_MIRRORING, _, StrEq("rbd"), StrEq("mirror_image_set"),
-                     _, _, _))
-      .WillOnce(Return(r));
-  }
-
-  void expect_remove_mirror_image(MockTestImageCtx &mock_image_ctx, int r) {
-    EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
-                exec(RBD_MIRRORING, _, StrEq("rbd"), StrEq("mirror_image_remove"),
-                     _, _, _))
-      .WillOnce(Return(r));
+  void expect_mirror_image_state_update(
+      MockTestImageCtx &mock_image_ctx,
+      MockImageStateUpdateRequest& mock_request, int r) {
+    EXPECT_CALL(mock_request, send())
+      .WillOnce(
+        Invoke([this, &mock_image_ctx, &mock_request, r]() {
+          mock_image_ctx.op_work_queue->queue(mock_request.on_finish, r);
+        }));
   }
 
-  void expect_notify_image_updated(MockTestImageCtx &mock_image_ctx,
-                                   MockMirroringWatcher &mock_mirroring_watcher,
-                                   cls::rbd::MirrorImageState state,
-                                   const std::string &global_id, int r) {
-    EXPECT_CALL(mock_mirroring_watcher,
-                notify_image_updated(state, mock_image_ctx.id, global_id, _))
-      .WillOnce(WithArg<3>(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)));
+  void expect_mirror_image_remove(
+      MockTestImageCtx &mock_image_ctx,
+      MockImageRemoveRequest& mock_request, int r) {
+    EXPECT_CALL(mock_request, send())
+      .WillOnce(
+        Invoke([this, &mock_image_ctx, &mock_request, r]() {
+          mock_image_ctx.op_work_queue->queue(mock_request.on_finish, r);
+        }));
   }
 
   void expect_journal_client_list(MockTestImageCtx &mock_image_ctx,
@@ -229,7 +250,6 @@ TEST_F(TestMockMirrorDisableRequest, Success) {
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
   MockTestImageCtx mock_image_ctx(*ictx);
-  MockMirroringWatcher mock_mirroring_watcher;
 
   expect_op_work_queue(mock_image_ctx);
   expect_snap_remove(mock_image_ctx, "snap 1", 0);
@@ -242,10 +262,9 @@ TEST_F(TestMockMirrorDisableRequest, Success) {
     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,
-                              "global id", -ESHUTDOWN);
+  MockImageStateUpdateRequest mock_image_state_update_request;
+  expect_mirror_image_state_update(
+    mock_image_ctx, mock_image_state_update_request, 0);
   expect_journal_client_list(
     mock_image_ctx, {
       {"", encode(journal::ClientData{journal::ImageClientMeta{}})},
@@ -258,10 +277,9 @@ TEST_F(TestMockMirrorDisableRequest, Success) {
   expect_journal_client_unregister(mock_image_ctx, "peer 1", 0);
   expect_journal_client_unregister(mock_image_ctx, "peer 2", 0);
   expect_journal_client_list(mock_image_ctx, {}, 0);
-  expect_remove_mirror_image(mock_image_ctx, 0);
-  expect_notify_image_updated(mock_image_ctx, mock_mirroring_watcher,
-                              cls::rbd::MIRROR_IMAGE_STATE_DISABLED,
-                              "global id", -ETIMEDOUT);
+  MockImageRemoveRequest mock_image_remove_request;
+  expect_mirror_image_remove(
+    mock_image_ctx, mock_image_remove_request, 0);
 
   C_SaferCond ctx;
   auto req = new MockDisableRequest(&mock_image_ctx, false, true, &ctx);
@@ -276,7 +294,6 @@ TEST_F(TestMockMirrorDisableRequest, SuccessNoRemove) {
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
   MockTestImageCtx mock_image_ctx(*ictx);
-  MockMirroringWatcher mock_mirroring_watcher;
 
   expect_op_work_queue(mock_image_ctx);
 
@@ -287,10 +304,9 @@ TEST_F(TestMockMirrorDisableRequest, SuccessNoRemove) {
     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,
-                              "global id", 0);
+  MockImageStateUpdateRequest mock_image_state_update_request;
+  expect_mirror_image_state_update(
+    mock_image_ctx, mock_image_state_update_request, 0);
   expect_journal_client_list(mock_image_ctx, {}, 0);
 
   C_SaferCond ctx;
@@ -306,7 +322,6 @@ TEST_F(TestMockMirrorDisableRequest, SuccessNonPrimary) {
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
   MockTestImageCtx mock_image_ctx(*ictx);
-  MockMirroringWatcher mock_mirroring_watcher;
   MockPromoteRequest mock_promote_request;
 
   expect_op_work_queue(mock_image_ctx);
@@ -318,16 +333,14 @@ TEST_F(TestMockMirrorDisableRequest, SuccessNonPrimary) {
     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,
-                              "global id", 0);
+  MockImageStateUpdateRequest mock_image_state_update_request;
+  expect_mirror_image_state_update(
+    mock_image_ctx, mock_image_state_update_request, 0);
   expect_journal_promote(mock_image_ctx, mock_promote_request, 0);
   expect_journal_client_list(mock_image_ctx, {}, 0);
-  expect_remove_mirror_image(mock_image_ctx, 0);
-  expect_notify_image_updated(mock_image_ctx, mock_mirroring_watcher,
-                              cls::rbd::MIRROR_IMAGE_STATE_DISABLED,
-                              "global id", 0);
+  MockImageRemoveRequest mock_image_remove_request;
+  expect_mirror_image_remove(
+    mock_image_ctx, mock_image_remove_request, 0);
 
   C_SaferCond ctx;
   auto req = new MockDisableRequest(&mock_image_ctx, true, true, &ctx);
@@ -342,7 +355,6 @@ TEST_F(TestMockMirrorDisableRequest, NonPrimaryError) {
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
   MockTestImageCtx mock_image_ctx(*ictx);
-  MockMirroringWatcher mock_mirroring_watcher;
 
   expect_op_work_queue(mock_image_ctx);
 
@@ -401,7 +413,9 @@ TEST_F(TestMockMirrorDisableRequest, MirrorImageSetError) {
     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);
+  MockImageStateUpdateRequest mock_image_state_update_request;
+  expect_mirror_image_state_update(
+    mock_image_ctx, mock_image_state_update_request, -ENOENT);
 
   C_SaferCond ctx;
   auto req = new MockDisableRequest(&mock_image_ctx, false, true, &ctx);
@@ -416,7 +430,6 @@ TEST_F(TestMockMirrorDisableRequest, JournalPromoteError) {
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
   MockTestImageCtx mock_image_ctx(*ictx);
-  MockMirroringWatcher mock_mirroring_watcher;
   MockPromoteRequest mock_promote_request;
 
   expect_op_work_queue(mock_image_ctx);
@@ -428,10 +441,9 @@ TEST_F(TestMockMirrorDisableRequest, JournalPromoteError) {
     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,
-                              "global id", 0);
+  MockImageStateUpdateRequest mock_image_state_update_request;
+  expect_mirror_image_state_update(
+    mock_image_ctx, mock_image_state_update_request, 0);
   expect_journal_promote(mock_image_ctx, mock_promote_request, -EPERM);
 
   C_SaferCond ctx;
@@ -447,7 +459,6 @@ TEST_F(TestMockMirrorDisableRequest, JournalClientListError) {
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
   MockTestImageCtx mock_image_ctx(*ictx);
-  MockMirroringWatcher mock_mirroring_watcher;
 
   expect_op_work_queue(mock_image_ctx);
 
@@ -458,10 +469,9 @@ TEST_F(TestMockMirrorDisableRequest, JournalClientListError) {
     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,
-                              "global id", 0);
+  MockImageStateUpdateRequest mock_image_state_update_request;
+  expect_mirror_image_state_update(
+    mock_image_ctx, mock_image_state_update_request, 0);
   expect_journal_client_list(mock_image_ctx, {}, -EBADMSG);
 
   C_SaferCond ctx;
@@ -477,7 +487,6 @@ TEST_F(TestMockMirrorDisableRequest, SnapRemoveError) {
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
   MockTestImageCtx mock_image_ctx(*ictx);
-  MockMirroringWatcher mock_mirroring_watcher;
 
   expect_op_work_queue(mock_image_ctx);
   expect_snap_remove(mock_image_ctx, "snap 1", 0);
@@ -490,10 +499,9 @@ TEST_F(TestMockMirrorDisableRequest, SnapRemoveError) {
     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,
-                              "global id", 0);
+  MockImageStateUpdateRequest mock_image_state_update_request;
+  expect_mirror_image_state_update(
+    mock_image_ctx, mock_image_state_update_request, 0);
   expect_journal_client_list(
     mock_image_ctx, {
       {"", encode(journal::ClientData{journal::ImageClientMeta{}})},
@@ -518,7 +526,6 @@ TEST_F(TestMockMirrorDisableRequest, JournalClientUnregisterError) {
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
   MockTestImageCtx mock_image_ctx(*ictx);
-  MockMirroringWatcher mock_mirroring_watcher;
 
   expect_op_work_queue(mock_image_ctx);
   expect_snap_remove(mock_image_ctx, "snap 1", 0);
@@ -531,10 +538,9 @@ TEST_F(TestMockMirrorDisableRequest, JournalClientUnregisterError) {
     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,
-                              "global id", 0);
+  MockImageStateUpdateRequest mock_image_state_update_request;
+  expect_mirror_image_state_update(
+    mock_image_ctx, mock_image_state_update_request, 0);
   expect_journal_client_list(
     mock_image_ctx, {
       {"", encode(journal::ClientData{journal::ImageClientMeta{}})},
@@ -560,7 +566,6 @@ TEST_F(TestMockMirrorDisableRequest, MirrorImageRemoveError) {
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
   MockTestImageCtx mock_image_ctx(*ictx);
-  MockMirroringWatcher mock_mirroring_watcher;
 
   expect_op_work_queue(mock_image_ctx);
 
@@ -571,12 +576,13 @@ TEST_F(TestMockMirrorDisableRequest, MirrorImageRemoveError) {
     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,
-                              "global id", 0);
+  MockImageStateUpdateRequest mock_image_state_update_request;
+  expect_mirror_image_state_update(
+    mock_image_ctx, mock_image_state_update_request, 0);
   expect_journal_client_list(mock_image_ctx, {}, 0);
-  expect_remove_mirror_image(mock_image_ctx, -EINVAL);
+  MockImageRemoveRequest mock_image_remove_request;
+  expect_mirror_image_remove(
+    mock_image_ctx, mock_image_remove_request, -EINVAL);
 
   C_SaferCond ctx;
   auto req = new MockDisableRequest(&mock_image_ctx, false, true, &ctx);