librbd: deep copy optionally support flattening cloned image
authorMykola Golub <mgolub@suse.com>
Thu, 26 Apr 2018 08:30:03 +0000 (11:30 +0300)
committerJason Dillaman <dillaman@redhat.com>
Wed, 16 May 2018 18:06:20 +0000 (14:06 -0400)
Fixes: http://tracker.ceph.com/issues/22787
Signed-off-by: Mykola Golub <mgolub@suse.com>
(cherry picked from commit 0d43d2faceca158cc9cf2177802b80dda2b554c9)

19 files changed:
src/include/rbd/librbd.h
src/librbd/DeepCopyRequest.cc
src/librbd/DeepCopyRequest.h
src/librbd/api/Image.cc
src/librbd/api/Image.h
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/deep_copy/SnapshotCopyRequest.cc
src/librbd/deep_copy/SnapshotCopyRequest.h
src/librbd/internal.cc
src/test/librbd/deep_copy/test_mock_ImageCopyRequest.cc
src/test/librbd/deep_copy/test_mock_ObjectCopyRequest.cc
src/test/librbd/deep_copy/test_mock_SnapshotCopyRequest.cc
src/test/librbd/test_DeepCopy.cc
src/test/librbd/test_mock_DeepCopyRequest.cc
src/test/rbd_mirror/test_mock_ImageSync.cc
src/tools/rbd_mirror/ImageSync.cc

index 51d83f9066d42cf945e3c4ec464eff2ac3f155a4..ee86d8aad23011fe3b82cc3f34396f05bed955de 100644 (file)
@@ -206,7 +206,8 @@ enum {
   RBD_IMAGE_OPTION_JOURNAL_POOL = 7,
   RBD_IMAGE_OPTION_FEATURES_SET = 8,
   RBD_IMAGE_OPTION_FEATURES_CLEAR = 9,
-  RBD_IMAGE_OPTION_DATA_POOL = 10
+  RBD_IMAGE_OPTION_DATA_POOL = 10,
+  RBD_IMAGE_OPTION_FLATTEN = 11,
 };
 
 typedef enum {
index b5983e9efded6a953a56c3ecfced7a93c4c43a4d..29f5f60198c19176c93c4475a8efa0e14b91d6a2 100644 (file)
@@ -29,16 +29,17 @@ using librbd::util::unique_lock_name;
 template <typename I>
 DeepCopyRequest<I>::DeepCopyRequest(I *src_image_ctx, I *dst_image_ctx,
                                     librados::snap_t snap_id_start,
-                                    librados::snap_t snap_id_end,
+                                    librados::snap_t snap_id_end, bool flatten,
                                     const ObjectNumber &object_number,
                                     ContextWQ *work_queue, SnapSeqs *snap_seqs,
                                     ProgressContext *prog_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_snap_id_start(snap_id_start),
-    m_snap_id_end(snap_id_end), m_object_number(object_number),
-    m_work_queue(work_queue), m_snap_seqs(snap_seqs), m_prog_ctx(prog_ctx),
-    m_on_finish(on_finish), m_cct(dst_image_ctx->cct),
+    m_snap_id_end(snap_id_end), m_flatten(flatten),
+    m_object_number(object_number), m_work_queue(work_queue),
+    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("DeepCopyRequest::m_lock", this)) {
 }
 
@@ -90,8 +91,8 @@ void DeepCopyRequest<I>::send_copy_snapshots() {
   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_snap_id_end, m_work_queue, m_snap_seqs,
-    ctx);
+    m_src_image_ctx, m_dst_image_ctx, m_snap_id_end, m_flatten, m_work_queue,
+    m_snap_seqs, ctx);
   m_snapshot_copy_request->get();
   m_lock.Unlock();
 
@@ -140,7 +141,7 @@ 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_snap_id_start, m_snap_id_end,
-      m_object_number, *m_snap_seqs, m_prog_ctx, ctx);
+      m_flatten, m_object_number, *m_snap_seqs, m_prog_ctx, ctx);
   m_image_copy_request->get();
   m_lock.Unlock();
 
