]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/librbd/api/Migration.cc
Import ceph 15.2.8
[ceph.git] / ceph / src / librbd / api / Migration.cc
index a5c22418293932fc3504e6f675c8c5ff0b6caa8a..7d6e29647374be6b7ca63013327d8f0974bbce95 100644 (file)
@@ -18,6 +18,8 @@
 #include "librbd/api/Image.h"
 #include "librbd/api/Snapshot.h"
 #include "librbd/api/Trash.h"
+#include "librbd/deep_copy/Handler.h"
+#include "librbd/deep_copy/ImageCopyRequest.h"
 #include "librbd/deep_copy/MetadataCopyRequest.h"
 #include "librbd/deep_copy/SnapshotCopyRequest.h"
 #include "librbd/exclusive_lock/Policy.h"
@@ -337,6 +339,30 @@ int open_source_image(librados::IoCtx& io_ctx, const std::string &image_name,
   return 0;
 }
 
+class SteppedProgressContext : public ProgressContext {
+public:
+  SteppedProgressContext(ProgressContext* progress_ctx, size_t total_steps)
+    : m_progress_ctx(progress_ctx), m_total_steps(total_steps) {
+  }
+
+  void next_step() {
+    ceph_assert(m_current_step < m_total_steps);
+    ++m_current_step;
+  }
+
+  int update_progress(uint64_t object_number,
+                      uint64_t object_count) override {
+    return m_progress_ctx->update_progress(
+      object_number + (object_count * (m_current_step - 1)),
+      object_count * m_total_steps);
+  }
+
+private:
+  ProgressContext* m_progress_ctx;
+  size_t m_total_steps;
+  size_t m_current_step = 1;
+};
+
 } // anonymous namespace
 
 template <typename I>
@@ -791,8 +817,41 @@ int Migration<I>::abort() {
     ldout(m_cct, 1) << "failed to open destination image: " << cpp_strerror(r)
                     << dendl;
   } else {
-    ldout(m_cct, 10) << "relinking children" << dendl;
+    BOOST_SCOPE_EXIT_TPL(&dst_image_ctx) {
+      if (dst_image_ctx != nullptr) {
+        dst_image_ctx->state->close();
+      }
+    } BOOST_SCOPE_EXIT_END;
 
+    std::list<obj_watch_t> watchers;
+    int flags = librbd::image::LIST_WATCHERS_FILTER_OUT_MY_INSTANCE |
+                librbd::image::LIST_WATCHERS_FILTER_OUT_MIRROR_INSTANCES;
+    C_SaferCond on_list_watchers;
+    auto list_watchers_request = librbd::image::ListWatchersRequest<I>::create(
+        *dst_image_ctx, flags, &watchers, &on_list_watchers);
+    list_watchers_request->send();
+    r = on_list_watchers.wait();
+    if (r < 0) {
+      lderr(m_cct) << "failed listing watchers:" << cpp_strerror(r) << dendl;
+      return r;
+    }
+    if (!watchers.empty()) {
+      lderr(m_cct) << "image has watchers - cannot abort migration" << dendl;
+      return -EBUSY;
+    }
+
+    // ensure destination image is now read-only
+    r = set_state(cls::rbd::MIGRATION_STATE_ABORTING, "");
+    if (r < 0) {
+      return r;
+    }
+
+    // copy dst HEAD -> src HEAD
+    SteppedProgressContext progress_ctx(m_prog_ctx, 2);
+    revert_data(dst_image_ctx, m_src_image_ctx, &progress_ctx);
+    progress_ctx.next_step();
+
+    ldout(m_cct, 10) << "relinking children" << dendl;
     r = relink_children(dst_image_ctx, m_src_image_ctx);
     if (r < 0) {
       return r;
@@ -800,12 +859,6 @@ int Migration<I>::abort() {
 
     ldout(m_cct, 10) << "removing dst image snapshots" << dendl;
 
-    BOOST_SCOPE_EXIT_TPL(&dst_image_ctx) {
-      if (dst_image_ctx != nullptr) {
-        dst_image_ctx->state->close();
-      }
-    } BOOST_SCOPE_EXIT_END;
-
     std::vector<librbd::snap_info_t> snaps;
     r = Snapshot<I>::list(dst_image_ctx, snaps);
     if (r < 0) {
@@ -841,7 +894,7 @@ int Migration<I>::abort() {
     ImageCtx::get_thread_pool_instance(m_cct, &thread_pool, &op_work_queue);
     C_SaferCond on_remove;
     auto req = librbd::image::RemoveRequest<>::create(
-      m_dst_io_ctx, dst_image_ctx, false, false, *m_prog_ctx, op_work_queue,
+      m_dst_io_ctx, dst_image_ctx, false, false, progress_ctx, op_work_queue,
       &on_remove);
     req->send();
     r = on_remove.wait();
@@ -853,7 +906,7 @@ int Migration<I>::abort() {
                    << m_dst_io_ctx.get_pool_name() << "/" << m_dst_image_name
                    << " (" << m_dst_image_id << ")': " << cpp_strerror(r)
                    << dendl;
-      // not fatal
+      return r;
     }
   }
 
@@ -1793,6 +1846,62 @@ int Migration<I>::remove_src_image() {
   return 0;
 }
 
+template <typename I>
+int Migration<I>::revert_data(I* src_image_ctx, I* dst_image_ctx,
+                              ProgressContext* prog_ctx) {
+  ldout(m_cct, 10) << dendl;
+
+  cls::rbd::MigrationSpec migration_spec;
+  int r = cls_client::migration_get(&src_image_ctx->md_ctx,
+                                    src_image_ctx->header_oid,
+                                    &migration_spec);
+
+  if (r < 0) {
+    lderr(m_cct) << "failed retrieving migration header: " << cpp_strerror(r)
+                 << dendl;
+    return r;
+  }
+
+  if (migration_spec.header_type != cls::rbd::MIGRATION_HEADER_TYPE_DST) {
+    lderr(m_cct) << "unexpected migration header type: "
+                 << migration_spec.header_type << dendl;
+    return -EINVAL;
+  }
+
+  uint64_t src_snap_id_start = 0;
+  uint64_t src_snap_id_end = CEPH_NOSNAP;
+  uint64_t dst_snap_id_start = 0;
+  if (!migration_spec.snap_seqs.empty()) {
+    src_snap_id_start = migration_spec.snap_seqs.rbegin()->second;
+  }
+
+  // we only care about the HEAD revision so only add a single mapping to
+  // represent the most recent state
+  SnapSeqs snap_seqs;
+  snap_seqs[CEPH_NOSNAP] = CEPH_NOSNAP;
+
+  ldout(m_cct, 20) << "src_snap_id_start=" << src_snap_id_start << ", "
+                   << "src_snap_id_end=" << src_snap_id_end << ", "
+                   << "dst_snap_id_start=" << dst_snap_id_start << ", "
+                   << "snap_seqs=" << snap_seqs << dendl;
+
+  C_SaferCond ctx;
+  deep_copy::ProgressHandler progress_handler(prog_ctx);
+  auto request = deep_copy::ImageCopyRequest<I>::create(
+    src_image_ctx, dst_image_ctx, src_snap_id_start, src_snap_id_end,
+    dst_snap_id_start, false, {}, snap_seqs, &progress_handler, &ctx);
+  request->send();
+
+  r = ctx.wait();
+  if (r < 0) {
+    lderr(m_cct) << "error reverting destination image data blocks back to "
+                 << "source image: " << cpp_strerror(r) << dendl;
+    return r;
+  }
+
+  return 0;
+}
+
 } // namespace api
 } // namespace librbd