]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rbd-mirror: copy snapshot parent image settings
authorJason Dillaman <dillaman@redhat.com>
Thu, 26 May 2016 12:22:16 +0000 (08:22 -0400)
committerJason Dillaman <dillaman@redhat.com>
Tue, 31 May 2016 20:39:42 +0000 (16:39 -0400)
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
12 files changed:
src/test/rbd_mirror/image_replayer/test_mock_BootstrapRequest.cc
src/test/rbd_mirror/image_sync/test_mock_SnapshotCopyRequest.cc
src/test/rbd_mirror/image_sync/test_mock_SnapshotCreateRequest.cc
src/test/rbd_mirror/test_ImageSync.cc
src/test/rbd_mirror/test_mock_ImageSync.cc
src/tools/rbd_mirror/ImageSync.cc
src/tools/rbd_mirror/ImageSync.h
src/tools/rbd_mirror/image_replayer/BootstrapRequest.cc
src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.cc
src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.h
src/tools/rbd_mirror/image_sync/SnapshotCreateRequest.cc
src/tools/rbd_mirror/image_sync/SnapshotCreateRequest.h

index 5712e60e3d6c742f26e86f026ab780eb2d71c148..79b7eff134967712f8c923db9ab734ef2b512ccc 100644 (file)
@@ -47,7 +47,7 @@ struct ImageSync<librbd::MockTestImageCtx> {
                            const std::string &mirror_uuid,
                            ::journal::MockJournaler *journaler,
                            librbd::journal::MirrorPeerClientMeta *client_meta,
-                           Context *on_finish,
+                           ContextWQ *work_queue, Context *on_finish,
                            ProgressContext *progress_ctx = nullptr) {
     assert(s_instance != nullptr);
     return s_instance;
index b3e4a120ab12bf7458c8b37b73bcc449e735c788..35252f9177e0b2dc0719a4e743feaffd98340093 100644 (file)
@@ -34,7 +34,10 @@ struct SnapshotCreateRequest<librbd::MockImageCtx> {
   static SnapshotCreateRequest* s_instance;
   static SnapshotCreateRequest* create(librbd::MockImageCtx* image_ctx,
                                        const std::string &snap_name,
-                                       uint64_t size, Context *on_finish) {
+                                       uint64_t size,
+                                       const librbd::parent_spec &parent_spec,
+                                       uint64_t parent_overlap,
+                                       Context *on_finish) {
     assert(s_instance != nullptr);
     s_instance->on_finish = on_finish;
     return s_instance;
@@ -157,7 +160,7 @@ public:
     return new MockSnapshotCopyRequest(&mock_local_image_ctx,
                                        &mock_remote_image_ctx, &m_snap_map,
                                        &mock_journaler, &m_client_meta,
-                                       on_finish);
+                                       m_threads->work_queue, on_finish);
   }
 
   int create_snap(librbd::ImageCtx *image_ctx, const std::string &snap_name,
index dd8305de02499458321b4e373f9d21cfe58e9f96..8cf6217bf75bc49b52c5646a01be77f7bc501a57 100644 (file)
@@ -54,6 +54,18 @@ public:
                   .WillOnce(Return(r));
   }
 
+  void expect_remove_parent(librbd::MockImageCtx &mock_image_ctx, int r) {
+    EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
+                exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("remove_parent"), _, _, _))
+                  .WillOnce(Return(r));
+  }
+
+  void expect_set_parent(librbd::MockImageCtx &mock_image_ctx, int r) {
+    EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
+                exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("set_parent"), _, _, _))
+                  .WillOnce(Return(r));
+  }
+
   void expect_snap_create(librbd::MockImageCtx &mock_image_ctx,
                           const std::string &snap_name, uint64_t snap_id, int r) {
     EXPECT_CALL(*mock_image_ctx.operations, execute_snap_create(StrEq(snap_name), _, 0, true))
@@ -81,9 +93,12 @@ public:
 
   MockSnapshotCreateRequest *create_request(librbd::MockImageCtx &mock_local_image_ctx,
                                             const std::string &snap_name,
-                                            uint64_t size, Context *on_finish) {
+                                            uint64_t size,
+                                            const librbd::parent_spec &spec,
+                                            uint64_t parent_overlap,
+                                            Context *on_finish) {
     return new MockSnapshotCreateRequest(&mock_local_image_ctx, snap_name, size,
-                                         on_finish);
+                                         spec, parent_overlap, on_finish);
   }
 
   librbd::ImageCtx *m_local_image_ctx;