index 553f575f7f8a46198120012d38036595a39549ee..dba07e6a862dc874d1840ec7bf31e7e70dcba0ab 100644 (file)
@@ -33,20 +33,20 @@ public:
   static DeepCopyRequest* create(ImageCtxT *src_image_ctx,
                                  ImageCtxT *dst_image_ctx,
                                  librados::snap_t snap_id_start,
-                                 librados::snap_t snap_id_end,
+                                 librados::snap_t snap_id_end, bool flatten,
                                  const deep_copy::ObjectNumber &object_number,
                                  ContextWQ *work_queue,
                                  SnapSeqs *snap_seqs,
                                  ProgressContext *prog_ctx,
                                  Context *on_finish) {
     return new DeepCopyRequest(src_image_ctx, dst_image_ctx, snap_id_start,
-                               snap_id_end, object_number, work_queue,
+                               snap_id_end, flatten, object_number, work_queue,
                                snap_seqs, prog_ctx, on_finish);
   }
 
   DeepCopyRequest(ImageCtxT *src_image_ctx, ImageCtxT *dst_image_ctx,
                   librados::snap_t snap_id_start, librados::snap_t snap_id_end,
-                  const deep_copy::ObjectNumber &object_number,
+                  bool flatten, const deep_copy::ObjectNumber &object_number,
                   ContextWQ *work_queue, SnapSeqs *snap_seqs,
                   ProgressContext *prog_ctx, Context *on_finish);
   ~DeepCopyRequest();
@@ -88,6 +88,7 @@ private:
   ImageCtxT *m_dst_image_ctx;
   librados::snap_t m_snap_id_start;
   librados::snap_t m_snap_id_end;
+  bool m_flatten;
   deep_copy::ObjectNumber m_object_number;
   ContextWQ *m_work_queue;
   SnapSeqs *m_snap_seqs;
index 0d3c8a46ff4d5054ba01c2cdad5d259900f40a0f..5c61746deeb99fe3ea35601fd66ffa27b5368f78 100644 (file)
@@ -205,8 +205,15 @@ int Image<I>::deep_copy(I *src, librados::IoCtx& dest_md_ctx,
     return -ENOSYS;
   }
 
+  uint64_t flatten = 0;
+  if (opts.get(RBD_IMAGE_OPTION_FLATTEN, &flatten) == 0) {
+    opts.unset(RBD_IMAGE_OPTION_FLATTEN);
+  }
+
   ParentSpec parent_spec;
