]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: async API for creating mirror snapshots
authorMykola Golub <mgolub@suse.com>
Mon, 12 Oct 2020 09:25:46 +0000 (10:25 +0100)
committerMykola Golub <mgolub@suse.com>
Thu, 29 Oct 2020 15:14:38 +0000 (15:14 +0000)
Signed-off-by: Mykola Golub <mgolub@suse.com>
src/include/rbd/librbd.h
src/include/rbd/librbd.hpp
src/librbd/api/Mirror.cc
src/librbd/api/Mirror.h
src/librbd/librbd.cc
src/test/librbd/test_mirroring.cc

index 810b03693365885972094c955fe0d8d66dfc53e3..85beed1987ebdf67cdb36260427d5b771c442a58 100644 (file)
@@ -1265,6 +1265,11 @@ CEPH_RBD_API int rbd_aio_mirror_image_get_status(
     size_t status_size, rbd_completion_t c)
   CEPH_RBD_DEPRECATED;
 
+CEPH_RBD_API int rbd_aio_mirror_image_create_snapshot(rbd_image_t image,
+                                                      uint32_t flags,
+                                                      uint64_t *snap_id,
+                                                      rbd_completion_t c);
+
 // RBD groups support functions
 CEPH_RBD_API int rbd_group_create(rados_ioctx_t p, const char *name);
 CEPH_RBD_API int rbd_group_remove(rados_ioctx_t p, const char *name);
index ec96f72b8fab83b2de07ac0b359b357d410bc838..8616367e098b57ae8f7d2e4dde98571e02e59abc 100644 (file)
@@ -784,6 +784,8 @@ public:
       mirror_image_status_t *mirror_image_status, size_t status_size,
       RBD::AioCompletion *c)
     CEPH_RBD_DEPRECATED;
+  int aio_mirror_image_create_snapshot(uint32_t flags, uint64_t *snap_id,
+      RBD::AioCompletion *c);
 
   int update_watch(UpdateWatchCtx *ctx, uint64_t *handle);
   int update_unwatch(uint64_t handle);
index 28bf2673d0f756e7a2815dfbe1580a454ef85736..25f22f0db9b845eff52d1c4ec752396cfdf7c08b 100644 (file)
@@ -354,6 +354,43 @@ struct C_ImageGetGlobalStatus : public C_ImageGetInfo {
   }
 };
 
+template <typename I>
+struct C_ImageSnapshotCreate : public Context {
+  I *ictx;
+  uint64_t snap_create_flags;
+  uint64_t *snap_id;
+  Context *on_finish;
+
+  cls::rbd::MirrorImage mirror_image;
+  mirror::PromotionState promotion_state;
+  std::string primary_mirror_uuid;
+
+  C_ImageSnapshotCreate(I *ictx, uint64_t snap_create_flags, uint64_t *snap_id,
+                        Context *on_finish)
+    : ictx(ictx), snap_create_flags(snap_create_flags), snap_id(snap_id),
+      on_finish(on_finish) {
+  }
+
+  void finish(int r) override {
+    if (r < 0 && r != -ENOENT) {
+      on_finish->complete(r);
+      return;
+    }
+
+    if (mirror_image.mode != cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT ||
+        mirror_image.state != cls::rbd::MIRROR_IMAGE_STATE_ENABLED) {
+      lderr(ictx->cct) << "snapshot based mirroring is not enabled" << dendl;
+      on_finish->complete(-EINVAL);
+      return;
+    }
+
+    auto req = mirror::snapshot::CreatePrimaryRequest<I>::create(
+      ictx, mirror_image.global_image_id, CEPH_NOSNAP, snap_create_flags, 0U,
+      snap_id, on_finish);
+    req->send();
+  }
+};
+
 } // anonymous namespace
 
 template <typename I>