@@ -99,7 +114,7 @@ TEST_F(TestMockImageSyncSnapshotCreateRequest, Resize) {
 
   C_SaferCond ctx;
   MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx,
-                                                      "snap1", 123,
+                                                      "snap1", 123, {}, 0,
                                                       &ctx);
   request->send();
   ASSERT_EQ(0, ctx.wait());
@@ -113,16 +128,71 @@ TEST_F(TestMockImageSyncSnapshotCreateRequest, ResizeError) {
 
   C_SaferCond ctx;
   MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx,
-                                                      "snap1", 123,
+                                                      "snap1", 123, {}, 0,
                                                       &ctx);
   request->send();
   ASSERT_EQ(-EINVAL, ctx.wait());
 }
 
-TEST_F(TestMockImageSyncSnapshotCreateRequest, SnapCreate) {
+TEST_F(TestMockImageSyncSnapshotCreateRequest, RemoveParent) {
+  librbd::MockImageCtx mock_local_image_ctx(*m_local_image_ctx);
+  mock_local_image_ctx.parent_md.spec.pool_id = 213;
+
+  InSequence seq;
+  expect_remove_parent(mock_local_image_ctx, 0);
+  expect_snap_create(mock_local_image_ctx, "snap1", 10, 0);
+  expect_test_features(mock_local_image_ctx, RBD_FEATURE_OBJECT_MAP, false);
+
+  C_SaferCond ctx;
+  MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx,
+                                                      "snap1",
+                                                      m_local_image_ctx->size,
+                                                      {}, 0, &ctx);
+  request->send();
+  ASSERT_EQ(0, ctx.wait());
+}
+
+TEST_F(TestMockImageSyncSnapshotCreateRequest, RemoveParentError) {
+  librbd::MockImageCtx mock_local_image_ctx(*m_local_image_ctx);
+  mock_local_image_ctx.parent_md.spec.pool_id = 213;
+
+  InSequence seq;
+  expect_remove_parent(mock_local_image_ctx, -EINVAL);
+
+  C_SaferCond ctx;
+  MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx,
+                                                      "snap1",
+                                                      m_local_image_ctx->size,
+                                                      {}, 0, &ctx);
+  request->send();
+  ASSERT_EQ(-EINVAL, ctx.wait());
+}
+
+TEST_F(TestMockImageSyncSnapshotCreateRequest, RemoveSetParent) {
+  librbd::MockImageCtx mock_local_image_ctx(*m_local_image_ctx);
+  mock_local_image_ctx.parent_md.spec.pool_id = 213;
+
+  InSequence seq;
+  expect_remove_parent(mock_local_image_ctx, 0);
+  expect_set_parent(mock_local_image_ctx, 0);
+  expect_snap_create(mock_local_image_ctx, "snap1", 10, 0);
+  expect_test_features(mock_local_image_ctx, RBD_FEATURE_OBJECT_MAP, false);
+
+  C_SaferCond ctx;
+  MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx,
+                                                      "snap1",
+                                                      m_local_image_ctx->size,
+                                                      {123, "test", 0}, 0,
+                                                      &ctx);
+  request->send();
+  ASSERT_EQ(0, ctx.wait());
+}
+
+TEST_F(TestMockImageSyncSnapshotCreateRequest, SetParentSpec) {
   librbd::MockImageCtx mock_local_image_ctx(*m_local_image_ctx);
 
   InSequence seq;
+  expect_set_parent(mock_local_image_ctx, 0);
   expect_snap_create(mock_local_image_ctx, "snap1", 10, 0);
   expect_test_features(mock_local_image_ctx, RBD_FEATURE_OBJECT_MAP, false);
 
@@ -130,11 +200,63 @@ TEST_F(TestMockImageSyncSnapshotCreateRequest, SnapCreate) {
   MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx,
                                                       "snap1",
                                                       m_local_image_ctx->size,
+                                                      {123, "test", 0}, 0,
                                                       &ctx);
   request->send();
   ASSERT_EQ(0, ctx.wait());
 }
 