-  {
+  if (flatten > 0) {
+    parent_spec.pool_id = -1;
+  } else {
     RWLock::RLocker snap_locker(src->snap_lock);
     RWLock::RLocker parent_locker(src->parent_lock);
 
@@ -297,7 +304,7 @@ int Image<I>::deep_copy(I *src, librados::IoCtx& dest_md_ctx,
     return r;
   }
 
-  r = deep_copy(src, dest, prog_ctx);
+  r = deep_copy(src, dest, flatten > 0, prog_ctx);
 
   int close_r = dest->state->close();
   if (r == 0 && close_r < 0) {
@@ -307,7 +314,8 @@ int Image<I>::deep_copy(I *src, librados::IoCtx& dest_md_ctx,
 }
 
 template <typename I>
-int Image<I>::deep_copy(I *src, I *dest, ProgressContext &prog_ctx) {
+int Image<I>::deep_copy(I *src, I *dest, bool flatten,
+                        ProgressContext &prog_ctx) {
   CephContext *cct = src->cct;
   librados::snap_t snap_id_start = 0;
   librados::snap_t snap_id_end;
@@ -323,8 +331,8 @@ int Image<I>::deep_copy(I *src, I *dest, ProgressContext &prog_ctx) {
   C_SaferCond cond;
   SnapSeqs snap_seqs;
   auto req = DeepCopyRequest<>::create(src, dest, snap_id_start, snap_id_end,
-                                       boost::none, op_work_queue, &snap_seqs,
-                                       &prog_ctx, &cond);
+                                       flatten, boost::none, op_work_queue,
+                                       &snap_seqs, &prog_ctx, &cond);
   req->send();
   int r = cond.wait();
   if (r < 0) {
index cefab1aaea536b04a79adc2955925c30a3d353de..062d98c23c820d6c02f799eafab8a1fa7cb0d2a6 100644 (file)
@@ -38,7 +38,7 @@ struct Image {
   static int deep_copy(ImageCtxT *ictx, librados::IoCtx& dest_md_ctx,
                        const char *destname, ImageOptions& opts,
                        ProgressContext &prog_ctx);
-  static int deep_copy(ImageCtxT *src, ImageCtxT *dest,
+  static int deep_copy(ImageCtxT *src, ImageCtxT *dest, bool flatten,
                        ProgressContext &prog_ctx);
 
   static int snap_set(ImageCtxT *ictx,
index d101aa8d17d62e1587ee8ca716d759d366004786..e3f742413fc21bfc5e164a4db3f0ebdbbb6026e3 100644 (file)
@@ -26,15 +26,16 @@ template <typename I>
 ImageCopyRequest<I>::ImageCopyRequest(I *src_image_ctx, I *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,
                                       Context *on_finish)
   : RefCountedObject(dst_image_ctx->cct, 1), m_src_image_ctx(src_image_ctx),
     m_dst_image_ctx(dst_image_ctx), m_snap_id_start(snap_id_start),
-    m_snap_id_end(snap_id_end), 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_snap_id_end(snap_id_end), 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)) {
 }
 
@@ -207,7 +208,7 @@ void ImageCopyRequest<I>::send_next_object_copy() {
     });
   ObjectCopyRequest<I> *req = ObjectCopyRequest<I>::create(
       m_src_image_ctx, m_src_parent_image_ctx, m_dst_image_ctx, m_snap_map, ono,
-      ctx);
+      m_flatten, ctx);
   req->send();
 }
 
index 8c395a34c9fd2c9923a5adacb33375c0f5b65bc0..c8fc08169f34946a7239b141f1b14bec07c30157 100644 (file)
@@ -31,20 +31,21 @@ public:
   static ImageCopyRequest* create(ImageCtxT *src_image_ctx,
                                   ImageCtxT *dst_image_ctx,
                                   librados::snap_t snap_id_start,
-                                  librados::snap_t snap_id_end,
+                                  librados::snap_t snap_id_end, 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, snap_id_start,
-                                snap_id_end, object_number, snap_seqs, prog_ctx,
-                                on_finish);
+                                snap_id_end, flatten, object_number, snap_seqs,
+                                prog_ctx, on_finish);
   }
 
   ImageCopyRequest(ImageCtxT *src_image_ctx, ImageCtxT *dst_image_ctx,
                    librados::snap_t snap_id_start, librados::snap_t snap_id_end,
-                   const ObjectNumber &object_number, const SnapSeqs &snap_seqs,
-                   ProgressContext *prog_ctx, Context *on_finish);
+                   bool flatten, const ObjectNumber &object_number,
+                   const SnapSeqs &snap_seqs, ProgressContext *prog_ctx,
+                   Context *on_finish);
 
   void send();
   void cancel();
@@ -79,6 +80,7 @@ private:
   ImageCtxT *m_dst_image_ctx;
   librados::snap_t m_snap_id_start;
   librados::snap_t m_snap_id_end;
+  bool m_flatten;
   ObjectNumber m_object_number;
   SnapSeqs m_snap_seqs;
   ProgressContext *m_prog_ctx;
index 98aa24b8f478d2c30f5f7a432d1da9fcc7f1e97e..7fb911d23df847a5f17045c513d0454fccc82b56 100644 (file)
@@ -45,12 +45,12 @@ ObjectCopyRequest<I>::ObjectCopyRequest(I *src_image_ctx,
                                         I *dst_image_ctx,
                                         const SnapMap &snap_map,
                                         uint64_t dst_object_number,
-                                        Context *on_finish)
+                                        bool flatten, Context *on_finish)
   : m_src_image_ctx(src_image_ctx),
     m_src_parent_image_ctx(src_parent_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_on_finish(on_finish) {
+    m_flatten(flatten), m_on_finish(on_finish) {
   assert(!m_snap_map.empty());
 
   m_src_io_ctx.dup(m_src_image_ctx->data_ctx);
@@ -704,7 +704,7 @@ void ObjectCopyRequest<I>::compute_read_from_parent_ops(
     return;
   }
 
-  if (noent_count == m_src_object_extents.size()) {
+  if (noent_count == m_src_object_extents.size() && !m_flatten) {
     ldout(m_cct, 20) << "reading all extents skipped when no flatten"
                      << dendl;
     return;
index e10daea86c7bcf21e17e78e50f7aef53231ea6c2..0d6598b08c50dfd90f2a7b83e0d11f4c1f38c461 100644 (file)
@@ -28,16 +28,16 @@ public:
                                    ImageCtxT *src_parent_image_ctx,
                                    ImageCtxT *dst_image_ctx,
                                    const SnapMap &snap_map,
-                                   uint64_t object_number,
+                                   uint64_t object_number, bool flatten,
                                    Context *on_finish) {
     return new ObjectCopyRequest(src_image_ctx, src_parent_image_ctx,
                                  dst_image_ctx, snap_map, object_number,
-                                 on_finish);
+                                 flatten, on_finish);
   }
 
   ObjectCopyRequest(ImageCtxT *src_image_ctx, ImageCtxT *src_parent_image_ctx,
                     ImageCtxT *dst_image_ctx, const SnapMap &snap_map,
-                    uint64_t object_number, Context *on_finish);
+                    uint64_t object_number, bool flatten, Context *on_finish);
 
   void send();
 
@@ -138,6 +138,7 @@ private:
   CephContext *m_cct;
   const SnapMap &m_snap_map;
   uint64_t m_dst_object_number;
+  bool m_flatten;
   Context *m_on_finish;
 
   decltype(m_src_image_ctx->data_ctx) m_src_io_ctx;
index 72c764132edddb99429c5652aa88616e87be5b2f..49c3a1b6bd8353325839fa92ad142712fcffae3a 100644 (file)
@@ -44,12 +44,12 @@ template <typename I>
 SnapshotCopyRequest<I>::SnapshotCopyRequest(I *src_image_ctx,
                                             I *dst_image_ctx,
                                             librados::snap_t snap_id_end,
-                                            ContextWQ *work_queue,
+                                            bool flatten, ContextWQ *work_queue,
                                             SnapSeqs *snap_seqs,
                                             Context *on_finish)
   : RefCountedObject(dst_image_ctx->cct, 1), m_src_image_ctx(src_image_ctx),
     m_dst_image_ctx(dst_image_ctx), m_snap_id_end(snap_id_end),
-    m_work_queue(work_queue), m_snap_seqs_result(snap_seqs),
+    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(unique_lock_name("SnapshotCopyRequest::m_lock", this)) {
   // snap ids ordered from oldest to newest
@@ -353,7 +353,7 @@ void SnapshotCopyRequest<I>::send_snap_create() {
   m_snap_namespace = snap_info_it->second.snap_namespace;
   librbd::ParentSpec parent_spec;
   uint64_t parent_overlap = 0;
-  if (snap_info_it->second.parent.spec.pool_id != -1) {
+  if (!m_flatten && snap_info_it->second.parent.spec.pool_id != -1) {
     parent_spec = m_dst_parent_spec;
     parent_overlap = snap_info_it->second.parent.overlap;
   }
@@ -519,12 +519,14 @@ void SnapshotCopyRequest<I>::send_set_head() {
 
   uint64_t size;
   ParentSpec parent_spec;
-  uint64_t parent_overlap;
+  uint64_t parent_overlap = 0;
   {
     RWLock::RLocker src_locker(m_src_image_ctx->snap_lock);
     size = m_src_image_ctx->size;
-    parent_spec = m_src_image_ctx->parent_md.spec;
-    parent_overlap = m_src_image_ctx->parent_md.overlap;
+    if (!m_flatten) {
+      parent_spec = m_src_image_ctx->parent_md.spec;
+      parent_overlap = m_src_image_ctx->parent_md.overlap;
+    }
   }
 
   auto ctx = create_context_callback<
index 47ab83e4982aa734940a62a548cddc23a66165c3..f5769a65be7dba61a80652ac079e67976fe92b3f 100644 (file)
@@ -25,17 +25,17 @@ class SnapshotCopyRequest : public RefCountedObject {
 public:
   static SnapshotCopyRequest* create(ImageCtxT *src_image_ctx,
                                      ImageCtxT *dst_image_ctx,
-                                     librados::snap_t snap_id_end,
-                                     ContextWQ *work_queue,
-                                     SnapSeqs *snap_seqs,
+                                     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,
-                                   work_queue, snap_seqs, on_finish);
+                                   flatten, work_queue, snap_seqs, on_finish);
   }
 
   SnapshotCopyRequest(ImageCtxT *src_image_ctx, ImageCtxT *dst_image_ctx,
-                      librados::snap_t snap_id_end, ContextWQ *work_queue,
-                      SnapSeqs *snap_seqs, Context *on_finish);
+                      librados::snap_t snap_id_end, bool flatten,
+                      ContextWQ *work_queue, SnapSeqs *snap_seqs,
+                      Context *on_finish);
 
   void send();
   void cancel();
@@ -80,6 +80,7 @@ private:
   ImageCtxT *m_src_image_ctx;
   ImageCtxT *m_dst_image_ctx;
   librados::snap_t m_snap_id_end;
+  bool m_flatten;
   ContextWQ *m_work_queue;
   SnapSeqs *m_snap_seqs_result;
   SnapSeqs m_snap_seqs;
index 7a9f7267b468f269bb875f570fa7fa024ba245da..2ef36f582235fb91cbd89838a4ac3f4b5b0bed37 100644 (file)
@@ -311,6 +311,7 @@ bool compare_by_name(const child_info_t& c1, const child_info_t& c2)
     {RBD_IMAGE_OPTION_FEATURES_SET, UINT64},
     {RBD_IMAGE_OPTION_FEATURES_CLEAR, UINT64},
     {RBD_IMAGE_OPTION_DATA_POOL, STR},
+    {RBD_IMAGE_OPTION_FLATTEN, UINT64},
   };
 
   std::string image_option_name(int optname) {
@@ -337,6 +338,8 @@ bool compare_by_name(const child_info_t& c1, const child_info_t& c2)
       return "features_clear";
     case RBD_IMAGE_OPTION_DATA_POOL:
       return "data_pool";
+    case RBD_IMAGE_OPTION_FLATTEN:
+      return "flatten";
     default:
       return "unknown (" + stringify(optname) + ")";
     }
@@ -842,6 +845,12 @@ bool compare_by_name(const child_info_t& c1, const child_info_t& c2)
     }
 
     CephContext *cct = (CephContext *)io_ctx.cct();
+    uint64_t flatten;
+    if (opts.get(RBD_IMAGE_OPTION_FLATTEN, &flatten) == 0) {
+      lderr(cct) << "create does not support 'flatten' image option" << dendl;
+      return -EINVAL;
+    }
+
     ldout(cct, 10) << __func__ << " name=" << image_name << ", "
                   << "id= " << id << ", "
                   << "size=" << size << ", opts=" << opts << dendl;
@@ -930,6 +939,12 @@ bool compare_by_name(const child_info_t& c1, const child_info_t& c2)
       return -EINVAL;
     }
 
+    uint64_t flatten;
+    if (c_opts.get(RBD_IMAGE_OPTION_FLATTEN, &flatten) == 0) {
+      lderr(cct) << "clone does not support 'flatten' image option" << dendl;
+      return -EINVAL;
+    }
+
     // make sure parent snapshot exists
     ImageCtx *p_imctx = new ImageCtx(p_name, "", p_snap_name, p_ioctx, true);
     int r = p_imctx->state->open(false);
@@ -1728,6 +1743,12 @@ bool compare_by_name(const child_info_t& c1, const child_info_t& c2)
           ImageOptions& opts, ProgressContext &prog_ctx, size_t sparse_size)
   {
     CephContext *cct = (CephContext *)dest_md_ctx.cct();
+    uint64_t flatten;
+    if (opts.get(RBD_IMAGE_OPTION_FLATTEN, &flatten) == 0) {
+      lderr(cct) << "copy does not support 'flatten' image option" << dendl;
+      return -EINVAL;
+    }
+
     ldout(cct, 20) << "copy " << src->name
                   << (src->snap_name.length() ? "@" + src->snap_name : "")
                   << " -> " << destname << " opts = " << opts << dendl;
index bd4f897249c99a0fc43ab423a8b422891ab003d4..602a12f04756bca0f8f652fe8769ad8af48b73a8 100644 (file)
@@ -52,7 +52,7 @@ struct ObjectCopyRequest<librbd::MockTestImageCtx> {
       librbd::MockTestImageCtx *src_image_ctx,
       librbd::MockTestImageCtx *src_parent_image_ctx,
       librbd::MockTestImageCtx *dst_image_ctx, const SnapMap &snap_map,
-      uint64_t object_number, Context *on_finish) {
+      uint64_t object_number, bool flatten, Context *on_finish) {
     assert(s_instance != nullptr);
     Mutex::Locker locker(s_instance->lock);
     s_instance->snap_map = &snap_map;
@@ -298,7 +298,7 @@ TEST_F(TestMockDeepCopyImageCopyRequest, SimpleImage) {
   C_SaferCond ctx;
   auto request = new MockImageCopyRequest(&mock_src_image_ctx,
                                           &mock_dst_image_ctx,
-                                          0, snap_id_end, boost::none,
+                                          0, snap_id_end, false, boost::none,
                                           m_snap_seqs, &no_op, &ctx);
   request->send();
 
@@ -358,7 +358,7 @@ TEST_F(TestMockDeepCopyImageCopyRequest, OutOfOrder) {
   C_SaferCond ctx;
   auto request = new MockImageCopyRequest(&mock_src_image_ctx,
                                           &mock_dst_image_ctx,
-                                          0, snap_id_end, boost::none,
+                                          0, snap_id_end, false, boost::none,
                                           m_snap_seqs, &prog_ctx, &ctx);
   request->send();
 
@@ -404,7 +404,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,
+                                          snap_id_start, snap_id_end, false,
                                           boost::none, m_snap_seqs, &no_op,
                                           &ctx);
   request->send();
@@ -435,7 +435,7 @@ TEST_F(TestMockDeepCopyImageCopyRequest, RestartPartialSync) {
   C_SaferCond ctx;
   auto request = new MockImageCopyRequest(&mock_src_image_ctx,
                                           &mock_dst_image_ctx,
-                                          0, snap_id_end,
+                                          0, snap_id_end, false,
                                           librbd::deep_copy::ObjectNumber{0U},
                                           m_snap_seqs, &no_op, &ctx);
   request->send();
@@ -470,7 +470,7 @@ TEST_F(TestMockDeepCopyImageCopyRequest, Cancel) {
   C_SaferCond ctx;
   auto request = new MockImageCopyRequest(&mock_src_image_ctx,
                                           &mock_dst_image_ctx,
-                                          0, snap_id_end, boost::none,
+                                          0, snap_id_end, false, boost::none,
                                           m_snap_seqs, &no_op, &ctx);
   request->send();
 
@@ -516,7 +516,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, boost::none,
+                                          0, snap_id_end, false, boost::none,
                                           m_snap_seqs, &prog_ctx, &ctx);
   request->send();
 
@@ -546,7 +546,7 @@ TEST_F(TestMockDeepCopyImageCopyRequest, MissingSnap) {
   C_SaferCond ctx;
   auto request = new MockImageCopyRequest(&mock_src_image_ctx,
                                           &mock_dst_image_ctx,
-                                          0, 123, boost::none,
+                                          0, 123, false, boost::none,
                                           m_snap_seqs, &no_op, &ctx);
   request->send();
   ASSERT_EQ(-EINVAL, ctx.wait());
@@ -563,7 +563,7 @@ TEST_F(TestMockDeepCopyImageCopyRequest, MissingFromSnap) {
   C_SaferCond ctx;
   auto request = new MockImageCopyRequest(&mock_src_image_ctx,
                                           &mock_dst_image_ctx,
-                                          123, snap_id_end, boost::none,
+                                          123, snap_id_end, false, boost::none,
                                           m_snap_seqs, &no_op, &ctx);
   request->send();
   ASSERT_EQ(-EINVAL, ctx.wait());
@@ -582,7 +582,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,
+                                          snap_id_start, snap_id_end, false,
                                           boost::none, {{0, 0}}, &no_op, &ctx);
   request->send();
   ASSERT_EQ(-EINVAL, ctx.wait());
@@ -601,7 +601,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,
+                                          snap_id_start, snap_id_end, false,
                                           boost::none, {}, &no_op, &ctx);
   request->send();
   ASSERT_EQ(-EINVAL, ctx.wait());
index cc86b800aaa8019844fee80451f49da36cce9761..c92bf342869ea48b4a57de695775b5dc0f4104f4 100644 (file)
@@ -199,7 +199,7 @@ public:
       librbd::MockTestImageCtx &mock_dst_image_ctx, Context *on_finish) {
     expect_get_object_name(mock_dst_image_ctx);
     return new MockObjectCopyRequest(&mock_src_image_ctx, nullptr,
-                                     &mock_dst_image_ctx, m_snap_map, 0,
+                                     &mock_dst_image_ctx, m_snap_map, 0, false,
                                      on_finish);
   }
 
index 805003e7f51f1ebd4bc8f8baef028bbdcce803ee..4c4f42ad06d0c31ba45d5818d12b09474f77a3ef 100644 (file)
@@ -223,8 +223,8 @@ public:
       librbd::MockTestImageCtx &mock_dst_image_ctx, Context *on_finish,
       librados::snap_t snap_id_end = CEPH_NOSNAP) {
     return new MockSnapshotCopyRequest(&mock_src_image_ctx, &mock_dst_image_ctx,
-                                       snap_id_end, m_work_queue, &m_snap_seqs,
-                                       on_finish);
+                                       snap_id_end, false, m_work_queue,
+                                       &m_snap_seqs, on_finish);
   }
 
   int create_snap(librbd::ImageCtx *image_ctx, const std::string &snap_name,
index 451f22212791d5e35e6a68d001756d270de2e4fe..fcd1a2876a40b923e1685e42baa4338df07eb38c 100644 (file)
@@ -406,6 +406,16 @@ TEST_F(TestDeepCopy, Clone)
   test_clone();
 }
 
+TEST_F(TestDeepCopy, CloneFlatten)
+{
+  REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
+
+  uint64_t flatten = 1;
+  ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_FLATTEN, flatten));
+
+  test_clone();
+}
+
 TEST_F(TestDeepCopy, Stress)
 {
   test_stress();
@@ -437,6 +447,18 @@ TEST_F(TestDeepCopy, Clone_LargerDstObjSize)
   test_clone();
 }
 
