]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: deep-copy objects from specified start position 33097/head
authorJason Dillaman <dillaman@redhat.com>
Wed, 5 Feb 2020 20:54:55 +0000 (15:54 -0500)
committerJason Dillaman <dillaman@redhat.com>
Thu, 13 Feb 2020 13:11:17 +0000 (08:11 -0500)
Only read data from from after the specified start position and copy it
to the specified starting write position in the destination.

Fixes: https://tracker.ceph.com/issues/43933
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
src/librbd/DeepCopyRequest.cc
src/librbd/deep_copy/ImageCopyRequest.cc
src/librbd/deep_copy/ImageCopyRequest.h
src/librbd/deep_copy/ObjectCopyRequest.cc
src/librbd/deep_copy/ObjectCopyRequest.h
src/librbd/io/CopyupRequest.cc
src/librbd/operation/MigrateRequest.cc
src/test/librbd/deep_copy/test_mock_ImageCopyRequest.cc
src/test/librbd/deep_copy/test_mock_ObjectCopyRequest.cc
src/test/librbd/io/test_mock_CopyupRequest.cc
src/test/librbd/test_mock_DeepCopyRequest.cc

index 74c46e8245b542d5f9a33015c0b93cf628a7a69c..90fde47b71dbf9dc0ed9a618ae9c5865be15189c 100644 (file)
@@ -158,7 +158,8 @@ void DeepCopyRequest<I>::send_copy_image() {
     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_flatten, m_object_number, *m_snap_seqs, m_prog_ctx, ctx);
+    m_dst_snap_id_start, m_flatten, m_object_number, *m_snap_seqs, m_prog_ctx,
+    ctx);
   m_image_copy_request->get();
   m_lock.unlock();
 
index 75cdae00b8ac3088ea1161a0a16b86cd1bcacc06..64be5fee908153a5405b3cc1c389b427b56f1561 100644 (file)
@@ -25,6 +25,7 @@ template <typename I>
 ImageCopyRequest<I>::ImageCopyRequest(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,
                                       const SnapSeqs &snap_seqs,
@@ -32,8 +33,8 @@ ImageCopyRequest<I>::ImageCopyRequest(I *src_image_ctx, I *dst_image_ctx,
                                       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_flatten(flatten),
-    m_object_number(object_number), m_snap_seqs(snap_seqs),
+    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_snap_seqs(snap_seqs),
     m_prog_ctx(prog_ctx), m_on_finish(on_finish), m_cct(dst_image_ctx->cct),
     m_lock(ceph::make_mutex(unique_lock_name("ImageCopyRequest::m_lock", this))) {
 }
@@ -126,7 +127,8 @@ void ImageCopyRequest<I>::send_next_object_copy() {
       handle_object_copy(ono, r);
     });
   ObjectCopyRequest<I> *req = ObjectCopyRequest<I>::create(
-      m_src_image_ctx, m_dst_image_ctx, m_snap_map, ono, m_flatten, ctx);
+    m_src_image_ctx, m_dst_image_ctx, m_src_snap_id_start, m_dst_snap_id_start,
+    m_snap_map, ono, m_flatten, ctx);
   req->send();
 }
 
index 8b0860087229bca44e3cc3be0f7f4158f9a61f6a..903952254427a7d18e2613a761b60642a54df719 100644 (file)
@@ -32,19 +32,21 @@ public:
                                   ImageCtxT *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,
                                   const SnapSeqs &snap_seqs,
                                   ProgressContext *prog_ctx,
                                   Context *on_finish) {
     return new ImageCopyRequest(src_image_ctx, dst_image_ctx, src_snap_id_start,
-                                src_snap_id_end, flatten, object_number,
-                                snap_seqs, prog_ctx, on_finish);
+                                src_snap_id_end, dst_snap_id_start, flatten,
+                                object_number, snap_seqs, prog_ctx, on_finish);
   }
 
   ImageCopyRequest(ImageCtxT *src_image_ctx, ImageCtxT *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,
                    const SnapSeqs &snap_seqs, ProgressContext *prog_ctx,
                    Context *on_finish);
