]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: deep-copy objects from specified start position
authorJason Dillaman <dillaman@redhat.com>
Wed, 5 Feb 2020 20:54:55 +0000 (15:54 -0500)
committerJason Dillaman <dillaman@redhat.com>
Wed, 16 Sep 2020 17:19:29 +0000 (13:19 -0400)
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>
(cherry picked from commit d445ac503a9b8aa7a8f7d235023325cca44d58ce)

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 1116c05d4ac3bfc862c5a4a7f32e7830c9db333b..3350fa3b9d11b0979cabdc9cef0e56aabe414f60 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 266e76b956b881b57979bc03853f6e7ba1a9d7cd..62e5409c27db8272d24dc110e728855cb45e4820 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, 1), 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(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 5a50cdd16ffb2f138e4996b57cad846c5ee8899e..189cb2375eacfdb7b195ad813414bd929cdedcbd 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 92a1750f1152e2c753454673b9f2e21c67d049fe..2400757a72a7928be2624f868b8baed417b500c0 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());
@@ -321,12 +325,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 << ", "
@@ -585,10 +592,10 @@ void ObjectCopyRequest<I>::compute_read_ops() {
   m_src_image_ctx->parent_lock.put_read();
 
   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 6df98e695ad0e97f83e1296c26bf3b14b7f49e7a..a0445f3bb01bdb9340d788ce3fdff081b98edc75 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 06ef47ca86504af6d32829717b9836c0b0b0fc8f..c2ebb10feda2c2a42c73bbc77344be7e44a4e4ff 100644 (file)
@@ -235,8 +235,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 71a6f93288efa38e09c230befe1e5138860cc66e..e3ddff0e3e5dce41938d29b87c0a4543c04fe3e8 100644 (file)
@@ -131,7 +131,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 a3e5effd9989e87ce6d3460b5ce3b6c54c31bed1..d6cc03a574f794596de15a382d3cbaf4fe4bae16 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);
     Mutex::Locker 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 7816a507e90d7d90fc22adc041b09f3a089077d8..ebaf479bfab5189df263d87928c226b7643e214a 100644 (file)
@@ -205,9 +205,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);
   }
 
@@ -368,6 +372,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()) {
@@ -420,6 +444,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;
       }
     }
@@ -456,7 +482,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()));
@@ -488,7 +515,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()));
@@ -534,7 +562,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()));
@@ -599,7 +628,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()));
@@ -633,7 +663,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()));
@@ -667,7 +698,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()));
@@ -716,7 +748,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()));
@@ -781,7 +814,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()));
@@ -834,7 +868,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()));
@@ -885,7 +920,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()));
@@ -906,5 +942,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 c6a28595ae87aa9e678d0acb4278fb7382320f94..7a30f59a138c2745234a343bf1b1a3065ddd1fda 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 58877028a697a726e69597b79a340d20c11c45c5..483c65aaa5e0a82e3c2a4587ed82fa7bb9cc69c1 100644 (file)
@@ -40,10 +40,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;