+TEST_F(TestMockImageSyncSnapshotCreateRequest, SetParentOverlap) {
+  librbd::MockImageCtx mock_local_image_ctx(*m_local_image_ctx);
+  mock_local_image_ctx.parent_md.spec = {123, "test", 0};
+
+  InSequence seq;
+  expect_set_parent(mock_local_image_ctx, 0);
+  expect_snap_create(mock_local_image_ctx, "snap1", 10, 0);
+  expect_test_features(mock_local_image_ctx, RBD_FEATURE_OBJECT_MAP, false);
+
+  C_SaferCond ctx;
+  MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx,
+                                                      "snap1",
+                                                      m_local_image_ctx->size,
+                                                      mock_local_image_ctx.parent_md.spec,
+                                                      123, &ctx);
+  request->send();
+  ASSERT_EQ(0, ctx.wait());
+}
+
+TEST_F(TestMockImageSyncSnapshotCreateRequest, SetParentError) {
+  librbd::MockImageCtx mock_local_image_ctx(*m_local_image_ctx);
+
+  InSequence seq;
+  expect_set_parent(mock_local_image_ctx, -ESTALE);
+
+  C_SaferCond ctx;
+  MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx,
+                                                      "snap1",
+                                                      m_local_image_ctx->size,
+                                                      {123, "test", 0}, 0,
+                                                      &ctx);
+  request->send();
+  ASSERT_EQ(-ESTALE, ctx.wait());
+}
+
+TEST_F(TestMockImageSyncSnapshotCreateRequest, SnapCreate) {
+  librbd::MockImageCtx mock_local_image_ctx(*m_local_image_ctx);
+
+  InSequence seq;
+  expect_snap_create(mock_local_image_ctx, "snap1", 10, 0);
+  expect_test_features(mock_local_image_ctx, RBD_FEATURE_OBJECT_MAP, false);
+
+  C_SaferCond ctx;
+  MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx,
+                                                      "snap1",
+                                                      m_local_image_ctx->size,
+                                                      {}, 0, &ctx);
+  request->send();
+  ASSERT_EQ(0, ctx.wait());
+}
+
 TEST_F(TestMockImageSyncSnapshotCreateRequest, SnapCreateError) {
   librbd::MockImageCtx mock_local_image_ctx(*m_local_image_ctx);
 
@@ -145,7 +267,7 @@ TEST_F(TestMockImageSyncSnapshotCreateRequest, SnapCreateError) {
   MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx,
                                                       "snap1",
                                                       m_local_image_ctx->size,
-                                                      &ctx);
+                                                      {}, 0, &ctx);
   request->send();
   ASSERT_EQ(-EINVAL, ctx.wait());
 }
@@ -162,7 +284,7 @@ TEST_F(TestMockImageSyncSnapshotCreateRequest, ResizeObjectMap) {
   MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx,
                                                       "snap1",
                                                       m_local_image_ctx->size,
-                                                      &ctx);
+                                                      {}, 0, &ctx);
   request->send();
   ASSERT_EQ(0, ctx.wait());
 }
@@ -179,7 +301,7 @@ TEST_F(TestMockImageSyncSnapshotCreateRequest, ResizeObjectMapError) {
   MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx,
                                                       "snap1",
                                                       m_local_image_ctx->size,
-                                                      &ctx);
+                                                      {}, 0, &ctx);
   request->send();
   ASSERT_EQ(-EINVAL, ctx.wait());
 }
index 5b80f970d888333c5eb5a6396764a0f5ec57c96a..db6e26f544d88c6cb810b4d7b7bda08e6a79eb4d 100644 (file)
@@ -88,7 +88,7 @@ public:
     return new ImageSync<>(m_local_image_ctx, m_remote_image_ctx,
                            m_threads->timer, &m_threads->timer_lock,
                            "mirror-uuid", m_remote_journaler, &m_client_meta,
-                           ctx);
+                           m_threads->work_queue, ctx);
   }
 
   librbd::ImageCtx *m_remote_image_ctx;