@@ -72,6 +74,7 @@ private:
   ImageCtxT *m_dst_image_ctx;
   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;
   ObjectNumber m_object_number;
   SnapSeqs m_snap_seqs;
index 42ad774ff4906799e424e4546935b3ded1d31f11..23f31bae64ea8d463e27e9ece8c17d4efa2b9448 100644 (file)
@@ -43,13 +43,17 @@ using librbd::util::create_rados_callback;
 template <typename I>
 ObjectCopyRequest<I>::ObjectCopyRequest(I *src_image_ctx,
                                         I *dst_image_ctx,
+                                        librados::snap_t src_snap_id_start,
+                                        librados::snap_t dst_snap_id_start,
                                         const SnapMap &snap_map,
                                         uint64_t dst_object_number,
                                         bool flatten, Context *on_finish)
   : m_src_image_ctx(src_image_ctx),
     m_dst_image_ctx(dst_image_ctx), m_cct(dst_image_ctx->cct),
-    m_snap_map(snap_map), m_dst_object_number(dst_object_number),
-    m_flatten(flatten), m_on_finish(on_finish) {
+    m_src_snap_id_start(src_snap_id_start),
+    m_dst_snap_id_start(dst_snap_id_start), m_snap_map(snap_map),
+    m_dst_object_number(dst_object_number), m_flatten(flatten),
+    m_on_finish(on_finish) {
   ceph_assert(src_image_ctx->data_ctx.is_valid());
   ceph_assert(dst_image_ctx->data_ctx.is_valid());
   ceph_assert(!m_snap_map.empty());
@@ -318,12 +322,15 @@ void ObjectCopyRequest<I>::send_write_object() {
     }
 
     // write snapshot context should be before actual snapshot
-    if (snap_map_it != m_snap_map.begin()) {
-      --snap_map_it;
-      ceph_assert(!snap_map_it->second.empty());
-      dst_snap_seq = snap_map_it->second.front();
-      dst_snap_ids = snap_map_it->second;
+    ceph_assert(!snap_map_it->second.empty());
+    auto dst_snap_ids_it = snap_map_it->second.begin();
+    ++dst_snap_ids_it;
+
+    dst_snap_ids = SnapIds{dst_snap_ids_it, snap_map_it->second.end()};
+    if (!dst_snap_ids.empty()) {
+      dst_snap_seq = dst_snap_ids.front();
     }
+    ceph_assert(dst_snap_seq != CEPH_NOSNAP);
   }
 
   ldout(m_cct, 20) << "dst_snap_seq=" << dst_snap_seq << ", "
@@ -581,10 +588,10 @@ void ObjectCopyRequest<I>::compute_read_ops() {
   m_src_image_ctx->image_lock.unlock_shared();
 
   librados::snap_t src_copy_point_snap_id = m_snap_map.rbegin()->first;
-  bool prev_exists = hide_parent;
+  bool prev_exists = (hide_parent || m_src_snap_id_start > 0);
   uint64_t prev_end_size = prev_exists ?
       m_src_image_ctx->layout.object_size : 0;
-  librados::snap_t start_src_snap_id = 0;
+  librados::snap_t start_src_snap_id = m_src_snap_id_start;
 
   for (auto &pair : m_snap_map) {
     ceph_assert(!pair.second.empty());
index a1dccf5d770a5a765a934d1fdc8110d59a0306e1..20f3ea37b252d50e2e0de236996b9cb3d3c96c3d 100644 (file)
@@ -29,16 +29,20 @@ class ObjectCopyRequest {
 public:
   static ObjectCopyRequest* create(ImageCtxT *src_image_ctx,
                                    ImageCtxT *dst_image_ctx,
+                                   librados::snap_t src_snap_id_start,
+                                   librados::snap_t dst_snap_id_start,
                                    const SnapMap &snap_map,
                                    uint64_t object_number, bool flatten,
                                    Context *on_finish) {
-    return new ObjectCopyRequest(src_image_ctx, dst_image_ctx, snap_map,
+    return new ObjectCopyRequest(src_image_ctx, dst_image_ctx,
+                                 src_snap_id_start, dst_snap_id_start, snap_map,
                                  object_number, flatten, on_finish);
   }
 
   ObjectCopyRequest(ImageCtxT *src_image_ctx, ImageCtxT *dst_image_ctx,
-                    const SnapMap &snap_map, uint64_t object_number,
-                    bool flatten, Context *on_finish);
+                    librados::snap_t src_snap_id_start,
+                    librados::snap_t dst_snap_id_start, const SnapMap &snap_map,
+                    uint64_t object_number, bool flatten, Context *on_finish);
 
   void send();
 
@@ -136,6 +140,8 @@ private:
   ImageCtxT *m_src_image_ctx;
   ImageCtxT *m_dst_image_ctx;
   CephContext *m_cct;
+  librados::snap_t m_src_snap_id_start;
+  librados::snap_t m_dst_snap_id_start;
   SnapMap m_snap_map;
   uint64_t m_dst_object_number;
   bool m_flatten;
index b65ab475e14db2121e9e37a330d42d3edade0bcc..066d15f4eaa17f04e2c150e2d965c57d00a54a01 100644 (file)
@@ -240,8 +240,8 @@ void CopyupRequest<I>::deep_copy() {
   auto ctx = util::create_context_callback<
     CopyupRequest<I>, &CopyupRequest<I>::handle_deep_copy>(this);
   auto req = deep_copy::ObjectCopyRequest<I>::create(
-    m_image_ctx->parent, m_image_ctx, m_image_ctx->migration_info.snap_map,
-    m_object_no, m_flatten, ctx);
+    m_image_ctx->parent, m_image_ctx, 0, 0,
+    m_image_ctx->migration_info.snap_map, m_object_no, m_flatten, ctx);
 
   req->send();
 }
index 04992ba6443ea68759d0d5143f819374d27da871..890d26c4b07b85bc086ba0fd494881194c443cf3 100644 (file)
@@ -129,7 +129,7 @@ private:
       ceph_assert(image_ctx.parent != nullptr);
 
       auto req = deep_copy::ObjectCopyRequest<I>::create(
-        image_ctx.parent, &image_ctx, image_ctx.migration_info.snap_map,
+        image_ctx.parent, &image_ctx, 0, 0, image_ctx.migration_info.snap_map,
         m_object_no, image_ctx.migration_info.flatten, ctx);
 
       ldout(cct, 20) << "deep copy object req " << req << ", object_no "
index cfe3228686f3af901090282002fdad4879331bd6..8becf673b07826285e42f9df86eb75f3b974df6c 100644 (file)
@@ -49,7 +49,10 @@ struct ObjectCopyRequest<librbd::MockTestImageCtx> {
   static ObjectCopyRequest* s_instance;
   static ObjectCopyRequest* create(
       librbd::MockTestImageCtx *src_image_ctx,
-      librbd::MockTestImageCtx *dst_image_ctx, const SnapMap &snap_map,
+      librbd::MockTestImageCtx *dst_image_ctx,
+      librados::snap_t src_snap_id_start,
+      librados::snap_t dst_snap_id_start,
+      const SnapMap &snap_map,
       uint64_t object_number, bool flatten, Context *on_finish) {
     ceph_assert(s_instance != nullptr);
     std::lock_guard locker{s_instance->lock};
@@ -271,7 +274,7 @@ TEST_F(TestMockDeepCopyImageCopyRequest, SimpleImage) {
   C_SaferCond ctx;
   auto request = new MockImageCopyRequest(&mock_src_image_ctx,
                                           &mock_dst_image_ctx,
-                                          0, snap_id_end, false, boost::none,
+                                          0, snap_id_end, 0, false, boost::none,
                                           m_snap_seqs, &no_op, &ctx);
   request->send();
 
@@ -330,7 +333,7 @@ TEST_F(TestMockDeepCopyImageCopyRequest, OutOfOrder) {
   C_SaferCond ctx;
   auto request = new MockImageCopyRequest(&mock_src_image_ctx,
                                           &mock_dst_image_ctx,
-                                          0, snap_id_end, false, boost::none,
+                                          0, snap_id_end, 0, false, boost::none,
                                           m_snap_seqs, &prog_ctx, &ctx);
   request->send();
 
@@ -375,7 +378,7 @@ TEST_F(TestMockDeepCopyImageCopyRequest, SnapshotSubset) {
   C_SaferCond ctx;
   auto request = new MockImageCopyRequest(&mock_src_image_ctx,
                                           &mock_dst_image_ctx,
-                                          snap_id_start, snap_id_end, false,
+                                          snap_id_start, snap_id_end, 0, false,
                                           boost::none, m_snap_seqs, &no_op,
                                           &ctx);
   request->send();
@@ -405,7 +408,7 @@ TEST_F(TestMockDeepCopyImageCopyRequest, RestartPartialSync) {
   C_SaferCond ctx;
   auto request = new MockImageCopyRequest(&mock_src_image_ctx,
                                           &mock_dst_image_ctx,
-                                          0, snap_id_end, false,
+                                          0, snap_id_end, 0, false,
                                           librbd::deep_copy::ObjectNumber{0U},
                                           m_snap_seqs, &no_op, &ctx);
   request->send();
@@ -439,7 +442,7 @@ TEST_F(TestMockDeepCopyImageCopyRequest, Cancel) {
   C_SaferCond ctx;
   auto request = new MockImageCopyRequest(&mock_src_image_ctx,
                                           &mock_dst_image_ctx,
-                                          0, snap_id_end, false, boost::none,
+                                          0, snap_id_end, 0, false, boost::none,
                                           m_snap_seqs, &no_op, &ctx);
   request->send();
 
@@ -484,7 +487,7 @@ TEST_F(TestMockDeepCopyImageCopyRequest, Cancel_Inflight_Sync) {
   C_SaferCond ctx;
   auto request = new MockImageCopyRequest(&mock_src_image_ctx,
                                           &mock_dst_image_ctx,
-                                          0, snap_id_end, false, boost::none,
+                                          0, snap_id_end, 0, false, boost::none,
                                           m_snap_seqs, &prog_ctx, &ctx);
   request->send();
 
@@ -514,7 +517,7 @@ TEST_F(TestMockDeepCopyImageCopyRequest, MissingSnap) {
   C_SaferCond ctx;
   auto request = new MockImageCopyRequest(&mock_src_image_ctx,
                                           &mock_dst_image_ctx,
-                                          0, 123, false, boost::none,
+                                          0, 123, 0, false, boost::none,
                                           m_snap_seqs, &no_op, &ctx);
   request->send();
   ASSERT_EQ(-EINVAL, ctx.wait());
@@ -531,8 +534,9 @@ TEST_F(TestMockDeepCopyImageCopyRequest, MissingFromSnap) {
   C_SaferCond ctx;
   auto request = new MockImageCopyRequest(&mock_src_image_ctx,
                                           &mock_dst_image_ctx,
-                                          123, snap_id_end, false, boost::none,
-                                          m_snap_seqs, &no_op, &ctx);
+                                          123, snap_id_end, 0, false,
+                                          boost::none, m_snap_seqs, &no_op,
+                                          &ctx);
   request->send();
   ASSERT_EQ(-EINVAL, ctx.wait());
 }
@@ -550,7 +554,7 @@ TEST_F(TestMockDeepCopyImageCopyRequest, EmptySnapMap) {
   C_SaferCond ctx;
   auto request = new MockImageCopyRequest(&mock_src_image_ctx,
                                           &mock_dst_image_ctx,
-                                          snap_id_start, snap_id_end, false,
+                                          snap_id_start, snap_id_end, 0, false,
                                           boost::none, {{0, 0}}, &no_op, &ctx);
   request->send();
   ASSERT_EQ(-EINVAL, ctx.wait());
@@ -569,7 +573,7 @@ TEST_F(TestMockDeepCopyImageCopyRequest, EmptySnapSeqs) {
   C_SaferCond ctx;
   auto request = new MockImageCopyRequest(&mock_src_image_ctx,
                                           &mock_dst_image_ctx,
-                                          snap_id_start, snap_id_end, false,
+                                          snap_id_start, snap_id_end, 0, false,
                                           boost::none, {}, &no_op, &ctx);
   request->send();
   ASSERT_EQ(-EINVAL, ctx.wait());
index 63c8adb2aac1c01f32fa7e573b76514649766aa3..056792cd5e3a8676360224df35eec292600cd441 100644 (file)
@@ -204,9 +204,13 @@ public:
 
   MockObjectCopyRequest *create_request(
       librbd::MockTestImageCtx &mock_src_image_ctx,
-      librbd::MockTestImageCtx &mock_dst_image_ctx, Context *on_finish) {
+      librbd::MockTestImageCtx &mock_dst_image_ctx,
+      librados::snap_t src_snap_id_start,
+      librados::snap_t dst_snap_id_start,
+      Context *on_finish) {
     expect_get_object_name(mock_dst_image_ctx);
     return new MockObjectCopyRequest(&mock_src_image_ctx, &mock_dst_image_ctx,
+                                     src_snap_id_start, dst_snap_id_start,
                                      m_snap_map, 0, false, on_finish);
   }
 
@@ -366,6 +370,26 @@ public:
     return it->first.second;
   }
 
+  int copy_objects() {
+    int r;
+    uint64_t object_size = 1 << m_src_image_ctx->order;
+
+    bufferlist bl;
+    bl.append(std::string(object_size, '1'));
+    r = m_src_image_ctx->io_work_queue->read(
+      0, object_size, librbd::io::ReadResult{&bl}, 0);
+    if (r < 0) {
+      return r;
+    }
+
+    r = m_dst_image_ctx->io_work_queue->write(0, object_size, std::move(bl), 0);
+    if (r < 0) {
+      return r;
+    }
+
+    return 0;
+  }
+
   int compare_objects() {
     SnapMap snap_map(m_snap_map);
     if (snap_map.empty()) {
@@ -418,6 +442,8 @@ public:
       }
 
       if (!src_bl.contents_equal(dst_bl)) {
+        std::cout << "src block: " << std::endl; src_bl.hexdump(std::cout);
+        std::cout << "dst block: " << std::endl; dst_bl.hexdump(std::cout);
         return -EBADMSG;
       }
     }
@@ -454,7 +480,8 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, DNE) {
 
   C_SaferCond ctx;
   MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
-                                                  mock_dst_image_ctx, &ctx);
+                                                  mock_dst_image_ctx, 0, 0,
+                                                  &ctx);
 
   librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
     request->get_src_io_ctx()));
@@ -486,7 +513,8 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, Write) {
 
   C_SaferCond ctx;
   MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
-                                                  mock_dst_image_ctx, &ctx);
+                                                  mock_dst_image_ctx, 0, 0,
+                                                  &ctx);
 
   librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
     request->get_src_io_ctx()));
@@ -532,7 +560,8 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, ReadMissingStaleSnapSet) {
 
   C_SaferCond ctx;
   MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
-                                                  mock_dst_image_ctx, &ctx);
+                                                  mock_dst_image_ctx, 0, 0,
+                                                  &ctx);
 
   librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
     request->get_src_io_ctx()));
@@ -597,7 +626,8 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, ReadMissingUpToDateSnapMap) {
 
   C_SaferCond ctx;
   MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
-                                                  mock_dst_image_ctx, &ctx);
+                                                  mock_dst_image_ctx, 0, 0,
+                                                  &ctx);
 
   librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
     request->get_src_io_ctx()));