@@ -1978,6 +2015,15 @@ int Mirror<I>::image_info_list(
 template <typename I>
 int Mirror<I>::image_snapshot_create(I *ictx, uint32_t flags,
                                      uint64_t *snap_id) {
+  C_SaferCond ctx;
+  Mirror<I>::image_snapshot_create(ictx, flags, snap_id, &ctx);
+
+  return ctx.wait();
+}
+
+template <typename I>
+void Mirror<I>::image_snapshot_create(I *ictx, uint32_t flags,
+                                      uint64_t *snap_id, Context *on_finish) {
   CephContext *cct = ictx->cct;
   ldout(cct, 20) << "ictx=" << ictx << dendl;
 
@@ -1985,36 +2031,32 @@ int Mirror<I>::image_snapshot_create(I *ictx, uint32_t flags,
   int r = util::snap_create_flags_api_to_internal(cct, flags,
                                                   &snap_create_flags);
   if (r < 0) {
-    return r;
+    on_finish->complete(r);
+    return;
   }
 
-  r = ictx->state->refresh_if_required();
-  if (r < 0) {
-    return r;
-  }
+  auto on_refresh = new LambdaContext(
+    [ictx, snap_create_flags, snap_id, on_finish](int r) {
+      if (r < 0) {
+        lderr(ictx->cct) << "refresh failed: " << cpp_strerror(r) << dendl;
+        on_finish->complete(r);
+        return;
+      }
 
-  cls::rbd::MirrorImage mirror_image;
-  r = cls_client::mirror_image_get(&ictx->md_ctx, ictx->id,
-                                   &mirror_image);
-  if (r == -ENOENT) {
-    return -EINVAL;
-  } else if (r < 0) {
-    lderr(cct) << "failed to retrieve mirror image" << dendl;
-    return r;
-  }
+      auto ctx = new C_ImageSnapshotCreate<I>(ictx, snap_create_flags, snap_id,
+                                              on_finish);
+      auto req = mirror::GetInfoRequest<I>::create(*ictx, &ctx->mirror_image,
+                                                   &ctx->promotion_state,
+                                                   &ctx->primary_mirror_uuid,
+                                                   ctx);
+      req->send();
+    });
 
-  if (mirror_image.mode != cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT ||
-      mirror_image.state != cls::rbd::MIRROR_IMAGE_STATE_ENABLED) {
-    lderr(cct) << "snapshot based mirroring is not enabled" << dendl;
-    return -EINVAL;
+  if (ictx->state->is_refresh_required()) {
+    ictx->state->refresh(on_refresh);
+  } else {
+    on_refresh->complete(0);
   }
-
-  C_SaferCond on_finish;
-  auto req = mirror::snapshot::CreatePrimaryRequest<I>::create(
-    ictx, mirror_image.global_image_id, CEPH_NOSNAP, snap_create_flags, 0U,
-    snap_id, &on_finish);
-  req->send();
-  return on_finish.wait();
 }
 
 } // namespace api
index 254c1f568f13b90d1efefea64415a5e07d385b6f..b3a552b13b7eee2f0495fce390e37f1816d59fde 100644 (file)
@@ -114,6 +114,8 @@ struct Mirror {
 
   static int image_snapshot_create(ImageCtxT *ictx, uint32_t flags,
                                    uint64_t *snap_id);
+  static void image_snapshot_create(ImageCtxT *ictx, uint32_t flags,
+                                    uint64_t *snap_id, Context *on_finish);
 };
 
 } // namespace api
index 1af6381f258f80928649505ad4e56ecb3f87f4ac..eda22c088043daf435c5370738e5cad8ecce2ba0 100644 (file)
@@ -3023,6 +3023,17 @@ namespace librbd {
 
 #pragma GCC diagnostic pop
 
+  int Image::aio_mirror_image_create_snapshot(uint32_t flags, uint64_t *snap_id,
+                                              RBD::AioCompletion *c) {
+    ImageCtx *ictx = (ImageCtx *)ctx;
+
+    librbd::api::Mirror<>::image_snapshot_create(
+        ictx, flags, snap_id, new C_AioCompletion(ictx,
+                                                  librbd::io::AIO_TYPE_GENERIC,
+                                                  get_aio_completion(c)));
+    return 0;
+  }
+
   int Image::update_watch(UpdateWatchCtx *wctx, uint64_t *handle) {
     ImageCtx *ictx = (ImageCtx *)ctx;
     tracepoint(librbd, update_watch_enter, ictx, wctx);
@@ -6579,6 +6590,20 @@ extern "C" int rbd_aio_mirror_image_get_status(
 
 #pragma GCC diagnostic pop
 
+extern "C" int rbd_aio_mirror_image_create_snapshot(rbd_image_t image,
+                                                    uint32_t flags,
+                                                    uint64_t *snap_id,
+                                                    rbd_completion_t c) {
+  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
+  librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
+
+  librbd::api::Mirror<>::image_snapshot_create(
+      ictx, flags, snap_id, new C_AioCompletion(ictx,
+                                                librbd::io::AIO_TYPE_GENERIC,
+                                                get_aio_completion(comp)));
+  return 0;
+}
+
 extern "C" int rbd_update_watch(rbd_image_t image, uint64_t *handle,
                                rbd_update_callback_t watch_cb, void *arg)
 {
index 840ac33b1195220eff86ffae8c487dff316116ab..75d18208cc702b95a03678dbdc5e2f28733fa525 100644 (file)
@@ -1470,3 +1470,66 @@ TEST_F(TestMirroring, SnapshotPromoteDemote)
   ASSERT_EQ(0, m_rbd.mirror_peer_site_remove(m_ioctx, peer_uuid));
   ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, RBD_MIRROR_MODE_DISABLED));
 }
+
+TEST_F(TestMirroring, AioSnapshotCreate)
+{
+  REQUIRE_FORMAT_V2();
+
+  std::list<std::string> image_names;
+  for (size_t idx = 0; idx < 10; ++idx) {
+    image_names.push_back(get_temp_image_name());
+  }
+
+  ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, RBD_MIRROR_MODE_IMAGE));
+  std::string peer_uuid;
+  ASSERT_EQ(0, m_rbd.mirror_peer_site_add(m_ioctx, &peer_uuid,
+                                          RBD_MIRROR_PEER_DIRECTION_RX_TX,
+                                          "cluster", "client"));
+  // create mirror images
+  uint64_t features;
+  ASSERT_TRUE(get_features(&features));
+  int order = 20;
+  std::list<librbd::Image> images;
+  for (auto &image_name : image_names) {
+    ASSERT_EQ(0, m_rbd.create2(m_ioctx, image_name.c_str(), 2048, features,
+                               &order));
+    images.emplace_back();
+    ASSERT_EQ(0, m_rbd.open(m_ioctx, images.back(), image_name.c_str()));
+    ASSERT_EQ(0, images.back().mirror_image_enable2(
+                RBD_MIRROR_IMAGE_MODE_SNAPSHOT));
+  }
+
+  // create snapshots
+  std::list<uint64_t> snap_ids;
+  std::list<librbd::RBD::AioCompletion *> aio_comps;
+  for (auto &image : images) {
+    snap_ids.emplace_back();
+    aio_comps.push_back(new librbd::RBD::AioCompletion(nullptr, nullptr));
+    ASSERT_EQ(0, image.aio_mirror_image_create_snapshot(0, &snap_ids.back(),
+                                                        aio_comps.back()));
+  }
+  for (auto aio_comp : aio_comps) {
+    ASSERT_EQ(0, aio_comp->wait_for_complete());
+    ASSERT_EQ(1, aio_comp->is_complete());
+    ASSERT_EQ(0, aio_comp->get_return_value());
+    aio_comp->release();
+  }
+  aio_comps.clear();
+
+  // verify
+  for (auto &image : images) {
+    vector<librbd::snap_info_t> snaps;
+    ASSERT_EQ(0, image.snap_list(snaps));
+    ASSERT_EQ(2U, snaps.size());
+    ASSERT_EQ(snaps[1].id, snap_ids.front());
+
+    std::string image_name;
+    ASSERT_EQ(0, image.get_name(&image_name));
+    ASSERT_EQ(0, image.close());
+    ASSERT_EQ(0, m_rbd.remove(m_ioctx, image_name.c_str()));
+    snap_ids.pop_front();
+  }
+
+  ASSERT_EQ(0, m_rbd.mirror_peer_site_remove(m_ioctx, peer_uuid));
+  ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, RBD_MIRROR_MODE_DISABLED));
+}