#include "librbd/api/Image.h"
#include "librbd/api/Snapshot.h"
#include "librbd/api/Trash.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"
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>
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) {
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();
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 << ", "
+ << "snap_seqs=" << snap_seqs << dendl;
+
+ C_SaferCond 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, prog_ctx, &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
no_op));
}
+TEST_F(TestMigration, AbortWithoutSnapshots) {
+ test_no_snaps();
+ migration_prepare(m_ioctx, m_image_name);
+ migration_status(RBD_IMAGE_MIGRATION_STATE_PREPARED);
+ test_no_snaps();
+ migration_abort(m_ioctx, m_image_name);
+}
+
+TEST_F(TestMigration, AbortWithSnapshots) {
+ test_snaps();
+ migration_prepare(m_ioctx, m_image_name);
+ migration_status(RBD_IMAGE_MIGRATION_STATE_PREPARED);
+
+ test_no_snaps();
+ flush();
+ ASSERT_EQ(0, TestFixture::snap_create(*m_ictx, "dst-only-snap"));
+
+ test_no_snaps();
+
+ migration_abort(m_ioctx, m_image_name);
+}
+
TEST_F(TestMigration, CloneV1Parent)
{
const uint32_t CLONE_FORMAT = 1;