@@ -631,7 +661,8 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, ReadError) {
 
   C_SaferCond ctx;
   MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
-                                                  mock_dst_image_ctx, &ctx);
+                                                  mock_dst_image_ctx, 0, 0,
+                                                  &ctx);
 
   librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
     request->get_src_io_ctx()));
@@ -665,7 +696,8 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, WriteError) {
 
   C_SaferCond ctx;
   MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
-                                                  mock_dst_image_ctx, &ctx);
+                                                  mock_dst_image_ctx, 0, 0,
+                                                  &ctx);
 
   librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
     request->get_src_io_ctx()));
@@ -714,7 +746,8 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, WriteSnaps) {
 
   C_SaferCond ctx;
   MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
-                                                  mock_dst_image_ctx, &ctx);
+                                                  mock_dst_image_ctx, 0, 0,
+                                                  &ctx);
 
   librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
     request->get_src_io_ctx()));
@@ -779,7 +812,8 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, Trim) {
 
   C_SaferCond ctx;
   MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
-                                                  mock_dst_image_ctx, &ctx);
+                                                  mock_dst_image_ctx, 0, 0,
+                                                  &ctx);
 
   librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
     request->get_src_io_ctx()));
@@ -832,7 +866,8 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, Remove) {
 
   C_SaferCond ctx;
   MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
-                                                  mock_dst_image_ctx, &ctx);
+                                                  mock_dst_image_ctx, 0, 0,
+                                                  &ctx);
 
   librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
     request->get_src_io_ctx()));