index f3c94bac2260e0fd39cba054161e5c631c90f0e9..38d2cb00e10dc74e50b88d17bb999c06a97191a3 100644 (file)
@@ -73,6 +73,7 @@ public:
                                      SnapshotCopyRequest<librbd::ImageCtx>::SnapMap *snap_map,
                                      journal::MockJournaler *journaler,
                                      librbd::journal::MirrorPeerClientMeta *client_meta,
+                                     ContextWQ *work_queue,
                                      Context *on_finish) {
     assert(s_instance != nullptr);
     s_instance->on_finish = on_finish;
@@ -238,7 +239,7 @@ public:
     return new MockImageSync(&mock_local_image_ctx, &mock_remote_image_ctx,
                              m_threads->timer, &m_threads->timer_lock,
                              "mirror-uuid", &mock_journaler, &m_client_meta,
-                             ctx);
+                             m_threads->work_queue, ctx);
   }
 
   librbd::ImageCtx *m_remote_image_ctx;
index 24202f496f1d663ccc4487e8a4df50641be520f3..ff2c7bb1561a6f1a1a01b51d817f34815c2956f7 100644 (file)
@@ -30,11 +30,13 @@ template <typename I>
 ImageSync<I>::ImageSync(I *local_image_ctx, I *remote_image_ctx,
                         SafeTimer *timer, Mutex *timer_lock,
                         const std::string &mirror_uuid, Journaler *journaler,
-                        MirrorPeerClientMeta *client_meta, Context *on_finish,
+                        MirrorPeerClientMeta *client_meta,
+                        ContextWQ *work_queue, Context *on_finish,
                        ProgressContext *progress_ctx)
   : m_local_image_ctx(local_image_ctx), m_remote_image_ctx(remote_image_ctx),
     m_timer(timer), m_timer_lock(timer_lock), m_mirror_uuid(mirror_uuid),
-    m_journaler(journaler), m_client_meta(client_meta), m_on_finish(on_finish),
+    m_journaler(journaler), m_client_meta(client_meta),
+    m_work_queue(work_queue), m_on_finish(on_finish),
     m_progress_ctx(progress_ctx),
     m_lock(unique_lock_name("ImageSync::m_lock", this)) {
 }
@@ -138,7 +140,7 @@ void ImageSync<I>::send_copy_snapshots() {
     ImageSync<I>, &ImageSync<I>::handle_copy_snapshots>(this);
   SnapshotCopyRequest<I> *request = SnapshotCopyRequest<I>::create(
     m_local_image_ctx, m_remote_image_ctx, &m_snap_map, m_journaler,
-    m_client_meta, ctx);
+    m_client_meta, m_work_queue, ctx);
   request->send();
 }
 
index 95809ab0fb95ebda63932480103ca6978ddd05eb..abe0f4648ddfa275360bb88f93a185ec942dcd28 100644 (file)
@@ -12,6 +12,7 @@
 #include <vector>
 
 class Context;
+class ContextWQ;
 class Mutex;
 class SafeTimer;
 namespace journal { class Journaler; }
@@ -36,17 +37,18 @@ public:
                            Mutex *timer_lock, const std::string &mirror_uuid,
                            Journaler *journaler,
                            MirrorPeerClientMeta *client_meta,
-                           Context *on_finish,
+                           ContextWQ *work_queue, Context *on_finish,
                           ProgressContext *progress_ctx = nullptr) {
     return new ImageSync(local_image_ctx, remote_image_ctx, timer, timer_lock,
-                         mirror_uuid, journaler, client_meta, on_finish,
-                        progress_ctx);
+                         mirror_uuid, journaler, client_meta, work_queue,
+                         on_finish, progress_ctx);
   }
 
   ImageSync(ImageCtxT *local_image_ctx, ImageCtxT *remote_image_ctx,
             SafeTimer *timer, Mutex *timer_lock, const std::string &mirror_uuid,
             Journaler *journaler, MirrorPeerClientMeta *client_meta,
-            Context *on_finish, ProgressContext *progress_ctx = nullptr);
+            ContextWQ *work_queue, Context *on_finish,
+            ProgressContext *progress_ctx = nullptr);
 
   void start();
   void cancel();
