summaryrefslogtreecommitdiffstats
path: root/src/librbd/DeepCopyRequest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/librbd/DeepCopyRequest.cc')
-rw-r--r--src/librbd/DeepCopyRequest.cc361
1 files changed, 361 insertions, 0 deletions
diff --git a/src/librbd/DeepCopyRequest.cc b/src/librbd/DeepCopyRequest.cc
new file mode 100644
index 000000000..af26ef0c9
--- /dev/null
+++ b/src/librbd/DeepCopyRequest.cc
@@ -0,0 +1,361 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "DeepCopyRequest.h"
+#include "common/errno.h"
+#include "librbd/ExclusiveLock.h"
+#include "librbd/ImageCtx.h"
+#include "librbd/ObjectMap.h"
+#include "librbd/Utils.h"
+#include "librbd/deep_copy/ImageCopyRequest.h"
+#include "librbd/deep_copy/MetadataCopyRequest.h"
+#include "librbd/deep_copy/SnapshotCopyRequest.h"
+#include "librbd/internal.h"
+
+#define dout_subsys ceph_subsys_rbd
+#undef dout_prefix
+#define dout_prefix *_dout << "librbd::DeepCopyRequest: " \
+ << this << " " << __func__ << ": "
+
+namespace librbd {
+
+using namespace librbd::deep_copy;
+
+using librbd::util::create_context_callback;
+using librbd::util::create_rados_callback;
+using librbd::util::unique_lock_name;
+
+template <typename I>
+DeepCopyRequest<I>::DeepCopyRequest(I *src_image_ctx, I *dst_image_ctx,
+ librados::snap_t src_snap_id_start,
+ librados::snap_t src_snap_id_end,
+ librados::snap_t dst_snap_id_start,
+ bool flatten,
+ const ObjectNumber &object_number,
+ asio::ContextWQ *work_queue,
+ SnapSeqs *snap_seqs,
+ deep_copy::Handler *handler,
+ Context *on_finish)
+ : RefCountedObject(dst_image_ctx->cct), m_src_image_ctx(src_image_ctx),
+ m_dst_image_ctx(dst_image_ctx), m_src_snap_id_start(src_snap_id_start),
+ m_src_snap_id_end(src_snap_id_end), m_dst_snap_id_start(dst_snap_id_start),
+ m_flatten(flatten), m_object_number(object_number),
+ m_work_queue(work_queue), m_snap_seqs(snap_seqs), m_handler(handler),
+ m_on_finish(on_finish), m_cct(dst_image_ctx->cct),
+ m_lock(ceph::make_mutex(unique_lock_name("DeepCopyRequest::m_lock", this))) {
+}
+
+template <typename I>
+DeepCopyRequest<I>::~DeepCopyRequest() {
+ ceph_assert(m_snapshot_copy_request == nullptr);
+ ceph_assert(m_image_copy_request == nullptr);
+}
+
+template <typename I>
+void DeepCopyRequest<I>::send() {
+ if (!m_src_image_ctx->data_ctx.is_valid()) {
+ lderr(m_cct) << "missing data pool for source image" << dendl;
+ finish(-ENODEV);
+ return;
+ }
+
+ if (!m_dst_image_ctx->data_ctx.is_valid()) {
+ lderr(m_cct) << "missing data pool for destination image" << dendl;
+ finish(-ENODEV);
+ return;
+ }
+
+ int r = validate_copy_points();
+ if (r < 0) {
+ finish(r);
+ return;
+ }
+
+ send_copy_snapshots();
+}
+
+template <typename I>
+void DeepCopyRequest<I>::cancel() {
+ std::lock_guard locker{m_lock};
+
+ ldout(m_cct, 20) << dendl;
+
+ m_canceled = true;
+
+ if (m_snapshot_copy_request != nullptr) {
+ m_snapshot_copy_request->cancel();
+ }
+
+ if (m_image_copy_request != nullptr) {
+ m_image_copy_request->cancel();
+ }
+}
+
+template <typename I>
+void DeepCopyRequest<I>::send_copy_snapshots() {
+ m_lock.lock();
+ if (m_canceled) {
+ m_lock.unlock();
+ finish(-ECANCELED);
+ return;
+ }
+
+ ldout(m_cct, 20) << dendl;
+
+ Context *ctx = create_context_callback<
+ DeepCopyRequest<I>, &DeepCopyRequest<I>::handle_copy_snapshots>(this);
+ m_snapshot_copy_request = SnapshotCopyRequest<I>::create(
+ m_src_image_ctx, m_dst_image_ctx, m_src_snap_id_start, m_src_snap_id_end,
+ m_dst_snap_id_start, m_flatten, m_work_queue, m_snap_seqs, ctx);
+ m_snapshot_copy_request->get();
+ m_lock.unlock();
+
+ m_snapshot_copy_request->send();
+}
+
+template <typename I>
+void DeepCopyRequest<I>::handle_copy_snapshots(int r) {
+ ldout(m_cct, 20) << "r=" << r << dendl;
+
+ {
+ std::lock_guard locker{m_lock};
+ m_snapshot_copy_request->put();
+ m_snapshot_copy_request = nullptr;
+ if (r == 0 && m_canceled) {
+ r = -ECANCELED;
+ }
+ }
+
+ if (r == -ECANCELED) {
+ ldout(m_cct, 10) << "snapshot copy canceled" << dendl;
+ finish(r);
+ return;
+ } else if (r < 0) {
+ lderr(m_cct) << "failed to copy snapshot metadata: " << cpp_strerror(r)
+ << dendl;
+ finish(r);
+ return;
+ }
+
+ if (m_src_snap_id_end == CEPH_NOSNAP) {
+ (*m_snap_seqs)[CEPH_NOSNAP] = CEPH_NOSNAP;
+ }
+
+ send_copy_image();
+}
+
+template <typename I>
+void DeepCopyRequest<I>::send_copy_image() {
+ m_lock.lock();
+ if (m_canceled) {
+ m_lock.unlock();
+ finish(-ECANCELED);
+ return;
+ }
+
+ ldout(m_cct, 20) << dendl;
+
+ Context *ctx = create_context_callback<
+ DeepCopyRequest<I>, &DeepCopyRequest<I>::handle_copy_image>(this);
+ m_image_copy_request = ImageCopyRequest<I>::create(
+ m_src_image_ctx, m_dst_image_ctx, m_src_snap_id_start, m_src_snap_id_end,
+ m_dst_snap_id_start, m_flatten, m_object_number, *m_snap_seqs, m_handler,
+ ctx);
+ m_image_copy_request->get();
+ m_lock.unlock();
+
+ m_image_copy_request->send();
+}
+
+template <typename I>
+void DeepCopyRequest<I>::handle_copy_image(int r) {
+ ldout(m_cct, 20) << "r=" << r << dendl;
+
+ {
+ std::lock_guard locker{m_lock};
+ m_image_copy_request->put();
+ m_image_copy_request = nullptr;
+ if (r == 0 && m_canceled) {
+ r = -ECANCELED;
+ }
+ }
+
+ if (r == -ECANCELED) {
+ ldout(m_cct, 10) << "image copy canceled" << dendl;
+ finish(r);
+ return;
+ } else if (r < 0) {
+ lderr(m_cct) << "failed to copy image: " << cpp_strerror(r) << dendl;
+ finish(r);
+ return;
+ }
+
+ send_copy_object_map();
+}
+
+template <typename I>
+void DeepCopyRequest<I>::send_copy_object_map() {
+ m_dst_image_ctx->owner_lock.lock_shared();
+ m_dst_image_ctx->image_lock.lock_shared();
+
+ if (!m_dst_image_ctx->test_features(RBD_FEATURE_OBJECT_MAP,
+ m_dst_image_ctx->image_lock)) {
+ m_dst_image_ctx->image_lock.unlock_shared();
+ m_dst_image_ctx->owner_lock.unlock_shared();
+ send_copy_metadata();
+ return;
+ }
+ if (m_src_snap_id_end == CEPH_NOSNAP) {
+ m_dst_image_ctx->image_lock.unlock_shared();
+ m_dst_image_ctx->owner_lock.unlock_shared();
+ send_refresh_object_map();
+ return;
+ }
+
+ ceph_assert(m_dst_image_ctx->object_map != nullptr);
+
+ ldout(m_cct, 20) << dendl;
+
+ Context *finish_op_ctx = nullptr;
+ int r;
+ if (m_dst_image_ctx->exclusive_lock != nullptr) {
+ finish_op_ctx = m_dst_image_ctx->exclusive_lock->start_op(&r);
+ }
+ if (finish_op_ctx == nullptr) {
+ lderr(m_cct) << "lost exclusive lock" << dendl;
+ m_dst_image_ctx->image_lock.unlock_shared();
+ m_dst_image_ctx->owner_lock.unlock_shared();
+ finish(r);
+ return;
+ }
+
+ // rollback the object map (copy snapshot object map to HEAD)
+ auto ctx = new LambdaContext([this, finish_op_ctx](int r) {
+ handle_copy_object_map(r);
+ finish_op_ctx->complete(0);
+ });
+ ceph_assert(m_snap_seqs->count(m_src_snap_id_end) > 0);
+ librados::snap_t copy_snap_id = (*m_snap_seqs)[m_src_snap_id_end];
+ m_dst_image_ctx->object_map->rollback(copy_snap_id, ctx);
+ m_dst_image_ctx->image_lock.unlock_shared();
+ m_dst_image_ctx->owner_lock.unlock_shared();
+}
+
+template <typename I>
+void DeepCopyRequest<I>::handle_copy_object_map(int r) {
+ ldout(m_cct, 20) << dendl;
+
+ if (r < 0) {
+ lderr(m_cct) << "failed to roll back object map: " << cpp_strerror(r)
+ << dendl;
+ finish(r);
+ return;
+ }
+
+ send_refresh_object_map();
+}
+
+template <typename I>
+void DeepCopyRequest<I>::send_refresh_object_map() {
+ int r;
+ Context *finish_op_ctx = nullptr;
+ {
+ std::shared_lock owner_locker{m_dst_image_ctx->owner_lock};
+ if (m_dst_image_ctx->exclusive_lock != nullptr) {
+ finish_op_ctx = m_dst_image_ctx->exclusive_lock->start_op(&r);
+ }
+ }
+ if (finish_op_ctx == nullptr) {
+ lderr(m_cct) << "lost exclusive lock" << dendl;
+ finish(r);
+ return;
+ }
+
+ ldout(m_cct, 20) << dendl;
+
+ auto ctx = new LambdaContext([this, finish_op_ctx](int r) {
+ handle_refresh_object_map(r);
+ finish_op_ctx->complete(0);
+ });
+ m_object_map = m_dst_image_ctx->create_object_map(CEPH_NOSNAP);
+ m_object_map->open(ctx);
+}
+
+template <typename I>
+void DeepCopyRequest<I>::handle_refresh_object_map(int r) {
+ ldout(m_cct, 20) << "r=" << r << dendl;
+
+ if (r < 0) {
+ lderr(m_cct) << "failed to open object map: " << cpp_strerror(r)
+ << dendl;
+ delete m_object_map;
+
+ finish(r);
+ return;
+ }
+
+ {
+ std::unique_lock image_locker{m_dst_image_ctx->image_lock};
+ std::swap(m_dst_image_ctx->object_map, m_object_map);
+ }
+ m_object_map->put();
+
+ send_copy_metadata();
+}
+
+template <typename I>
+void DeepCopyRequest<I>::send_copy_metadata() {
+ ldout(m_cct, 20) << dendl;
+
+ Context *ctx = create_context_callback<
+ DeepCopyRequest<I>, &DeepCopyRequest<I>::handle_copy_metadata>(this);
+ auto request = MetadataCopyRequest<I>::create(m_src_image_ctx,
+ m_dst_image_ctx, ctx);
+ request->send();
+}
+
+template <typename I>
+void DeepCopyRequest<I>::handle_copy_metadata(int r) {
+ ldout(m_cct, 20) << "r=" << r << dendl;
+
+ if (r < 0) {
+ lderr(m_cct) << "failed to copy metadata: " << cpp_strerror(r) << dendl;
+ finish(r);
+ return;
+ }
+
+ finish(0);
+}
+
+template <typename I>
+int DeepCopyRequest<I>::validate_copy_points() {
+ std::shared_lock image_locker{m_src_image_ctx->image_lock};
+
+ if (m_src_snap_id_start != 0 &&
+ m_src_image_ctx->snap_info.find(m_src_snap_id_start) ==
+ m_src_image_ctx->snap_info.end()) {
+ lderr(m_cct) << "invalid start snap_id " << m_src_snap_id_start << dendl;
+ return -EINVAL;
+ }
+
+ if (m_src_snap_id_end != CEPH_NOSNAP &&
+ m_src_image_ctx->snap_info.find(m_src_snap_id_end) ==
+ m_src_image_ctx->snap_info.end()) {
+ lderr(m_cct) << "invalid end snap_id " << m_src_snap_id_end << dendl;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+template <typename I>
+void DeepCopyRequest<I>::finish(int r) {
+ ldout(m_cct, 20) << "r=" << r << dendl;
+
+ m_on_finish->complete(r);
+ put();
+}
+
+} // namespace librbd
+
+template class librbd::DeepCopyRequest<librbd::ImageCtx>;