@@ -883,7 +918,8 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, ObjectMapUpdateError) {
 
   C_SaferCond ctx;
   MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
-                                                  mock_dst_image_ctx, &ctx);
+                                                  mock_dst_image_ctx, 0, 0,
+                                                  &ctx);
 
   librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
     request->get_src_io_ctx()));
@@ -904,5 +940,99 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, ObjectMapUpdateError) {
   ASSERT_EQ(-EBLACKLISTED, ctx.wait());
 }
 
+TEST_F(TestMockDeepCopyObjectCopyRequest, WriteSnapsStart) {
+  // scribble some data
+  interval_set<uint64_t> one;
+  scribble(m_src_image_ctx, 10, 102400, &one);
+  ASSERT_EQ(0, copy_objects());
+  ASSERT_EQ(0, create_snap("one"));
+
+  auto src_snap_id_start = m_src_image_ctx->snaps[0];
+  auto dst_snap_id_start = m_dst_image_ctx->snaps[0];
+
+  interval_set<uint64_t> two;
+  scribble(m_src_image_ctx, 10, 102400, &two);
+  ASSERT_EQ(0, create_snap("two"));
+
+  interval_set<uint64_t> three;
+  scribble(m_src_image_ctx, 10, 102400, &three);
+  ASSERT_EQ(0, create_snap("three"));
+
+  auto max_extent = one.range_end();
+  if (max_extent < two.range_end()) {
+    interval_set<uint64_t> resize_diff;
+    resize_diff.insert(max_extent, two.range_end() - max_extent);
+    two.union_of(resize_diff);
+  }
+
+  max_extent = std::max(max_extent, two.range_end());
+  if (max_extent < three.range_end()) {
+    interval_set<uint64_t> resize_diff;
+    resize_diff.insert(max_extent, three.range_end() - max_extent);
+    three.union_of(resize_diff);
+  }
+
+  interval_set<uint64_t> four;
+  scribble(m_src_image_ctx, 10, 102400, &four);
+
+  // map should begin after src start and src end's dst snap seqs should
+  // point to HEAD revision
+  m_snap_map.erase(src_snap_id_start);
+  m_snap_map[m_src_image_ctx->snaps[0]][0] = CEPH_NOSNAP;
+
+  librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
+  librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
+
+  librbd::MockExclusiveLock mock_exclusive_lock;
+  prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
+
+  librbd::MockObjectMap mock_object_map;
+  mock_dst_image_ctx.object_map = &mock_object_map;
+
+  expect_test_features(mock_dst_image_ctx);
+  expect_get_object_count(mock_dst_image_ctx);
+
+  C_SaferCond ctx;
+  MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
+                                                  mock_dst_image_ctx,
+                                                  src_snap_id_start,
+                                                  dst_snap_id_start,
+                                                  &ctx);
+
+  librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
+    request->get_src_io_ctx()));
+  librados::MockTestMemIoCtxImpl &mock_dst_io_ctx(get_mock_io_ctx(
+    request->get_dst_io_ctx()));
+
+  InSequence seq;
+  expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx, 0);
+
+  expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[1]);
+  expect_sparse_read(mock_src_io_ctx, two, 0);
+
+  expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[2]);
+  expect_sparse_read(mock_src_io_ctx, three, 0);
+
+  expect_start_op(mock_exclusive_lock);
+  expect_write(mock_dst_io_ctx, two,
+               {m_dst_snap_ids[0], {m_dst_snap_ids[0]}}, 0);
+
+  expect_start_op(mock_exclusive_lock);
+  expect_write(mock_dst_io_ctx, three,
+               {m_dst_snap_ids[1], {m_dst_snap_ids[1], m_dst_snap_ids[0]}}, 0);
+
+  expect_start_op(mock_exclusive_lock);
+  expect_update_object_map(mock_dst_image_ctx, mock_object_map,
+                           m_dst_snap_ids[1], OBJECT_EXISTS, 0);
+
+  expect_start_op(mock_exclusive_lock);
+  expect_update_object_map(mock_dst_image_ctx, mock_object_map,
+                           CEPH_NOSNAP, OBJECT_EXISTS, 0);
+
+  request->send();
+  ASSERT_EQ(0, ctx.wait());
+  ASSERT_EQ(0, compare_objects());
+}
+
 } // namespace deep_copy
 } // namespace librbd