@@ -94,6 +96,7 @@ private:
   std::string m_mirror_uuid;
   Journaler *m_journaler;
   MirrorPeerClientMeta *m_client_meta;
+  ContextWQ *m_work_queue;
   Context *m_on_finish;
   ProgressContext *m_progress_ctx;
 
index e241aee19e944219ee504f31518b37dcaa713157..b90b60856f35284bf5642ba50fe4e7f1de1bacab 100644 (file)
@@ -515,7 +515,7 @@ void BootstrapRequest<I>::image_sync() {
                                                m_remote_image_ctx, m_timer,
                                                m_timer_lock,
                                                m_local_mirror_uuid, m_journaler,
-                                               m_client_meta, ctx,
+                                               m_client_meta, m_work_queue, ctx,
                                               m_progress_ctx);
   request->start();
 }
index 016e4b4e4bbbb76de6d1c949471d8747d966cb9f..bee21c019e665250191e2144dcab23b3543da56e 100644 (file)
@@ -4,6 +4,7 @@
 #include "SnapshotCopyRequest.h"
 #include "SnapshotCreateRequest.h"
 #include "common/errno.h"
+#include "common/WorkQueue.h"
 #include "journal/Journaler.h"
 #include "librbd/Operations.h"
 #include "librbd/Utils.h"
@@ -42,10 +43,12 @@ SnapshotCopyRequest<I>::SnapshotCopyRequest(I *local_image_ctx,
                                             SnapMap *snap_map,
                                             Journaler *journaler,
                                             librbd::journal::MirrorPeerClientMeta *meta,
+                                            ContextWQ *work_queue,
                                             Context *on_finish)
   : m_local_image_ctx(local_image_ctx), m_remote_image_ctx(remote_image_ctx),
     m_snap_map(snap_map), m_journaler(journaler), m_client_meta(meta),
