]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/tools/rbd_mirror/ImageReplayer.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / tools / rbd_mirror / ImageReplayer.cc
index 2d51efe8bb4f13729f48a1bb44a6b3bb40c810b0..cec1f5463e6065f75610349d5a37f14086d1ca67 100644 (file)
@@ -9,7 +9,6 @@
 #include "include/stringify.h"
 #include "cls/rbd/cls_rbd_client.h"
 #include "common/Timer.h"
-#include "common/WorkQueue.h"
 #include "global/global_context.h"
 #include "journal/Journaler.h"
 #include "librbd/ExclusiveLock.h"
@@ -18,6 +17,7 @@
 #include "librbd/Journal.h"
 #include "librbd/Operations.h"
 #include "librbd/Utils.h"
+#include "librbd/asio/ContextWQ.h"
 #include "ImageDeleter.h"
 #include "ImageReplayer.h"
 #include "MirrorStatusUpdater.h"
@@ -36,8 +36,6 @@
 #define dout_prefix *_dout << "rbd::mirror::" << *this << " " \
                            << __func__ << ": "
 
-extern PerfCounters *g_perf_counters;
-
 namespace rbd {
 namespace mirror {
 
@@ -246,7 +244,7 @@ ImageReplayer<I>::~ImageReplayer()
   unregister_admin_socket_hook();
   ceph_assert(m_state_builder == nullptr);
   ceph_assert(m_on_start_finish == nullptr);
-  ceph_assert(m_on_stop_finish == nullptr);
+  ceph_assert(m_on_stop_contexts.empty());
   ceph_assert(m_bootstrap_request == nullptr);
   ceph_assert(m_update_status_task == nullptr);
   delete m_replayer_listener;
@@ -312,12 +310,13 @@ void ImageReplayer<I>::start(Context *on_finish, bool manual, bool restart)
       m_manual_stop = false;
       m_delete_requested = false;
       m_restart_requested = false;
+      m_status_removed = false;
 
       if (on_finish != nullptr) {
         ceph_assert(m_on_start_finish == nullptr);
         m_on_start_finish = on_finish;
       }
-      ceph_assert(m_on_stop_finish == nullptr);
+      ceph_assert(m_on_stop_contexts.empty());
     }
   }
 
@@ -396,6 +395,9 @@ void ImageReplayer<I>::handle_bootstrap(int r) {
     m_delete_requested = true;
     on_start_fail(0, "remote image no longer exists");
     return;
+  } else if (r == -ERESTART) {
+    on_start_fail(r, "image in transient state, try again");
+    return;
   } else if (r < 0) {
     on_start_fail(r, "error bootstrapping replay");
     return;
@@ -520,41 +522,56 @@ void ImageReplayer<I>::stop(Context *on_finish, bool manual, bool restart)
 
   image_replayer::BootstrapRequest<I> *bootstrap_request = nullptr;
   bool shut_down_replay = false;
-  bool running = true;
+  bool is_stopped = false;
   {
     std::lock_guard locker{m_lock};
 
-    if (restart) {
-      m_restart_requested = true;
-    }
-
     if (!is_running_()) {
-      running = false;
+      if (manual && !m_manual_stop) {
+        dout(10) << "marking manual" << dendl;
+        m_manual_stop = true;
+      }
       if (!restart && m_restart_requested) {
         dout(10) << "canceling restart" << dendl;
         m_restart_requested = false;
       }
+      if (is_stopped_()) {
+        dout(10) << "already stopped" << dendl;
+        is_stopped = true;
+      } else {
+        dout(10) << "joining in-flight stop" << dendl;
+        if (on_finish != nullptr) {
+          m_on_stop_contexts.push_back(on_finish);
+        }
+      }
     } else {
-      if (!is_stopped_()) {
-       if (m_state == STATE_STARTING) {
-         dout(10) << "canceling start" << dendl;
-         if (m_bootstrap_request != nullptr) {
-            bootstrap_request = m_bootstrap_request;
-            bootstrap_request->get();
-         }
-       } else {
-         dout(10) << "interrupting replay" << dendl;
-         shut_down_replay = true;
-       }
-
-        ceph_assert(m_on_stop_finish == nullptr);
-        std::swap(m_on_stop_finish, on_finish);
-        m_stop_requested = true;
-        m_manual_stop = manual;
+      if (m_state == STATE_STARTING) {
+        dout(10) << "canceling start" << dendl;
+        if (m_bootstrap_request != nullptr) {
+          bootstrap_request = m_bootstrap_request;
+          bootstrap_request->get();
+        }
+      } else {
+        dout(10) << "interrupting replay" << dendl;
+        shut_down_replay = true;
       }
+
+      ceph_assert(m_on_stop_contexts.empty());
+      if (on_finish != nullptr) {
+        m_on_stop_contexts.push_back(on_finish);
+      }
+      m_stop_requested = true;
+      m_manual_stop = manual;
     }
   }
 
+  if (is_stopped) {
+    if (on_finish) {
+      on_finish->complete(-EINVAL);
+    }
+    return;
+  }
+
   // avoid holding lock since bootstrap request will update status
   if (bootstrap_request != nullptr) {
     dout(10) << "canceling bootstrap" << dendl;
@@ -562,18 +579,8 @@ void ImageReplayer<I>::stop(Context *on_finish, bool manual, bool restart)
     bootstrap_request->put();
   }
 
-  if (!running) {
-    dout(20) << "not running" << dendl;
-    if (on_finish) {
-      on_finish->complete(-EINVAL);
-    }
-    return;
-  }
-
   if (shut_down_replay) {
     on_stop_journal_replay();
-  } else if (on_finish != nullptr) {
-    on_finish->complete(0);
   }
 }
 
@@ -930,6 +937,7 @@ void ImageReplayer<I>::handle_shut_down(int r) {
       dout(0) << "remote image no longer exists: scheduling deletion" << dendl;
       unregister_asok_hook = true;
       std::swap(delete_requested, m_delete_requested);
+      m_delete_in_progress = true;
     }
 
     std::swap(resync_requested, m_resync_requested);
@@ -965,23 +973,12 @@ void ImageReplayer<I>::handle_shut_down(int r) {
     return;
   }
 
-  if (m_local_status_updater->exists(m_global_image_id)) {
-    dout(15) << "removing local mirror image status" << dendl;
-    auto ctx = new LambdaContext([this, r](int) {
-        handle_shut_down(r);
-      });
-    m_local_status_updater->remove_mirror_image_status(m_global_image_id, ctx);
-    return;
-  }
-
-  if (m_remote_image_peer.mirror_status_updater != nullptr &&
-      m_remote_image_peer.mirror_status_updater->exists(m_global_image_id)) {
-    dout(15) << "removing remote mirror image status" << dendl;
+  if (!m_status_removed) {
     auto ctx = new LambdaContext([this, r](int) {
-        handle_shut_down(r);
-      });
-    m_remote_image_peer.mirror_status_updater->remove_mirror_image_status(
-      m_global_image_id, ctx);
+      m_status_removed = true;
+      handle_shut_down(r);
+    });
+    remove_image_status(m_delete_in_progress, ctx);
     return;
   }
 