index e565941865336c5131deb04a727f2f44a561c951..50c2f7b56ff3aca107d72922f6d78b5faa776d80 100644 (file)
@@ -47,6 +47,8 @@ struct ObjectCopyRequest<librbd::MockTestImageCtx> {
   static ObjectCopyRequest* s_instance;
   static ObjectCopyRequest* create(librbd::MockImageCtx* parent_image_ctx,
                                    librbd::MockTestImageCtx* image_ctx,
+                                   librados::snap_t src_snap_id_start,
+                                   librados::snap_t dst_snap_id_start,
                                    const SnapMap &snap_map,
                                    uint64_t object_number, bool flatten,
                                    Context *on_finish) {
index 6f96e4ba3ea78abf79339b18932f6e95dd1070fb..fa5f77e8f468e04c03fe537783dffe60d11153c8 100644 (file)
@@ -41,10 +41,12 @@ public:
 
   static ImageCopyRequest* create(
       librbd::MockTestImageCtx *src_image_ctx,
-      librbd::MockTestImageCtx *dst_image_ctx, librados::snap_t snap_id_start,
-      librados::snap_t snap_id_end, bool flatten,
-      const ObjectNumber &object_number, const SnapSeqs &snap_seqs,
-      ProgressContext *prog_ctx,
+      librbd::MockTestImageCtx *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,
+      const SnapSeqs &snap_seqs, ProgressContext *prog_ctx,
       Context *on_finish) {
     ceph_assert(s_instance != nullptr);
     s_instance->on_finish = on_finish;