-    m_on_finish(on_finish), m_snap_seqs(meta->snap_seqs) {
+    m_work_queue(work_queue), m_on_finish(on_finish),
+    m_snap_seqs(meta->snap_seqs) {
   m_snap_map->clear();
 
   // snap ids ordered from oldest to newest
@@ -57,6 +60,21 @@ SnapshotCopyRequest<I>::SnapshotCopyRequest(I *local_image_ctx,
 
 template <typename I>
 void SnapshotCopyRequest<I>::send() {
+  librbd::parent_spec remote_parent_spec;
+  int r = validate_parent(m_remote_image_ctx, &remote_parent_spec);
+  if (r < 0) {
+    derr << ": remote image parent spec mismatch" << dendl;
+    error(r);
+    return;
+  }
+
+  r = validate_parent(m_local_image_ctx, &m_local_parent_spec);
+  if (r < 0) {
+    derr << ": local image parent spec mismatch" << dendl;
+    error(r);
+    return;
+  }
+
   send_snap_unprotect();
 }
 
@@ -64,21 +82,6 @@ template <typename I>
 void SnapshotCopyRequest<I>::send_snap_unprotect() {
   CephContext *cct = m_local_image_ctx->cct;
 
-  // TODO: issue #14937 needs to add support for cloned images
-  m_remote_image_ctx->snap_lock.get_read();
-  if (m_remote_image_ctx->parent_md.spec.pool_id != -1 ||
-      std::find_if(m_remote_image_ctx->snap_info.begin(),
-                   m_remote_image_ctx->snap_info.end(),
-                   [](const std::pair<librados::snap_t, librbd::SnapInfo>& pair) {
-          return pair.second.parent.spec.pool_id != -1;
-        }) != m_remote_image_ctx->snap_info.end()) {
-    lderr(cct) << ": cloned images are not currently supported" << dendl;
-    m_remote_image_ctx->snap_lock.put_read();
-    finish(-EINVAL);
-    return;
-  }
-  m_remote_image_ctx->snap_lock.put_read();
-
   SnapIdSet::iterator snap_id_it = m_local_snap_ids.begin();
   if (m_prev_snap_id != CEPH_NOSNAP) {
     snap_id_it = m_local_snap_ids.upper_bound(m_prev_snap_id);
@@ -271,19 +274,32 @@ void SnapshotCopyRequest<I>::send_snap_create() {
     finish(-ENOENT);
     return;
   }
+
   uint64_t size = snap_info_it->second.size;
+  librbd::parent_spec parent_spec;
+  uint64_t parent_overlap = 0;
+  if (snap_info_it->second.parent.spec.pool_id != -1) {
+    parent_spec = m_local_parent_spec;
+    parent_overlap = snap_info_it->second.parent.overlap;
+  }
   m_remote_image_ctx->snap_lock.put_read();
 
+
   ldout(cct, 20) << ": "
                  << "snap_name=" << m_snap_name << ", "
                  << "snap_id=" << m_prev_snap_id << ", "
-                 << "size=" << size << dendl;
+                 << "size=" << size << ", "
+                 << "parent_info=["
+                 << "pool_id=" << parent_spec.pool_id << ", "
+                 << "image_id=" << parent_spec.image_id << ", "
+                 << "snap_id=" << parent_spec.snap_id << ", "
+                 << "overlap=" << parent_overlap << "]" << dendl;
 
   Context *ctx = create_context_callback<
     SnapshotCopyRequest<I>, &SnapshotCopyRequest<I>::handle_snap_create>(
       this);
   SnapshotCreateRequest<I> *req = SnapshotCreateRequest<I>::create(
-    m_local_image_ctx, m_snap_name, size, ctx);
+    m_local_image_ctx, m_snap_name, size, parent_spec, parent_overlap, ctx);
   req->send();
 }
 
@@ -437,6 +453,14 @@ void SnapshotCopyRequest<I>::handle_update_client(int r) {
   finish(0);
 }
 
+template <typename I>
+void SnapshotCopyRequest<I>::error(int r) {
+  dout(20) << ": r=" << r << dendl;
+
+  m_work_queue->queue(create_context_callback<
+    SnapshotCopyRequest<I>, &SnapshotCopyRequest<I>::finish>(this), r);
+}
+
 template <typename I>
 void SnapshotCopyRequest<I>::finish(int r) {
   CephContext *cct = m_local_image_ctx->cct;
@@ -460,6 +484,30 @@ void SnapshotCopyRequest<I>::compute_snap_map() {
   }
 }
 
+template <typename I>
+int SnapshotCopyRequest<I>::validate_parent(I *image_ctx,
+                                            librbd::parent_spec *spec) {
+  RWLock::RLocker owner_locker(image_ctx->owner_lock);
+  RWLock::RLocker snap_locker(image_ctx->snap_lock);
+
+  // ensure remote image's parent specs are still consistent
+  *spec = image_ctx->parent_md.spec;
+  for (auto &snap_info_pair : image_ctx->snap_info) {
+    auto &parent_spec = snap_info_pair.second.parent.spec;
+    if (parent_spec.pool_id == -1) {
+      continue;
+    } else if (spec->pool_id == -1) {
+      *spec = parent_spec;
+      continue;
+    }
+
+    if (*spec != parent_spec) {
+      return -EINVAL;
+    }
+  }
+  return 0;
+}
+
 } // namespace image_sync
 } // namespace mirror
 } // namespace rbd
index 87f766f1f2ccb823f8b8ee02f06ec94616e831f8..02b5ce74a39de474252da065de87fa0fc72e861c 100644 (file)
@@ -8,6 +8,7 @@
 #include "include/rados/librados.hpp"
 #include "common/snap_types.h"
 #include "librbd/ImageCtx.h"
+#include "librbd/parent_types.h"
 #include "librbd/journal/TypeTraits.h"
 #include <map>
 #include <set>
@@ -15,6 +16,7 @@
 #include <tuple>
 
 class Context;
+class ContextWQ;
 namespace journal { class Journaler; }
 namespace librbd { namespace journal { struct MirrorPeerClientMeta; } }
 