@@ -992,11 +989,11 @@ void ImageReplayer<I>::handle_shut_down(int r) {
 
   dout(10) << "stop complete" << dendl;
   Context *on_start = nullptr;
-  Context *on_stop = nullptr;
+  Contexts on_stop_contexts;
   {
     std::lock_guard locker{m_lock};
     std::swap(on_start, m_on_start_finish);
-    std::swap(on_stop, m_on_stop_finish);
+    on_stop_contexts = std::move(m_on_stop_contexts);
     m_stop_requested = false;
     ceph_assert(m_state == STATE_STOPPING);
     m_state = STATE_STOPPED;
@@ -1007,9 +1004,9 @@ void ImageReplayer<I>::handle_shut_down(int r) {
     on_start->complete(r);
     r = 0;
   }
-  if (on_stop != nullptr) {
-    dout(10) << "on stop finish complete, r=" << r << dendl;
-    on_stop->complete(r);
+  for (auto ctx : on_stop_contexts) {
+    dout(10) << "on stop finish " << ctx << " complete, r=" << r << dendl;
+    ctx->complete(r);
   }
 }
 
@@ -1137,6 +1134,48 @@ void ImageReplayer<I>::reregister_admin_socket_hook() {
   register_admin_socket_hook();
 }
 
+template <typename I>
+void ImageReplayer<I>::remove_image_status(bool force, Context *on_finish)
+{
+  auto ctx = new LambdaContext([this, force, on_finish](int) {
+    remove_image_status_remote(force, on_finish);
+  });
+
+  if (m_local_status_updater->exists(m_global_image_id)) {
+    dout(15) << "removing local mirror image status" << dendl;
+    if (force) {
+      m_local_status_updater->remove_mirror_image_status(
+        m_global_image_id, true, ctx);
+    } else {
+      m_local_status_updater->remove_refresh_mirror_image_status(
+        m_global_image_id, ctx);
+    }
+    return;
+  }
+
+  ctx->complete(0);
+}
+
+template <typename I>
+void ImageReplayer<I>::remove_image_status_remote(bool force, Context *on_finish)
+{
+  if (m_remote_image_peer.mirror_status_updater != nullptr &&
+      m_remote_image_peer.mirror_status_updater->exists(m_global_image_id)) {
+    dout(15) << "removing remote mirror image status" << dendl;
+    if (force) {
+      m_remote_image_peer.mirror_status_updater->remove_mirror_image_status(
+        m_global_image_id, true, on_finish);
+    } else {
+      m_remote_image_peer.mirror_status_updater->remove_refresh_mirror_image_status(
+        m_global_image_id, on_finish);
+    }
+    return;
+  }
+  if (on_finish) {
+    on_finish->complete(0);
+  }
+}
+
 template <typename I>
 std::ostream &operator<<(std::ostream &os, const ImageReplayer<I> &replayer)
 {