managed_lock/ReacquireRequest.cc
managed_lock/ReleaseRequest.cc
managed_lock/Utils.cc
+ migration/ImageDispatch.cc
+ migration/NativeFormat.cc
+ migration/OpenSourceImageRequest.cc
mirror/DemoteRequest.cc
mirror/DisableRequest.cc
mirror/EnableRequest.cc
IMAGE_DISPATCH_LAYER_EXCLUSIVE_LOCK,
IMAGE_DISPATCH_LAYER_REFRESH,
IMAGE_DISPATCH_LAYER_INTERNAL_START = IMAGE_DISPATCH_LAYER_REFRESH,
+ IMAGE_DISPATCH_LAYER_MIGRATION,
IMAGE_DISPATCH_LAYER_JOURNAL,
IMAGE_DISPATCH_LAYER_WRITE_BLOCK,
IMAGE_DISPATCH_LAYER_WRITEBACK_CACHE,
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_LIBRBD_MIGRATION_FORMAT_INTERFACE_H
+#define CEPH_LIBRBD_MIGRATION_FORMAT_INTERFACE_H
+
+#include "include/buffer_fwd.h"
+#include "include/int_types.h"
+#include "common/zipkin_trace.h"
+#include "librbd/Types.h"
+#include "librbd/io/Types.h"
+#include <map>
+
+struct Context;
+
+namespace librbd {
+
+namespace io {
+struct AioCompletion;
+struct ReadResult;
+} // namespace io
+
+namespace migration {
+
+struct FormatInterface {
+ typedef std::map<uint64_t, SnapInfo> SnapInfos;
+
+ virtual ~FormatInterface() {
+ }
+
+ virtual void open(Context* on_finish) = 0;
+ virtual void close(Context* on_finish) = 0;
+
+ virtual void get_snapshots(SnapInfos* snap_infos, Context* on_finish) = 0;
+ virtual void get_image_size(uint64_t snap_id, uint64_t* size,
+ Context* on_finish) = 0;
+
+ virtual void read(io::AioCompletion* aio_comp, uint64_t snap_id,
+ io::Extents&& image_extents, io::ReadResult&& read_result,
+ int op_flags, int read_flags,
+ const ZTracer::Trace &parent_trace) = 0;
+
+ virtual void list_snaps(io::Extents&& image_extents, io::SnapIds&& snap_ids,
+ int list_snaps_flags,
+ io::SnapshotDelta* snapshot_delta,
+ const ZTracer::Trace &parent_trace,
+ Context* on_finish) = 0;
+};
+
+} // namespace migration
+} // namespace librbd
+
+#endif // CEPH_LIBRBD_MIGRATION_FORMAT_INTERFACE_H
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "librbd/migration/ImageDispatch.h"
+#include "include/neorados/RADOS.hpp"
+#include "common/dout.h"
+#include "librbd/ImageCtx.h"
+#include "librbd/io/AioCompletion.h"
+#include "librbd/migration/FormatInterface.h"
+
+#define dout_subsys ceph_subsys_rbd
+#undef dout_prefix
+#define dout_prefix *_dout << "librbd::migration::ImageDispatch: " << this \
+ << " " << __func__ << ": "
+
+namespace librbd {
+namespace migration {
+
+template <typename I>
+ImageDispatch<I>::ImageDispatch(I* image_ctx,
+ std::unique_ptr<FormatInterface> format)
+ : m_image_ctx(image_ctx), m_format(std::move(format)) {
+ auto cct = m_image_ctx->cct;
+ ldout(cct, 10) << "ictx=" << image_ctx << dendl;
+}
+
+template <typename I>
+void ImageDispatch<I>::shut_down(Context* on_finish) {
+ auto cct = m_image_ctx->cct;
+ ldout(cct, 10) << dendl;
+
+ on_finish->complete(0);
+}
+
+template <typename I>
+bool ImageDispatch<I>::read(
+ io::AioCompletion* aio_comp, io::Extents &&image_extents,
+ io::ReadResult &&read_result, IOContext io_context, int op_flags,
+ int read_flags, const ZTracer::Trace &parent_trace, uint64_t tid,
+ std::atomic<uint32_t>* image_dispatch_flags,
+ io::DispatchResult* dispatch_result, Context** on_finish,
+ Context* on_dispatched) {
+ auto cct = m_image_ctx->cct;
+ ldout(cct, 20) << dendl;
+
+ *dispatch_result = io::DISPATCH_RESULT_COMPLETE;
+ m_format->read(aio_comp, io_context->read_snap().value_or(CEPH_NOSNAP),
+ std::move(image_extents), std::move(read_result), op_flags,
+ read_flags, parent_trace);
+ return true;
+}
+
+template <typename I>
+bool ImageDispatch<I>::write(
+ io::AioCompletion* aio_comp, io::Extents &&image_extents, bufferlist &&bl,
+ IOContext io_context, int op_flags, const ZTracer::Trace &parent_trace,
+ uint64_t tid, std::atomic<uint32_t>* image_dispatch_flags,
+ io::DispatchResult* dispatch_result, Context** on_finish,
+ Context* on_dispatched) {
+ auto cct = m_image_ctx->cct;
+ lderr(cct) << dendl;
+
+ fail_io(-EROFS, aio_comp, dispatch_result);
+ return true;
+}
+
+template <typename I>
+bool ImageDispatch<I>::discard(
+ io::AioCompletion* aio_comp, io::Extents &&image_extents,
+ uint32_t discard_granularity_bytes,
+ IOContext io_context, const ZTracer::Trace &parent_trace, uint64_t tid,
+ std::atomic<uint32_t>* image_dispatch_flags,
+ io::DispatchResult* dispatch_result, Context** on_finish,
+ Context* on_dispatched) {
+ auto cct = m_image_ctx->cct;
+ lderr(cct) << dendl;
+
+ fail_io(-EROFS, aio_comp, dispatch_result);
+ return true;
+}
+
+template <typename I>
+bool ImageDispatch<I>::write_same(
+ io::AioCompletion* aio_comp, io::Extents &&image_extents, bufferlist &&bl,
+ IOContext io_context, int op_flags, const ZTracer::Trace &parent_trace,
+ uint64_t tid, std::atomic<uint32_t>* image_dispatch_flags,
+ io::DispatchResult* dispatch_result, Context** on_finish,
+ Context* on_dispatched) {
+ auto cct = m_image_ctx->cct;
+ lderr(cct) << dendl;
+
+ fail_io(-EROFS, aio_comp, dispatch_result);
+ return true;
+}
+
+template <typename I>
+bool ImageDispatch<I>::compare_and_write(
+ io::AioCompletion* aio_comp, io::Extents &&image_extents,
+ bufferlist &&cmp_bl, bufferlist &&bl, uint64_t *mismatch_offset,
+ IOContext io_context, int op_flags, const ZTracer::Trace &parent_trace,
+ uint64_t tid, std::atomic<uint32_t>* image_dispatch_flags,
+ io::DispatchResult* dispatch_result, Context** on_finish,
+ Context* on_dispatched) {
+ auto cct = m_image_ctx->cct;
+ lderr(cct) << dendl;
+
+ fail_io(-EROFS, aio_comp, dispatch_result);
+ return true;
+}
+
+template <typename I>
+bool ImageDispatch<I>::flush(
+ io::AioCompletion* aio_comp, io::FlushSource flush_source,
+ const ZTracer::Trace &parent_trace, uint64_t tid,
+ std::atomic<uint32_t>* image_dispatch_flags,
+ io::DispatchResult* dispatch_result, Context** on_finish,
+ Context* on_dispatched) {
+ auto cct = m_image_ctx->cct;
+ ldout(cct, 20) << dendl;
+
+ *dispatch_result = io::DISPATCH_RESULT_COMPLETE;
+ aio_comp->set_request_count(0);
+ return true;
+}
+
+template <typename I>
+bool ImageDispatch<I>::list_snaps(
+ io::AioCompletion* aio_comp, io::Extents&& image_extents,
+ io::SnapIds&& snap_ids, int list_snaps_flags,
+ io::SnapshotDelta* snapshot_delta, const ZTracer::Trace &parent_trace,
+ uint64_t tid, std::atomic<uint32_t>* image_dispatch_flags,
+ io::DispatchResult* dispatch_result, Context** on_finish,
+ Context* on_dispatched) {
+ auto cct = m_image_ctx->cct;
+ ldout(cct, 20) << dendl;
+
+ *dispatch_result = io::DISPATCH_RESULT_COMPLETE;
+
+ aio_comp->set_request_count(1);
+ auto ctx = new io::C_AioRequest(aio_comp);
+
+ m_format->list_snaps(std::move(image_extents), std::move(snap_ids),
+ list_snaps_flags, snapshot_delta, parent_trace,
+ ctx);
+ return true;
+}
+
+template <typename I>
+void ImageDispatch<I>::fail_io(int r, io::AioCompletion* aio_comp,
+ io::DispatchResult* dispatch_result) {
+ *dispatch_result = io::DISPATCH_RESULT_COMPLETE;
+ aio_comp->fail(r);
+}
+
+} // namespace migration
+} // namespace librbd
+
+template class librbd::migration::ImageDispatch<librbd::ImageCtx>;
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_LIBRBD_MIGRATION_IMAGE_DISPATCH_H
+#define CEPH_LIBRBD_MIGRATION_IMAGE_DISPATCH_H
+
+#include "librbd/io/ImageDispatchInterface.h"
+#include <memory>
+
+struct Context;
+
+namespace librbd {
+
+struct ImageCtx;
+
+namespace migration {
+
+struct FormatInterface;
+
+template <typename ImageCtxT>
+class ImageDispatch : public io::ImageDispatchInterface {
+public:
+ static ImageDispatch* create(ImageCtxT* image_ctx,
+ std::unique_ptr<FormatInterface> source) {
+ return new ImageDispatch(image_ctx, std::move(source));
+ }
+
+ ImageDispatch(ImageCtxT* image_ctx, std::unique_ptr<FormatInterface> source);
+
+ void shut_down(Context* on_finish) override;
+
+ io::ImageDispatchLayer get_dispatch_layer() const override {
+ return io::IMAGE_DISPATCH_LAYER_MIGRATION;
+ }
+
+ bool read(
+ io::AioCompletion* aio_comp, io::Extents &&image_extents,
+ io::ReadResult &&read_result, IOContext io_context, int op_flags,
+ int read_flags, const ZTracer::Trace &parent_trace, uint64_t tid,
+ std::atomic<uint32_t>* image_dispatch_flags,
+ io::DispatchResult* dispatch_result, Context** on_finish,
+ Context* on_dispatched) override;
+ bool write(
+ io::AioCompletion* aio_comp, io::Extents &&image_extents, bufferlist &&bl,
+ IOContext io_context, int op_flags, const ZTracer::Trace &parent_trace,
+ uint64_t tid, std::atomic<uint32_t>* image_dispatch_flags,
+ io::DispatchResult* dispatch_result, Context** on_finish,
+ Context* on_dispatched) override;
+ bool discard(
+ io::AioCompletion* aio_comp, io::Extents &&image_extents,
+ uint32_t discard_granularity_bytes,
+ IOContext io_context, const ZTracer::Trace &parent_trace, uint64_t tid,
+ std::atomic<uint32_t>* image_dispatch_flags,
+ io::DispatchResult* dispatch_result, Context** on_finish,
+ Context* on_dispatched) override;
+ bool write_same(
+ io::AioCompletion* aio_comp, io::Extents &&image_extents, bufferlist &&bl,
+ IOContext io_context, int op_flags, const ZTracer::Trace &parent_trace,
+ uint64_t tid, std::atomic<uint32_t>* image_dispatch_flags,
+ io::DispatchResult* dispatch_result, Context** on_finish,
+ Context* on_dispatched) override;
+ bool compare_and_write(
+ io::AioCompletion* aio_comp, io::Extents &&image_extents,
+ bufferlist &&cmp_bl, bufferlist &&bl, uint64_t *mismatch_offset,
+ IOContext io_context, int op_flags, const ZTracer::Trace &parent_trace,
+ uint64_t tid, std::atomic<uint32_t>* image_dispatch_flags,
+ io::DispatchResult* dispatch_result, Context** on_finish,
+ Context* on_dispatched) override;
+ bool flush(
+ io::AioCompletion* aio_comp, io::FlushSource flush_source,
+ const ZTracer::Trace &parent_trace, uint64_t tid,
+ std::atomic<uint32_t>* image_dispatch_flags,
+ io::DispatchResult* dispatch_result, Context** on_finish,
+ Context* on_dispatched) override;
+
+ bool list_snaps(
+ io::AioCompletion* aio_comp, io::Extents&& image_extents,
+ io::SnapIds&& snap_ids, int list_snaps_flags,
+ io::SnapshotDelta* snapshot_delta, const ZTracer::Trace &parent_trace,
+ uint64_t tid, std::atomic<uint32_t>* image_dispatch_flags,
+ io::DispatchResult* dispatch_result, Context** on_finish,
+ Context* on_dispatched) override;
+
+private:
+ ImageCtxT* m_image_ctx;
+ std::unique_ptr<FormatInterface> m_format;
+
+ void fail_io(int r, io::AioCompletion* aio_comp,
+ io::DispatchResult* dispatch_result);
+
+};
+
+} // namespace migration
+} // namespace librbd
+
+extern template class librbd::migration::ImageDispatch<librbd::ImageCtx>;
+
+#endif // CEPH_LIBRBD_MIGRATION_IMAGE_DISPATCH_H
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "librbd/migration/NativeFormat.h"
+#include "include/neorados/RADOS.hpp"
+#include "common/dout.h"
+#include "librbd/ImageCtx.h"
+#include "librbd/ImageState.h"
+#include "librbd/Utils.h"
+#include "librbd/asio/ContextWQ.h"
+#include "librbd/io/ImageDispatchSpec.h"
+
+#define dout_subsys ceph_subsys_rbd
+#undef dout_prefix
+#define dout_prefix *_dout << "librbd::migration::NativeFormat: " << this \
+ << " " << __func__ << ": "
+
+namespace librbd {
+namespace migration {
+
+template <typename I>
+NativeFormat<I>::NativeFormat(
+ I* image_ctx, const MigrationInfo& migration_info)
+ : m_image_ctx(image_ctx), m_migration_info(migration_info) {
+}
+
+template <typename I>
+void NativeFormat<I>::open(Context* on_finish) {
+ auto cct = m_image_ctx->cct;
+ ldout(cct, 10) << dendl;
+
+ // TODO add support for external clusters
+ librados::IoCtx io_ctx;
+ int r = util::create_ioctx(m_image_ctx->md_ctx, "source image",
+ m_migration_info.pool_id,
+ m_migration_info.pool_namespace, &io_ctx);
+ if (r < 0) {
+ on_finish->complete(r);
+ return;
+ }
+
+ m_image_ctx->md_ctx.dup(io_ctx);
+ m_image_ctx->data_ctx.dup(io_ctx);
+
+ uint64_t flags = 0;
+ if (m_migration_info.image_id.empty()) {
+ m_image_ctx->name = m_migration_info.image_name;
+ flags |= OPEN_FLAG_OLD_FORMAT;
+ } else {
+ m_image_ctx->id = m_migration_info.image_id;
+ }
+
+ // set rados flags for reading the parent image
+ if (m_image_ctx->child->config.template get_val<bool>("rbd_balance_parent_reads")) {
+ m_image_ctx->set_read_flag(librados::OPERATION_BALANCE_READS);
+ } else if (m_image_ctx->child->config.template get_val<bool>("rbd_localize_parent_reads")) {
+ m_image_ctx->set_read_flag(librados::OPERATION_LOCALIZE_READS);
+ }
+
+ // open the source RBD image
+ auto ctx = util::create_async_context_callback(*m_image_ctx, on_finish);
+ m_image_ctx->state->open(flags, ctx);
+}
+
+template <typename I>
+void NativeFormat<I>::close(Context* on_finish) {
+ auto cct = m_image_ctx->cct;
+ ldout(cct, 10) << dendl;
+
+ // the native librbd::image::CloseRequest handles all cleanup
+ on_finish->complete(0);
+}
+
+template <typename I>
+void NativeFormat<I>::get_snapshots(SnapInfos* snap_infos, Context* on_finish) {
+ auto cct = m_image_ctx->cct;
+ ldout(cct, 10) << dendl;
+
+ m_image_ctx->image_lock.lock_shared();
+ *snap_infos = m_image_ctx->snap_info;
+ m_image_ctx->image_lock.unlock_shared();
+
+ on_finish->complete(0);
+}
+
+template <typename I>
+void NativeFormat<I>::get_image_size(uint64_t snap_id, uint64_t* size,
+ Context* on_finish) {
+ auto cct = m_image_ctx->cct;
+ ldout(cct, 10) << dendl;
+
+ m_image_ctx->image_lock.lock_shared();
+ *size = m_image_ctx->get_image_size(snap_id);
+ m_image_ctx->image_lock.unlock_shared();
+
+
+ on_finish->complete(0);
+}
+
+template <typename I>
+void NativeFormat<I>::read(
+ io::AioCompletion* aio_comp, uint64_t snap_id, io::Extents&& image_extents,
+ io::ReadResult&& read_result, int op_flags, int read_flags,
+ const ZTracer::Trace &parent_trace) {
+ auto cct = m_image_ctx->cct;
+ ldout(cct, 20) << "snap_id=" << snap_id << ", "
+ << "image_extents=" << image_extents << dendl;
+
+ auto io_context = m_image_ctx->duplicate_data_io_context();
+ if (snap_id != CEPH_NOSNAP) {
+ io_context->read_snap(snap_id);
+ }
+
+ auto req = io::ImageDispatchSpec::create_read(
+ *m_image_ctx, io::IMAGE_DISPATCH_LAYER_MIGRATION, aio_comp,
+ std::move(image_extents), std::move(read_result), io_context, op_flags,
+ read_flags, {});
+ req->send();
+}
+
+template <typename I>
+void NativeFormat<I>::list_snaps(io::Extents&& image_extents,
+ io::SnapIds&& snap_ids, int list_snaps_flags,
+ io::SnapshotDelta* snapshot_delta,
+ const ZTracer::Trace &parent_trace,
+ Context* on_finish) {
+ auto cct = m_image_ctx->cct;
+ ldout(cct, 20) << "image_extents=" << image_extents << dendl;
+
+ auto aio_comp = io::AioCompletion::create_and_start(
+ on_finish, util::get_image_ctx(m_image_ctx), io::AIO_TYPE_GENERIC);
+ auto req = io::ImageDispatchSpec::create_list_snaps(
+ *m_image_ctx, io::IMAGE_DISPATCH_LAYER_MIGRATION, aio_comp,
+ std::move(image_extents), std::move(snap_ids), list_snaps_flags,
+ snapshot_delta, {});
+ req->send();
+}
+
+} // namespace migration
+} // namespace librbd
+
+template class librbd::migration::NativeFormat<librbd::ImageCtx>;
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_LIBRBD_MIGRATION_NATIVE_FORMAT_H
+#define CEPH_LIBRBD_MIGRATION_NATIVE_FORMAT_H
+
+#include "include/int_types.h"
+#include "librbd/Types.h"
+#include "librbd/migration/FormatInterface.h"
+#include <memory>
+
+struct Context;
+
+namespace librbd {
+
+struct AsioEngine;
+struct ImageCtx;
+
+namespace migration {
+
+template <typename ImageCtxT>
+class NativeFormat : public FormatInterface {
+public:
+ static NativeFormat* create(ImageCtxT* image_ctx,
+ const MigrationInfo& migration_info) {
+ return new NativeFormat(image_ctx, migration_info);
+ }
+
+ NativeFormat(ImageCtxT* image_ctx, const MigrationInfo& migration_info);
+ NativeFormat(const NativeFormat&) = delete;
+ NativeFormat& operator=(const NativeFormat&) = delete;
+
+ void open(Context* on_finish) override;
+ void close(Context* on_finish) override;
+
+ void get_snapshots(SnapInfos* snap_infos, Context* on_finish) override;
+ void get_image_size(uint64_t snap_id, uint64_t* size,
+ Context* on_finish) override;
+
+ void read(io::AioCompletion* aio_comp, uint64_t snap_id,
+ io::Extents&& image_extents, io::ReadResult&& read_result,
+ int op_flags, int read_flags,
+ const ZTracer::Trace &parent_trace) override;
+
+ void list_snaps(io::Extents&& image_extents, io::SnapIds&& snap_ids,
+ int list_snaps_flags, io::SnapshotDelta* snapshot_delta,
+ const ZTracer::Trace &parent_trace,
+ Context* on_finish) override;
+
+private:
+ ImageCtxT* m_image_ctx;
+ MigrationInfo m_migration_info;
+
+};
+
+} // namespace migration
+} // namespace librbd
+
+extern template class librbd::migration::NativeFormat<librbd::ImageCtx>;
+
+#endif // CEPH_LIBRBD_MIGRATION_NATIVE_FORMAT_H
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "librbd/migration/OpenSourceImageRequest.h"
+#include "common/dout.h"
+#include "common/errno.h"
+#include "librbd/ImageCtx.h"
+#include "librbd/Utils.h"
+#include "librbd/io/ImageDispatcher.h"
+#include "librbd/migration/ImageDispatch.h"
+#include "librbd/migration/NativeFormat.h"
+
+#define dout_subsys ceph_subsys_rbd
+#undef dout_prefix
+#define dout_prefix *_dout << "librbd::migration::OpenSourceImageRequest: " \
+ << this << " " << __func__ << ": "
+
+namespace librbd {
+namespace migration {
+
+template <typename I>
+OpenSourceImageRequest<I>::OpenSourceImageRequest(
+ I* dst_image_ctx, uint64_t src_snap_id,
+ const MigrationInfo &migration_info, I** src_image_ctx, Context* on_finish)
+ : m_dst_image_ctx(dst_image_ctx), m_src_snap_id(src_snap_id),
+ m_migration_info(migration_info), m_src_image_ctx(src_image_ctx),
+ m_on_finish(on_finish) {
+ auto cct = m_dst_image_ctx->cct;
+ ldout(cct, 10) << dendl;
+}
+
+template <typename I>
+void OpenSourceImageRequest<I>::send() {
+ open_source();
+}
+
+template <typename I>
+void OpenSourceImageRequest<I>::open_source() {
+ auto cct = m_dst_image_ctx->cct;
+ ldout(cct, 10) << dendl;
+
+ // note that all source image ctx properties are placeholders
+ *m_src_image_ctx = I::create("", "", m_src_snap_id,
+ m_dst_image_ctx->md_ctx, true);
+ (*m_src_image_ctx)->child = m_dst_image_ctx;
+
+ // TODO use factory once multiple sources are available
+ m_format = std::unique_ptr<FormatInterface>(NativeFormat<I>::create(
+ *m_src_image_ctx, m_migration_info));
+
+ auto ctx = util::create_context_callback<
+ OpenSourceImageRequest<I>,
+ &OpenSourceImageRequest<I>::handle_open_source>(this);
+ m_format->open(ctx);
+}
+
+template <typename I>
+void OpenSourceImageRequest<I>::handle_open_source(int r) {
+ auto cct = m_dst_image_ctx->cct;
+ ldout(cct, 10) << "r=" << r << dendl;
+
+ if (r < 0) {
+ lderr(cct) << "failed to open migration source: " << cpp_strerror(r)
+ << dendl;
+ finish(r);
+ return;
+ }
+
+ // intercept any IO requests to the source image
+ auto io_image_dispatch = ImageDispatch<I>::create(
+ *m_src_image_ctx, std::move(m_format));
+ (*m_src_image_ctx)->io_image_dispatcher->register_dispatch(io_image_dispatch);
+
+ finish(0);
+}
+
+template <typename I>
+void OpenSourceImageRequest<I>::finish(int r) {
+ auto cct = m_dst_image_ctx->cct;
+ ldout(cct, 10) << "r=" << r << dendl;
+
+ if (r < 0) {
+ delete *m_src_image_ctx;
+ *m_src_image_ctx = nullptr;
+ }
+ m_on_finish->complete(r);
+ delete this;
+}
+
+} // namespace migration
+} // namespace librbd
+
+template class librbd::migration::OpenSourceImageRequest<librbd::ImageCtx>;
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_LIBRBD_MIGRATION_OPEN_SOURCE_IMAGE_REQUEST_H
+#define CEPH_LIBRBD_MIGRATION_OPEN_SOURCE_IMAGE_REQUEST_H
+
+#include "librbd/Types.h"
+#include <memory>
+
+struct Context;
+
+namespace librbd {
+
+struct ImageCtx;
+
+namespace migration {
+
+struct FormatInterface;
+
+template <typename ImageCtxT>
+class OpenSourceImageRequest {
+public:
+ static OpenSourceImageRequest* create(ImageCtxT* destination_image_ctx,
+ uint64_t src_snap_id,
+ const MigrationInfo &migration_info,
+ ImageCtxT** source_image_ctx,
+ Context* on_finish) {
+ return new OpenSourceImageRequest(destination_image_ctx, src_snap_id,
+ migration_info, source_image_ctx,
+ on_finish);
+ }
+
+ OpenSourceImageRequest(ImageCtxT* destination_image_ctx,
+ uint64_t src_snap_id,
+ const MigrationInfo &migration_info,
+ ImageCtxT** source_image_ctx,
+ Context* on_finish);
+
+ void send();
+
+private:
+ /**
+ * @verbatim
+ *
+ * <start>
+ * |
+ * v
+ * OPEN_SOURCE
+ * |
+ * v
+ * <finish>
+ *
+ * @endverbatim
+ */
+
+ ImageCtxT* m_dst_image_ctx;
+ uint64_t m_src_snap_id;
+ MigrationInfo m_migration_info;
+ ImageCtxT** m_src_image_ctx;
+ Context* m_on_finish;
+
+ std::unique_ptr<FormatInterface> m_format;
+
+ void open_source();
+ void handle_open_source(int r);
+
+ void finish(int r);
+
+};
+
+} // namespace migration
+} // namespace librbd
+
+extern template class librbd::migration::OpenSourceImageRequest<librbd::ImageCtx>;
+
+#endif // CEPH_LIBRBD_MIGRATION_OPEN_SOURCE_IMAGE_REQUEST_H