+TEST_F(TestDeepCopy, CloneFlatten_LargerDstObjSize)
+{
+  REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
+
+  uint64_t order = m_src_ictx->order + 1 + rand() % 2;
+  ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_ORDER, order));
+  uint64_t flatten = 1;
+  ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_FLATTEN, flatten));
+
+  test_clone();
+}
+
 TEST_F(TestDeepCopy, Stress_LargerDstObjSize)
 {
   uint64_t order = m_src_ictx->order + 1 + rand() % 2;
@@ -477,6 +499,20 @@ TEST_F(TestDeepCopy, Clone_SmallerDstObjSize)
   test_clone();
 }
 
+TEST_F(TestDeepCopy, CloneFlatten_SmallerDstObjSize)
+{
+  REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
+
+  uint64_t order = m_src_ictx->order - 1 - rand() % 2;
+  ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_ORDER, order));
+  uint64_t stripe_unit = m_src_ictx->stripe_unit >> 2;
+  ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit));
+  uint64_t flatten = 1;
+  ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_FLATTEN, flatten));
+
+  test_clone();
+}
+
 TEST_F(TestDeepCopy, Stress_SmallerDstObjSize)
 {
   uint64_t order = m_src_ictx->order - 1 - rand() % 2;
@@ -529,6 +565,22 @@ TEST_F(TestDeepCopy, Clone_StrippingLargerDstObjSize)
   test_clone();
 }
 