@@ -35,15 +37,17 @@ public:
                                      ImageCtxT *remote_image_ctx,
                                      SnapMap *snap_map, Journaler *journaler,
                                      librbd::journal::MirrorPeerClientMeta *client_meta,
+                                     ContextWQ *work_queue,
                                      Context *on_finish) {
     return new SnapshotCopyRequest(local_image_ctx, remote_image_ctx,
-                                   snap_map, journaler, client_meta, on_finish);
+                                   snap_map, journaler, client_meta, work_queue,
+                                   on_finish);
   }
 
   SnapshotCopyRequest(ImageCtxT *local_image_ctx, ImageCtxT *remote_image_ctx,
                       SnapMap *snap_map, Journaler *journaler,
                       librbd::journal::MirrorPeerClientMeta *client_meta,
-                      Context *on_finish);
+                      ContextWQ *work_queue, Context *on_finish);
 
   void send();
 
@@ -90,6 +94,7 @@ private:
   SnapMap *m_snap_map;
   Journaler *m_journaler;
   librbd::journal::MirrorPeerClientMeta *m_client_meta;
+  ContextWQ *m_work_queue;
   Context *m_on_finish;
 
   SnapIdSet m_local_snap_ids;
@@ -99,6 +104,8 @@ private:
 
   std::string m_snap_name;
 
+  librbd::parent_spec m_local_parent_spec;
+
   void send_snap_unprotect();
   void handle_snap_unprotect(int r);
 
@@ -114,10 +121,13 @@ private:
   void send_update_client();
   void handle_update_client(int r);
 
+  void error(int r);
   void finish(int r);
 
   void compute_snap_map();
 
+  int validate_parent(ImageCtxT *image_ctx, librbd::parent_spec *spec);
+
 };
 
 } // namespace image_sync
index 60d03ffa1eb91ae167a2aeb4dd03fe8e98554cbd..e15ca958e48281df0048596454e98e69d72f83ab 100644 (file)
@@ -25,8 +25,11 @@ template <typename I>
 SnapshotCreateRequest<I>::SnapshotCreateRequest(I *local_image_ctx,
                                                 const std::string &snap_name,
                                                 uint64_t size,
+                                                const librbd::parent_spec &spec,
+                                                uint64_t parent_overlap,
                                                 Context *on_finish)
   : m_local_image_ctx(local_image_ctx), m_snap_name(snap_name), m_size(size),
+    m_parent_spec(spec), m_parent_overlap(parent_overlap),
     m_on_finish(on_finish) {
 }
 
