From 1fac1f72c2d2000175f854f9bb14ec95ccb68b08 Mon Sep 17 00:00:00 2001 From: Jason Dillaman Date: Wed, 5 Feb 2020 14:23:53 -0500 Subject: [PATCH] librbd: deep-copy snapshots from a specified start/end position Allow the snapshots to be arbitrarily copied from any source image start/end snapshot ids. If the end snapshot is not a user-snapshot, it will associate to the destination image HEAD revision. Signed-off-by: Jason Dillaman --- src/librbd/DeepCopyRequest.cc | 4 +- src/librbd/api/Migration.cc | 2 +- src/librbd/deep_copy/SnapshotCopyRequest.cc | 79 ++++++++-- src/librbd/deep_copy/SnapshotCopyRequest.h | 24 ++- .../test_mock_SnapshotCopyRequest.cc | 146 ++++++++++++++---- src/test/librbd/test_mock_DeepCopyRequest.cc | 8 +- 6 files changed, 204 insertions(+), 59 deletions(-) diff --git a/src/librbd/DeepCopyRequest.cc b/src/librbd/DeepCopyRequest.cc index 3d93699dc6e53..74c46e8245b54 100644 --- a/src/librbd/DeepCopyRequest.cc +++ b/src/librbd/DeepCopyRequest.cc @@ -104,8 +104,8 @@ void DeepCopyRequest::send_copy_snapshots() { Context *ctx = create_context_callback< DeepCopyRequest, &DeepCopyRequest::handle_copy_snapshots>(this); m_snapshot_copy_request = SnapshotCopyRequest::create( - m_src_image_ctx, m_dst_image_ctx, m_src_snap_id_end, m_flatten, - m_work_queue, m_snap_seqs, ctx); + 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(); diff --git a/src/librbd/api/Migration.cc b/src/librbd/api/Migration.cc index a2fb4fb08b2dd..f776ab7d024b1 100644 --- a/src/librbd/api/Migration.cc +++ b/src/librbd/api/Migration.cc @@ -1287,7 +1287,7 @@ int Migration::create_dst_image() { C_SaferCond on_snapshot_copy; auto snapshot_copy_req = librbd::deep_copy::SnapshotCopyRequest::create( - m_src_image_ctx, dst_image_ctx, CEPH_NOSNAP, m_flatten, + m_src_image_ctx, dst_image_ctx, 0, CEPH_NOSNAP, 0, m_flatten, m_src_image_ctx->op_work_queue, &snap_seqs, &on_snapshot_copy); snapshot_copy_req->send(); r = on_snapshot_copy.wait(); diff --git a/src/librbd/deep_copy/SnapshotCopyRequest.cc b/src/librbd/deep_copy/SnapshotCopyRequest.cc index 25d24b062464d..bfb125b62e1ed 100644 --- a/src/librbd/deep_copy/SnapshotCopyRequest.cc +++ b/src/librbd/deep_copy/SnapshotCopyRequest.cc @@ -45,22 +45,34 @@ using librbd::util::unique_lock_name; template SnapshotCopyRequest::SnapshotCopyRequest(I *src_image_ctx, I *dst_image_ctx, - librados::snap_t snap_id_end, + librados::snap_t src_snap_id_start, + librados::snap_t src_snap_id_end, + librados::snap_t dst_snap_id_start, bool flatten, ContextWQ *work_queue, SnapSeqs *snap_seqs, Context *on_finish) : RefCountedObject(dst_image_ctx->cct), m_src_image_ctx(src_image_ctx), - m_dst_image_ctx(dst_image_ctx), m_snap_id_end(snap_id_end), + 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_work_queue(work_queue), m_snap_seqs_result(snap_seqs), m_snap_seqs(*snap_seqs), m_on_finish(on_finish), m_cct(dst_image_ctx->cct), m_lock(ceph::make_mutex(unique_lock_name("SnapshotCopyRequest::m_lock", this))) { + ceph_assert((m_src_snap_id_start == 0 && m_dst_snap_id_start == 0) || + (m_src_snap_id_start > 0 && m_dst_snap_id_start > 0)); + // snap ids ordered from oldest to newest + m_src_image_ctx->image_lock.lock_shared(); m_src_snap_ids.insert(src_image_ctx->snaps.begin(), src_image_ctx->snaps.end()); + m_src_image_ctx->image_lock.unlock_shared(); + + m_dst_image_ctx->image_lock.lock_shared(); m_dst_snap_ids.insert(dst_image_ctx->snaps.begin(), dst_image_ctx->snaps.end()); - if (m_snap_id_end != CEPH_NOSNAP) { - m_src_snap_ids.erase(m_src_snap_ids.upper_bound(m_snap_id_end), + m_dst_image_ctx->image_lock.unlock_shared(); + + if (m_src_snap_id_end != CEPH_NOSNAP) { + m_src_snap_ids.erase(m_src_snap_ids.upper_bound(m_src_snap_id_end), m_src_snap_ids.end()); } } @@ -99,6 +111,8 @@ void SnapshotCopyRequest::send_snap_unprotect() { SnapIdSet::iterator snap_id_it = m_dst_snap_ids.begin(); if (m_prev_snap_id != CEPH_NOSNAP) { snap_id_it = m_dst_snap_ids.upper_bound(m_prev_snap_id); + } else if (m_dst_snap_id_start > 0) { + snap_id_it = m_dst_snap_ids.upper_bound(m_dst_snap_id_start); } for (; snap_id_it != m_dst_snap_ids.end(); ++snap_id_it) { @@ -197,7 +211,7 @@ void SnapshotCopyRequest::handle_snap_unprotect(int r) { if (r < 0) { lderr(m_cct) << "failed to unprotect snapshot '" << m_snap_name << "': " - << cpp_strerror(r) << dendl; + << cpp_strerror(r) << dendl; finish(r); return; } @@ -224,6 +238,8 @@ void SnapshotCopyRequest::send_snap_remove() { SnapIdSet::iterator snap_id_it = m_dst_snap_ids.begin(); if (m_prev_snap_id != CEPH_NOSNAP) { snap_id_it = m_dst_snap_ids.upper_bound(m_prev_snap_id); + } else if (m_dst_snap_id_start > 0) { + snap_id_it = m_dst_snap_ids.upper_bound(m_dst_snap_id_start); } for (; snap_id_it != m_dst_snap_ids.end(); ++snap_id_it) { @@ -310,6 +326,8 @@ void SnapshotCopyRequest::send_snap_create() { SnapIdSet::iterator snap_id_it = m_src_snap_ids.begin(); if (m_prev_snap_id != CEPH_NOSNAP) { snap_id_it = m_src_snap_ids.upper_bound(m_prev_snap_id); + } else if (m_src_snap_id_start > 0) { + snap_id_it = m_src_snap_ids.upper_bound(m_src_snap_id_start); } for (; snap_id_it != m_src_snap_ids.end(); ++snap_id_it) { @@ -326,10 +344,17 @@ void SnapshotCopyRequest::send_snap_create() { return; } - // if the source snapshot isn't in our mapping table, create it - if (m_snap_seqs.find(src_snap_id) == m_snap_seqs.end() && - boost::get(&snap_namespace) != nullptr) { - break; + if (m_snap_seqs.find(src_snap_id) == m_snap_seqs.end()) { + // the source snapshot is not in our mapping table, ... + if (boost::get(&snap_namespace) != + nullptr) { + // ... create it since it's a user snapshot + break; + } else if (src_snap_id == m_src_snap_id_end) { + // ... map it to destination HEAD since it's not a user snapshot that we + // will create (e.g. MirrorPrimarySnapshotNamespace) + m_snap_seqs[src_snap_id] = CEPH_NOSNAP; + } } } @@ -396,7 +421,7 @@ void SnapshotCopyRequest::handle_snap_create(int r) { if (r < 0) { lderr(m_cct) << "failed to create snapshot '" << m_snap_name << "': " - << cpp_strerror(r) << dendl; + << cpp_strerror(r) << dendl; finish(r); return; } @@ -423,6 +448,8 @@ void SnapshotCopyRequest::send_snap_protect() { SnapIdSet::iterator snap_id_it = m_src_snap_ids.begin(); if (m_prev_snap_id != CEPH_NOSNAP) { snap_id_it = m_src_snap_ids.upper_bound(m_prev_snap_id); + } else if (m_src_snap_id_start > 0) { + snap_id_it = m_src_snap_ids.upper_bound(m_src_snap_id_start); } for (; snap_id_it != m_src_snap_ids.end(); ++snap_id_it) { @@ -449,6 +476,11 @@ void SnapshotCopyRequest::send_snap_protect() { // if destination snapshot is not protected, protect it auto snap_seq_it = m_snap_seqs.find(src_snap_id); ceph_assert(snap_seq_it != m_snap_seqs.end()); + if (snap_seq_it->second == CEPH_NOSNAP) { + // implies src end snapshot is mapped to a non-copyable snapshot + ceph_assert(src_snap_id == m_src_snap_id_end); + break; + } m_dst_image_ctx->image_lock.lock_shared(); bool dst_protected; @@ -516,7 +548,11 @@ void SnapshotCopyRequest::handle_snap_protect(int r) { template void SnapshotCopyRequest::send_set_head() { - if (m_snap_id_end != CEPH_NOSNAP) { + auto snap_seq_it = m_snap_seqs.find(m_src_snap_id_end); + if (m_src_snap_id_end != CEPH_NOSNAP && + (snap_seq_it == m_snap_seqs.end() || + snap_seq_it->second != CEPH_NOSNAP)) { + // not copying to src nor dst HEAD revision finish(0); return; } @@ -528,10 +564,20 @@ void SnapshotCopyRequest::send_set_head() { uint64_t parent_overlap = 0; { std::shared_lock src_locker{m_src_image_ctx->image_lock}; - size = m_src_image_ctx->size; - if (!m_flatten) { - parent_spec = m_src_image_ctx->parent_md.spec; - parent_overlap = m_src_image_ctx->parent_md.overlap; + auto snap_info_it = m_src_image_ctx->snap_info.find(m_src_snap_id_end); + if (snap_info_it != m_src_image_ctx->snap_info.end()) { + auto& snap_info = snap_info_it->second; + size = snap_info.size; + if (!m_flatten) { + parent_spec = snap_info.parent.spec; + parent_overlap = snap_info.parent.overlap; + } + } else { + size = m_src_image_ctx->size; + if (!m_flatten) { + parent_spec = m_src_image_ctx->parent_md.spec; + parent_overlap = m_src_image_ctx->parent_md.overlap; + } } } @@ -563,8 +609,7 @@ template void SnapshotCopyRequest::send_resize_object_map() { int r = 0; - if (m_snap_id_end == CEPH_NOSNAP && - m_dst_image_ctx->test_features(RBD_FEATURE_OBJECT_MAP)) { + if (m_dst_image_ctx->test_features(RBD_FEATURE_OBJECT_MAP)) { std::shared_lock owner_locker{m_dst_image_ctx->owner_lock}; std::shared_lock image_locker{m_dst_image_ctx->image_lock}; diff --git a/src/librbd/deep_copy/SnapshotCopyRequest.h b/src/librbd/deep_copy/SnapshotCopyRequest.h index ede5a76758fee..a80f981336ff8 100644 --- a/src/librbd/deep_copy/SnapshotCopyRequest.h +++ b/src/librbd/deep_copy/SnapshotCopyRequest.h @@ -25,16 +25,22 @@ class SnapshotCopyRequest : public RefCountedObject { public: static SnapshotCopyRequest* create(ImageCtxT *src_image_ctx, ImageCtxT *dst_image_ctx, - librados::snap_t snap_id_end, bool flatten, - ContextWQ *work_queue, SnapSeqs *snap_seqs, - Context *on_finish) { - return new SnapshotCopyRequest(src_image_ctx, dst_image_ctx, snap_id_end, - flatten, work_queue, snap_seqs, on_finish); + librados::snap_t src_snap_id_start, + librados::snap_t src_snap_id_end, + librados::snap_t dst_snap_id_start, + bool flatten, ContextWQ *work_queue, + SnapSeqs *snap_seqs, Context *on_finish) { + return new SnapshotCopyRequest(src_image_ctx, dst_image_ctx, + src_snap_id_start, src_snap_id_end, + dst_snap_id_start, flatten, work_queue, + snap_seqs, on_finish); } SnapshotCopyRequest(ImageCtxT *src_image_ctx, ImageCtxT *dst_image_ctx, - librados::snap_t snap_id_end, bool flatten, - ContextWQ *work_queue, SnapSeqs *snap_seqs, + librados::snap_t src_snap_id_start, + librados::snap_t src_snap_id_end, + librados::snap_t dst_snap_id_start, + bool flatten, ContextWQ *work_queue, SnapSeqs *snap_seqs, Context *on_finish); void send(); @@ -82,7 +88,9 @@ private: ImageCtxT *m_src_image_ctx; ImageCtxT *m_dst_image_ctx; - librados::snap_t m_snap_id_end; + librados::snap_t m_src_snap_id_start; + librados::snap_t m_src_snap_id_end; + librados::snap_t m_dst_snap_id_start; bool m_flatten; ContextWQ *m_work_queue; SnapSeqs *m_snap_seqs_result; diff --git a/src/test/librbd/deep_copy/test_mock_SnapshotCopyRequest.cc b/src/test/librbd/deep_copy/test_mock_SnapshotCopyRequest.cc index 56c5c78a6a533..4495fdc166efb 100644 --- a/src/test/librbd/deep_copy/test_mock_SnapshotCopyRequest.cc +++ b/src/test/librbd/deep_copy/test_mock_SnapshotCopyRequest.cc @@ -154,8 +154,12 @@ public: void expect_get_snap_namespace(librbd::MockTestImageCtx &mock_image_ctx, uint64_t snap_id) { EXPECT_CALL(mock_image_ctx, get_snap_namespace(snap_id, _)) - .WillOnce(DoAll(SetArgPointee<1>(cls::rbd::UserSnapshotNamespace()), - Return(0))); + .WillOnce(Invoke([&mock_image_ctx](uint64_t snap_id, + cls::rbd::SnapshotNamespace* snap_ns) { + auto it = mock_image_ctx.snap_info.find(snap_id); + *snap_ns = it->second.snap_namespace; + return 0; + })); } void expect_snap_create(librbd::MockTestImageCtx &mock_image_ctx, @@ -223,24 +227,29 @@ public: MockSnapshotCopyRequest *create_request( librbd::MockTestImageCtx &mock_src_image_ctx, - librbd::MockTestImageCtx &mock_dst_image_ctx, Context *on_finish, - librados::snap_t snap_id_end = CEPH_NOSNAP) { + librbd::MockTestImageCtx &mock_dst_image_ctx, + librados::snap_t src_snap_id_start, + librados::snap_t src_snap_id_end, + librados::snap_t dst_snap_id_start, + Context *on_finish) { return new MockSnapshotCopyRequest(&mock_src_image_ctx, &mock_dst_image_ctx, - snap_id_end, false, m_work_queue, + src_snap_id_start, src_snap_id_end, + dst_snap_id_start, false, m_work_queue, &m_snap_seqs, on_finish); } - int create_snap(librbd::ImageCtx *image_ctx, const std::string &snap_name, - bool protect = false) { - int r = image_ctx->operations->snap_create(cls::rbd::UserSnapshotNamespace(), - snap_name.c_str()); + int create_snap(librbd::ImageCtx *image_ctx, + const cls::rbd::SnapshotNamespace& snap_ns, + const std::string &snap_name, bool protect) { + int r = image_ctx->operations->snap_create(snap_ns, snap_name.c_str()); if (r < 0) { return r; } if (protect) { - r = image_ctx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(), - snap_name.c_str()); + EXPECT_TRUE(boost::get(&snap_ns) != + nullptr); + r = image_ctx->operations->snap_protect(snap_ns, snap_name.c_str()); if (r < 0) { return r; } @@ -253,6 +262,12 @@ public: return 0; } + int create_snap(librbd::ImageCtx *image_ctx, const std::string &snap_name, + bool protect = false) { + return create_snap(image_ctx, cls::rbd::UserSnapshotNamespace{}, snap_name, + protect); + } + void validate_snap_seqs(const librbd::SnapSeqs &snap_seqs) { ASSERT_EQ(snap_seqs, m_snap_seqs); } @@ -273,7 +288,8 @@ TEST_F(TestMockDeepCopySnapshotCopyRequest, Empty) { C_SaferCond ctx; MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx, - mock_dst_image_ctx, &ctx); + mock_dst_image_ctx, 0, + CEPH_NOSNAP, 0, &ctx); request->send(); ASSERT_EQ(0, ctx.wait()); @@ -312,7 +328,8 @@ TEST_F(TestMockDeepCopySnapshotCopyRequest, SnapCreate) { C_SaferCond ctx; MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx, - mock_dst_image_ctx, &ctx); + mock_dst_image_ctx, 0, + CEPH_NOSNAP, 0, &ctx); request->send(); ASSERT_EQ(0, ctx.wait()); @@ -342,7 +359,8 @@ TEST_F(TestMockDeepCopySnapshotCopyRequest, SnapCreateError) { C_SaferCond ctx; MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx, - mock_dst_image_ctx, &ctx); + mock_dst_image_ctx, 0, + CEPH_NOSNAP, 0, &ctx); request->send(); ASSERT_EQ(-EINVAL, ctx.wait()); } @@ -363,7 +381,8 @@ TEST_F(TestMockDeepCopySnapshotCopyRequest, SnapCreateCancel) { C_SaferCond ctx; MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx, - mock_dst_image_ctx, &ctx); + mock_dst_image_ctx, 0, + CEPH_NOSNAP, 0, &ctx); expect_test_features(mock_dst_image_ctx); InSequence seq; @@ -415,7 +434,8 @@ TEST_F(TestMockDeepCopySnapshotCopyRequest, SnapRemoveAndCreate) { C_SaferCond ctx; MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx, - mock_dst_image_ctx, &ctx); + mock_dst_image_ctx, 0, + CEPH_NOSNAP, 0, &ctx); request->send(); ASSERT_EQ(0, ctx.wait()); @@ -447,7 +467,8 @@ TEST_F(TestMockDeepCopySnapshotCopyRequest, SnapRemoveError) { C_SaferCond ctx; MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx, - mock_dst_image_ctx, &ctx); + mock_dst_image_ctx, 0, + CEPH_NOSNAP, 0, &ctx); request->send(); ASSERT_EQ(-EINVAL, ctx.wait()); } @@ -485,7 +506,8 @@ TEST_F(TestMockDeepCopySnapshotCopyRequest, SnapUnprotect) { C_SaferCond ctx; MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx, - mock_dst_image_ctx, &ctx); + mock_dst_image_ctx, 0, + CEPH_NOSNAP, 0, &ctx); request->send(); ASSERT_EQ(0, ctx.wait()); @@ -520,7 +542,8 @@ TEST_F(TestMockDeepCopySnapshotCopyRequest, SnapUnprotectError) { C_SaferCond ctx; MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx, - mock_dst_image_ctx, &ctx); + mock_dst_image_ctx, 0, + CEPH_NOSNAP, 0, &ctx); request->send(); ASSERT_EQ(-EBUSY, ctx.wait()); } @@ -545,7 +568,8 @@ TEST_F(TestMockDeepCopySnapshotCopyRequest, SnapUnprotectCancel) { C_SaferCond ctx; MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx, - mock_dst_image_ctx, &ctx); + mock_dst_image_ctx, 0, + CEPH_NOSNAP, 0, &ctx); expect_test_features(mock_dst_image_ctx); InSequence seq; @@ -605,7 +629,8 @@ TEST_F(TestMockDeepCopySnapshotCopyRequest, SnapUnprotectRemove) { C_SaferCond ctx; MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx, - mock_dst_image_ctx, &ctx); + mock_dst_image_ctx, 0, + CEPH_NOSNAP, 0, &ctx); request->send(); ASSERT_EQ(0, ctx.wait()); @@ -643,7 +668,8 @@ TEST_F(TestMockDeepCopySnapshotCopyRequest, SnapCreateProtect) { C_SaferCond ctx; MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx, - mock_dst_image_ctx, &ctx); + mock_dst_image_ctx, 0, + CEPH_NOSNAP, 0, &ctx); request->send(); ASSERT_EQ(0, ctx.wait()); @@ -683,7 +709,8 @@ TEST_F(TestMockDeepCopySnapshotCopyRequest, SnapProtect) { C_SaferCond ctx; MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx, - mock_dst_image_ctx, &ctx); + mock_dst_image_ctx, 0, + CEPH_NOSNAP, 0, &ctx); request->send(); ASSERT_EQ(0, ctx.wait()); @@ -721,7 +748,8 @@ TEST_F(TestMockDeepCopySnapshotCopyRequest, SnapProtectError) { C_SaferCond ctx; MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx, - mock_dst_image_ctx, &ctx); + mock_dst_image_ctx, 0, + CEPH_NOSNAP, 0, &ctx); request->send(); ASSERT_EQ(-EINVAL, ctx.wait()); } @@ -746,7 +774,8 @@ TEST_F(TestMockDeepCopySnapshotCopyRequest, SnapProtectCancel) { C_SaferCond ctx; MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx, - mock_dst_image_ctx, &ctx); + mock_dst_image_ctx, 0, + CEPH_NOSNAP, 0, &ctx); expect_test_features(mock_dst_image_ctx); InSequence seq; @@ -784,7 +813,8 @@ TEST_F(TestMockDeepCopySnapshotCopyRequest, SetHeadError) { C_SaferCond ctx; MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx, - mock_dst_image_ctx, &ctx); + mock_dst_image_ctx, 0, + CEPH_NOSNAP, 0, &ctx); request->send(); ASSERT_EQ(-EINVAL, ctx.wait()); } @@ -815,13 +845,73 @@ TEST_F(TestMockDeepCopySnapshotCopyRequest, NoSetHead) { C_SaferCond ctx; MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx, - mock_dst_image_ctx, &ctx, - src_snap_id1); + mock_dst_image_ctx,0, + src_snap_id1, 0, &ctx); request->send(); ASSERT_EQ(0, ctx.wait()); validate_snap_seqs({{src_snap_id1, 12}}); } +TEST_F(TestMockDeepCopySnapshotCopyRequest, StartEndLimit) { + REQUIRE_FEATURE(RBD_FEATURE_LAYERING); + + ASSERT_EQ(0, create_snap(m_src_image_ctx, "snap1", false)); + ASSERT_EQ(0, create_snap(m_src_image_ctx, "snap2", false)); + ASSERT_EQ(0, create_snap(m_src_image_ctx, + {cls::rbd::MirrorPrimarySnapshotNamespace{ + false, {{"peer uuid1"}}}}, + "snap3", false)); + auto src_snap_id1 = m_src_image_ctx->snaps[2]; + auto src_snap_id2 = m_src_image_ctx->snaps[1]; + auto src_snap_id3 = m_src_image_ctx->snaps[0]; + + ASSERT_EQ(0, create_snap(m_dst_image_ctx, "snap0", true)); + ASSERT_EQ(0, create_snap(m_dst_image_ctx, "snap1", false)); + ASSERT_EQ(0, create_snap(m_dst_image_ctx, "snap3", false)); + auto dst_snap_id1 = m_dst_image_ctx->snaps[1]; + auto dst_snap_id3 = m_dst_image_ctx->snaps[0]; + + librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); + librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); + MockSnapshotCreateRequest mock_snapshot_create_request; + + librbd::MockExclusiveLock mock_exclusive_lock; + prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock); + + expect_test_features(mock_dst_image_ctx); + + InSequence seq; + expect_snap_is_unprotected(mock_dst_image_ctx, dst_snap_id3, + true, 0); + + expect_get_snap_namespace(mock_dst_image_ctx, dst_snap_id3); + expect_start_op(mock_exclusive_lock); + expect_snap_remove(mock_dst_image_ctx, "snap3", 0); + + expect_get_snap_namespace(mock_src_image_ctx, src_snap_id2); + expect_start_op(mock_exclusive_lock); + expect_snap_create(mock_dst_image_ctx, mock_snapshot_create_request, "snap2", + 12, 0); + expect_get_snap_namespace(mock_src_image_ctx, src_snap_id3); + + expect_snap_is_protected(mock_src_image_ctx, src_snap_id2, false, 0); + expect_snap_is_protected(mock_src_image_ctx, src_snap_id3, false, 0); + + MockSetHeadRequest mock_set_head_request; + expect_set_head(mock_set_head_request, 0); + + C_SaferCond ctx; + MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx, + mock_dst_image_ctx, + src_snap_id1, + src_snap_id3, + dst_snap_id1, &ctx); + request->send(); + ASSERT_EQ(0, ctx.wait()); + + validate_snap_seqs({{src_snap_id2, 12}, {src_snap_id3, CEPH_NOSNAP}}); +} + } // namespace deep_copy } // namespace librbd diff --git a/src/test/librbd/test_mock_DeepCopyRequest.cc b/src/test/librbd/test_mock_DeepCopyRequest.cc index 0329b057323d4..6f96e4ba3ea78 100644 --- a/src/test/librbd/test_mock_DeepCopyRequest.cc +++ b/src/test/librbd/test_mock_DeepCopyRequest.cc @@ -94,9 +94,11 @@ public: static SnapshotCopyRequest* create(librbd::MockTestImageCtx *src_image_ctx, librbd::MockTestImageCtx *dst_image_ctx, - librados::snap_t snap_id_end, bool flatten, - ContextWQ *work_queue, SnapSeqs *snap_seqs, - Context *on_finish) { + librados::snap_t src_snap_id_start, + librados::snap_t src_snap_id_end, + librados::snap_t dst_snap_id_start, + bool flatten, ContextWQ *work_queue, + SnapSeqs *snap_seqs, Context *on_finish) { ceph_assert(s_instance != nullptr); s_instance->on_finish = on_finish; return s_instance; -- 2.39.5