+TEST_F(TestDeepCopy, CloneFlatten_StrippingLargerDstObjSize)
+{
+  REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_STRIPINGV2);
+
+  uint64_t order = m_src_ictx->order + 1;
+  uint64_t stripe_unit = 1 << (order - 2);
+  uint64_t stripe_count = 4;
+  ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_ORDER, order));
+  ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit));
+  ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, stripe_count));
+  uint64_t flatten = 1;
+  ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_FLATTEN, flatten));
+
+  test_clone();
+}
+
 TEST_F(TestDeepCopy, Stress_StrippingLargerDstObjSize)
 {
   REQUIRE_FEATURE(RBD_FEATURE_STRIPINGV2);
@@ -585,6 +637,22 @@ TEST_F(TestDeepCopy, Clone_StrippingSmallerDstObjSize)
   test_clone();
 }
 
+TEST_F(TestDeepCopy, CloneFlatten_StrippingSmallerDstObjSize)
+{
+  REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_STRIPINGV2);
+
+  uint64_t order = m_src_ictx->order - 1 - rand() % 2;
+  uint64_t stripe_unit = 1 << (order - rand() % 4);
+  uint64_t stripe_count = 2 + rand() % 14;
+  ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_ORDER, order));
+  ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit));
+  ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, stripe_count));
+  uint64_t flatten = 1;
+  ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_FLATTEN, flatten));
+
+  test_clone();
+}
+
 TEST_F(TestDeepCopy, Stress_StrippingSmallerDstObjSize)
 {
   REQUIRE_FEATURE(RBD_FEATURE_STRIPINGV2);
index 1148d4584002195c56dec8255170cc763fb8e98a..5d394ba73af65833e4ef2b832f1141ab3b116400 100644 (file)
@@ -41,8 +41,9 @@ 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, const ObjectNumber &object_number,
-      const SnapSeqs &snap_seqs, ProgressContext *prog_ctx,
+      librados::snap_t snap_id_end, bool flatten,
+      const ObjectNumber &object_number, const SnapSeqs &snap_seqs,
+      ProgressContext *prog_ctx,
       Context *on_finish) {
     assert(s_instance != nullptr);
     s_instance->on_finish = on_finish;
@@ -92,7 +93,7 @@ public:
 
   static SnapshotCopyRequest* create(librbd::MockTestImageCtx *src_image_ctx,
                                      librbd::MockTestImageCtx *dst_image_ctx,
-                                     librados::snap_t snap_id_end,
+                                     librados::snap_t snap_id_end, bool flatten,
                                      ContextWQ *work_queue, SnapSeqs *snap_seqs,
                                      Context *on_finish) {
     assert(s_instance != nullptr);
@@ -260,8 +261,8 @@ TEST_F(TestMockDeepCopyRequest, SimpleCopy) {
   librbd::SnapSeqs snap_seqs;
   librbd::NoOpProgressContext no_op;
   auto request = librbd::DeepCopyRequest<librbd::MockTestImageCtx>::create(
-      &mock_src_image_ctx, &mock_dst_image_ctx, 0, CEPH_NOSNAP, boost::none,
-      m_work_queue, &snap_seqs, &no_op, &ctx);
+      &mock_src_image_ctx, &mock_dst_image_ctx, 0, CEPH_NOSNAP, false,
+      boost::none, m_work_queue, &snap_seqs, &no_op, &ctx);
   request->send();
   ASSERT_EQ(0, ctx.wait());
 }
@@ -278,8 +279,8 @@ TEST_F(TestMockDeepCopyRequest, ErrorOnCopySnapshots) {
   librbd::SnapSeqs snap_seqs;
   librbd::NoOpProgressContext no_op;
   auto request = librbd::DeepCopyRequest<librbd::MockTestImageCtx>::create(
-      &mock_src_image_ctx, &mock_dst_image_ctx, 0, CEPH_NOSNAP, boost::none,
-      m_work_queue, &snap_seqs, &no_op, &ctx);
+      &mock_src_image_ctx, &mock_dst_image_ctx, 0, CEPH_NOSNAP, false,
+      boost::none, m_work_queue, &snap_seqs, &no_op, &ctx);
   request->send();
   ASSERT_EQ(-EINVAL, ctx.wait());
 }