@@ -87,15 +90,28 @@ void SnapshotCreateRequest<I>::handle_set_size(int r) {
 
 template <typename I>
 void SnapshotCreateRequest<I>::send_remove_parent() {
-  // TODO: issue #14937 needs to add support for cloned images
-  if (true) {
-    send_snap_create();
+  m_local_image_ctx->parent_lock.get_read();
+  if (m_local_image_ctx->parent_md.spec.pool_id == -1 ||
+      m_local_image_ctx->parent_md.spec == m_parent_spec) {
+    m_local_image_ctx->parent_lock.put_read();
+    send_set_parent();
     return;
   }
+  m_local_image_ctx->parent_lock.put_read();
 
   CephContext *cct = m_local_image_ctx->cct;
   ldout(cct, 20) << dendl;
 
+  librados::ObjectWriteOperation op;
+  librbd::cls_client::remove_parent(&op);
+
+  librados::AioCompletion *comp = create_rados_safe_callback<
+    SnapshotCreateRequest<I>,
+    &SnapshotCreateRequest<I>::handle_remove_parent>(this);
+  int r = m_local_image_ctx->md_ctx.aio_operate(m_local_image_ctx->header_oid,
+                                                comp, &op);
+  assert(r == 0);
+  comp->release();
 }
 
 template <typename I>
@@ -103,15 +119,47 @@ void SnapshotCreateRequest<I>::handle_remove_parent(int r) {
   CephContext *cct = m_local_image_ctx->cct;
   ldout(cct, 20) << ": r=" << r << dendl;
 
-  // TODO: issue #14937 needs to add support for cloned images
+  if (r < 0) {
+    lderr(cct) << ": failed to remove parent '" << m_snap_name << "': "
+               << cpp_strerror(r) << dendl;
+    finish(r);
+    return;
+  }
+
+  {
+    // adjust in-memory parent now that it's updated on disk
+    RWLock::WLocker parent_locker(m_local_image_ctx->parent_lock);
+    m_local_image_ctx->parent_md.spec = {};
+    m_local_image_ctx->parent_md.overlap = 0;
+  }
+
+  send_set_parent();
 }
 
 template <typename I>
 void SnapshotCreateRequest<I>::send_set_parent() {
+  m_local_image_ctx->parent_lock.get_read();
+  if (m_local_image_ctx->parent_md.spec == m_parent_spec &&
+      m_local_image_ctx->parent_md.overlap == m_parent_overlap) {
+    m_local_image_ctx->parent_lock.put_read();
+    send_snap_create();
+    return;
+  }
+  m_local_image_ctx->parent_lock.put_read();
+
   CephContext *cct = m_local_image_ctx->cct;
   ldout(cct, 20) << dendl;
 
-  // TODO: issue #14937 needs to add support for cloned images
+  librados::ObjectWriteOperation op;
+  librbd::cls_client::set_parent(&op, m_parent_spec, m_parent_overlap);
+
+  librados::AioCompletion *comp = create_rados_safe_callback<
+    SnapshotCreateRequest<I>,
+    &SnapshotCreateRequest<I>::handle_set_parent>(this);
+  int r = m_local_image_ctx->md_ctx.aio_operate(m_local_image_ctx->header_oid,
+                                                comp, &op);
+  assert(r == 0);
+  comp->release();
 }
 
 template <typename I>
@@ -119,7 +167,21 @@ void SnapshotCreateRequest<I>::handle_set_parent(int r) {
   CephContext *cct = m_local_image_ctx->cct;
   ldout(cct, 20) << ": r=" << r << dendl;
 
-  // TODO: issue #14937 needs to add support for cloned images
+  if (r < 0) {
+    lderr(cct) << ": failed to set parent '" << m_snap_name << "': "
+               << cpp_strerror(r) << dendl;
+    finish(r);
+    return;
+  }
+
+  {
+    // adjust in-memory parent now that it's updated on disk
+    RWLock::WLocker parent_locker(m_local_image_ctx->parent_lock);
+    m_local_image_ctx->parent_md.spec = m_parent_spec;
+    m_local_image_ctx->parent_md.overlap = m_parent_overlap;
+  }
+
+  send_snap_create();
 }
 
 template <typename I>
index 897c7b9d8ac5834b13d7cd8aef7437f252a96d23..c8c772f4acaf173a4f6bff917aa8d09ce713526e 100644 (file)
@@ -8,6 +8,7 @@
 #include "include/rados/librados.hpp"
 #include "common/snap_types.h"
 #include "librbd/ImageCtx.h"
+#include "librbd/parent_types.h"
 #include "librbd/journal/TypeTraits.h"
 #include <map>
 #include <set>
@@ -25,14 +26,18 @@ class SnapshotCreateRequest {
 public:
   static SnapshotCreateRequest* create(ImageCtxT *local_image_ctx,
                                        const std::string &snap_name,
-                                       uint64_t size, Context *on_finish) {
+                                       uint64_t size,
+                                       const librbd::parent_spec &parent_spec,
+                                       uint64_t parent_overlap,
+                                       Context *on_finish) {
     return new SnapshotCreateRequest(local_image_ctx, snap_name, size,
-                                     on_finish);
+                                     parent_spec, parent_overlap, on_finish);
   }
 
   SnapshotCreateRequest(ImageCtxT *local_image_ctx,
                         const std::string &snap_name, uint64_t size,
-                        Context *on_finish);
+                        const librbd::parent_spec &parent_spec,
+                        uint64_t parent_overlap, Context *on_finish);
 
   void send();
 
@@ -66,6 +71,8 @@ private:
   ImageCtxT *m_local_image_ctx;
   std::string m_snap_name;
   uint64_t m_size;
+  librbd::parent_spec m_parent_spec;
+  uint64_t m_parent_overlap;
   Context *m_on_finish;
 
   void send_set_size();