]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: new migration IO image dispatch layer
authorJason Dillaman <dillaman@redhat.com>
Wed, 14 Oct 2020 20:03:47 +0000 (16:03 -0400)
committerJason Dillaman <dillaman@redhat.com>
Thu, 22 Oct 2020 13:40:39 +0000 (09:40 -0400)
The initial hooks merely abstract the standard RBD parent/child
clone relationship. The basic interface, however, is abstract
enough to allow third party data formats and streams to be eventually
integrated with RBD live-migration.

Signed-off-by: Jason Dillaman <dillaman@redhat.com>
src/librbd/CMakeLists.txt
src/librbd/io/Types.h
src/librbd/migration/FormatInterface.h [new file with mode: 0644]
src/librbd/migration/ImageDispatch.cc [new file with mode: 0644]
src/librbd/migration/ImageDispatch.h [new file with mode: 0644]
src/librbd/migration/NativeFormat.cc [new file with mode: 0644]
src/librbd/migration/NativeFormat.h [new file with mode: 0644]
src/librbd/migration/OpenSourceImageRequest.cc [new file with mode: 0644]
src/librbd/migration/OpenSourceImageRequest.h [new file with mode: 0644]

index 291b95d39ad6ff7f12d47c2ce2b7e527d8d98638..677b240a5fa18bec74f4717f56a5633a390e4655 100644 (file)
@@ -116,6 +116,9 @@ set(librbd_internal_srcs
   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
index a41d1e9f23749c1cf54d4e97d7ba0cf8ae9536ff..b0428a0ba753108b93fef1a3d67350968791fad3 100644 (file)
@@ -62,6 +62,7 @@ enum ImageDispatchLayer {
   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,
diff --git a/src/librbd/migration/FormatInterface.h b/src/librbd/migration/FormatInterface.h
new file mode 100644 (file)
index 0000000..27669dd
--- /dev/null
@@ -0,0 +1,53 @@
+// -*- 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
diff --git a/src/librbd/migration/ImageDispatch.cc b/src/librbd/migration/ImageDispatch.cc
new file mode 100644 (file)
index 0000000..bde0a69
--- /dev/null
@@ -0,0 +1,158 @@
+// -*- 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>;
diff --git a/src/librbd/migration/ImageDispatch.h b/src/librbd/migration/ImageDispatch.h
new file mode 100644 (file)
index 0000000..490ea2d
--- /dev/null
@@ -0,0 +1,98 @@
+// -*- 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
diff --git a/src/librbd/migration/NativeFormat.cc b/src/librbd/migration/NativeFormat.cc
new file mode 100644 (file)
index 0000000..bf6a78f
--- /dev/null
@@ -0,0 +1,142 @@
+// -*- 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>;
diff --git a/src/librbd/migration/NativeFormat.h b/src/librbd/migration/NativeFormat.h
new file mode 100644 (file)
index 0000000..0f0d43a
--- /dev/null
@@ -0,0 +1,61 @@
+// -*- 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
diff --git a/src/librbd/migration/OpenSourceImageRequest.cc b/src/librbd/migration/OpenSourceImageRequest.cc
new file mode 100644 (file)
index 0000000..0fc80d4
--- /dev/null
@@ -0,0 +1,93 @@
+// -*- 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>;
diff --git a/src/librbd/migration/OpenSourceImageRequest.h b/src/librbd/migration/OpenSourceImageRequest.h
new file mode 100644 (file)
index 0000000..1ad2476
--- /dev/null
@@ -0,0 +1,76 @@
+// -*- 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