@@ -298,8 +299,8 @@ TEST_F(TestMockDeepCopyRequest, ErrorOnCopyImage) {
   librbd::SnapSeqs snap_seqs;
   librbd::NoOpProgressContext no_op;
   auto request = librbd::DeepCopyRequest<librbd::MockTestImageCtx>::create(
-      &mock_src_image_ctx, &mock_dst_image_ctx, 0, CEPH_NOSNAP, boost::none,
-      m_work_queue, &snap_seqs, &no_op, &ctx);
+      &mock_src_image_ctx, &mock_dst_image_ctx, 0, CEPH_NOSNAP, false,
+      boost::none, m_work_queue, &snap_seqs, &no_op, &ctx);
   request->send();
   ASSERT_EQ(-EINVAL, ctx.wait());
 }
@@ -333,8 +334,8 @@ TEST_F(TestMockDeepCopyRequest, ErrorOnCopyMetadata) {
   librbd::SnapSeqs snap_seqs;
   librbd::NoOpProgressContext no_op;
   auto request = librbd::DeepCopyRequest<librbd::MockTestImageCtx>::create(
-      &mock_src_image_ctx, &mock_dst_image_ctx, 0, CEPH_NOSNAP, boost::none,
-      m_work_queue, &snap_seqs, &no_op, &ctx);
+      &mock_src_image_ctx, &mock_dst_image_ctx, 0, CEPH_NOSNAP, false,
+      boost::none, m_work_queue, &snap_seqs, &no_op, &ctx);
   request->send();
   ASSERT_EQ(-EINVAL, ctx.wait());
 }
@@ -375,7 +376,7 @@ TEST_F(TestMockDeepCopyRequest, Snap) {
   librbd::NoOpProgressContext no_op;
   auto request = librbd::DeepCopyRequest<librbd::MockTestImageCtx>::create(
       &mock_src_image_ctx, &mock_dst_image_ctx, 0, m_src_image_ctx->snap_id,
-      boost::none, m_work_queue, &snap_seqs, &no_op, &ctx);
+      false, boost::none, m_work_queue, &snap_seqs, &no_op, &ctx);
   request->send();
   ASSERT_EQ(0, ctx.wait());
 }
index 8414f8ce604ab15d43afce1b574157f426028ef8..23d4db6996ddd81c6e37bbb047f0f1ecd2d469a2 100644 (file)
@@ -45,7 +45,7 @@ public:
       librbd::MockTestImageCtx *src_image_ctx,
       librbd::MockTestImageCtx *dst_image_ctx,
       librados::snap_t snap_id_start, librados::snap_t snap_id_end,
-      const librbd::deep_copy::ObjectNumber &object_number,
+      bool flatten, const librbd::deep_copy::ObjectNumber &object_number,
       ContextWQ *work_queue, SnapSeqs *snap_seqs, ProgressContext *prog_ctx,
       Context *on_finish) {
     assert(s_instance != nullptr);
index f7ececbafc4fedd4db4db329e0c07733385ba9e3..68588c2ac8f52eacd67f1745a3394c0abf8d269c 100644 (file)
@@ -245,7 +245,7 @@ void ImageSync<I>::send_copy_image() {
   m_image_copy_prog_ctx = new ImageCopyProgressContext(this);
   m_image_copy_request = librbd::DeepCopyRequest<I>::create(
       m_remote_image_ctx, m_local_image_ctx, snap_id_start, snap_id_end,
-      object_number, m_work_queue, &m_client_meta->snap_seqs,
+      false, object_number, m_work_queue, &m_client_meta->snap_seqs,
       m_image_copy_prog_ctx, ctx);
   m_image_copy_request->get();
   m_lock.Unlock();