]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: add group snap rollback method
authorsongweibin <song.weibin@zte.com.cn>
Tue, 31 Jul 2018 08:53:24 +0000 (16:53 +0800)
committersongweibin <song.weibin@zte.com.cn>
Wed, 12 Sep 2018 15:42:14 +0000 (23:42 +0800)
Fixes: http://tracker.ceph.com/issues/23550
Signed-off-by: songweibin <song.weibin@zte.com.cn>
src/cls/rbd/cls_rbd_client.cc
src/cls/rbd/cls_rbd_client.h
src/include/rbd/librbd.h
src/include/rbd/librbd.hpp
src/librbd/api/Group.cc
src/librbd/api/Group.h
src/librbd/librbd.cc
src/test/librbd/test_Groups.cc
src/tracing/librbd.tp

index 5e6f3181d9d4fb29c8b37716af464b018d305d29..14123b92bdb997fd99707c2055886dfcdfd72723 100644 (file)
@@ -2381,7 +2381,7 @@ namespace librbd {
       op->exec("rbd", "mirror_image_map_remove", bl);
     }
 
-    // Consistency groups functions
+    // Groups functions
     int group_dir_list(librados::IoCtx *ioctx, const std::string &oid,
                        const std::string &start, uint64_t max_return,
                        map<string, string> *cgs)
@@ -2567,6 +2567,7 @@ namespace librbd {
 
       return 0;
     }
+
     int group_snap_list(librados::IoCtx *ioctx, const std::string &oid,
                        const cls::rbd::GroupSnapshot &start,
                        uint64_t max_return,
index c9c362bb53689328cbc25cb50d60478f5ab26f48..ad3050516bcca65c6c332890181d48a0c7a3a937 100644 (file)
@@ -505,7 +505,7 @@ namespace librbd {
     void mirror_image_map_remove(librados::ObjectWriteOperation *op,
                                  const std::string &global_image_id);
 
-    // Consistency groups functions
+    // Groups functions
     int group_dir_list(librados::IoCtx *ioctx, const std::string &oid,
                        const std::string &start, uint64_t max_return,
                        map<string, string> *groups);
index 85e9636f426564db35cac10fd3b9465c7142c12e..aaad6b811af9f5590a203a0dd3d0bf71c8468db5 100644 (file)
@@ -1038,6 +1038,14 @@ CEPH_RBD_API int rbd_group_snap_list(rados_ioctx_t group_p,
 CEPH_RBD_API int rbd_group_snap_list_cleanup(rbd_group_snap_info_t *snaps,
                                              size_t group_snap_info_size,
                                              size_t num_entries);
+CEPH_RBD_API int rbd_group_snap_rollback(rados_ioctx_t group_p,
+                                         const char *group_name,
+                                         const char *snap_name);
+CEPH_RBD_API int rbd_group_snap_rollback_with_progress(rados_ioctx_t group_p,
+                                                       const char *group_name,
+                                                       const char *snap_name,
+                                                       librbd_progress_fn_t cb,
+                                                       void *cbdata);
 
 CEPH_RBD_API int rbd_namespace_create(rados_ioctx_t io,
                                       const char *namespace_name);
index 38cc707a31f031aa19cd7c2c6fd6e0be8bc6c1f4..052ec111caf33e124a045c076fd9a268d73f1978 100644 (file)
@@ -267,6 +267,11 @@ public:
   int group_snap_list(IoCtx& group_ioctx, const char *group_name,
                       std::vector<group_snap_info_t> *snaps,
                       size_t group_snap_info_size);
+  int group_snap_rollback(IoCtx& io_ctx, const char *group_name,
+                          const char *snap_name);
+  int group_snap_rollback_with_progress(IoCtx& io_ctx, const char *group_name,
+                                        const char *snap_name,
+                                        ProgressContext& pctx);
 
   int namespace_create(IoCtx& ioctx, const char *namespace_name);
   int namespace_remove(IoCtx& ioctx, const char *namespace_name);
index c0540881b310b4b486ec04e7e79210a8102ab9a3..6dd971037daabfb7102c65e650c60903ac1cbc55 100644 (file)
@@ -313,6 +313,127 @@ finish:
   return ret_code;
 }
 
+int group_snap_rollback_by_record(librados::IoCtx& group_ioctx,
+                                  const cls::rbd::GroupSnapshot& group_snap,
+                                  const std::string& group_id,
+                                  const std::string& group_header_oid,
+                                  ProgressContext& pctx) {
+  CephContext *cct = (CephContext *)group_ioctx.cct();
+  librados::Rados rados(group_ioctx);
+  std::vector<C_SaferCond*> on_finishes;
+  int r, ret_code;
+
+  std::vector<librbd::ImageCtx*> ictxs;
+
+  cls::rbd::GroupSnapshotNamespace ne{group_ioctx.get_id(), group_id,
+                                      group_snap.id};
+
+  ldout(cct, 20) << "Rolling back snapshots" << dendl;
+  int snap_count = group_snap.snaps.size();
+
+  for (int i = 0; i < snap_count; ++i) {
+    librados::IoCtx image_io_ctx;
+    r = rados.ioctx_create2(group_snap.snaps[i].pool, image_io_ctx);
+    if (r < 0) {
+      ldout(cct, 1) << "Failed to create io context for image" << dendl;
+    }
+
+    librbd::ImageCtx* image_ctx = new ImageCtx("", group_snap.snaps[i].image_id,
+                                               nullptr, image_io_ctx, false);
+
+    C_SaferCond* on_finish = new C_SaferCond;
+
+    image_ctx->state->open(false, on_finish);
+
+    ictxs.push_back(image_ctx);
+    on_finishes.push_back(on_finish);
+  }
+
+  ret_code = 0;
+  for (int i = 0; i < snap_count; ++i) {
+    r = on_finishes[i]->wait();
+    delete on_finishes[i];
+    if (r < 0) {
+      delete ictxs[i];
+      ictxs[i] = nullptr;
+      ret_code = r;
+    }
+  }
+  if (ret_code != 0) {
+    goto finish;
+  }
+
+  ldout(cct, 20) << "Requesting exclusive locks for images" << dendl;
+  for (auto ictx: ictxs) {
+    RWLock::RLocker owner_lock(ictx->owner_lock);
+    if (ictx->exclusive_lock != nullptr) {
+      ictx->exclusive_lock->block_requests(-EBUSY);
+    }
+  }
+  for (int i = 0; i < snap_count; ++i) {
+    ImageCtx *ictx = ictxs[i];
+    RWLock::RLocker owner_lock(ictx->owner_lock);
+
+    on_finishes[i] = new C_SaferCond;
+    if (ictx->exclusive_lock != nullptr) {
+      ictx->exclusive_lock->acquire_lock(on_finishes[i]);
+    }
+  }
+
+  ret_code = 0;
+  for (int i = 0; i < snap_count; ++i) {
+    r = 0;
+    ImageCtx *ictx = ictxs[i];
+    if (ictx->exclusive_lock != nullptr) {
+      r = on_finishes[i]->wait();
+    }
+    delete on_finishes[i];
+    if (r < 0) {
+      ret_code = r;
+    }
+  }
+  if (ret_code != 0) {
+    goto finish;
+  }
+
+  for (int i = 0; i < snap_count; ++i) {
+    ImageCtx *ictx = ictxs[i];
+    on_finishes[i] = new C_SaferCond;
+
+    RWLock::RLocker owner_locker(ictx->owner_lock);
+    std::string snap_name;
+    ictx->snap_lock.get_read();
+    snap_t snap_id = get_group_snap_id(ictx, ne);
+    r = ictx->get_snap_name(snap_id, &snap_name);
+    ictx->snap_lock.put_read();
+
+    if (r >= 0) {
+      ldout(cct, 20) << "rolling back to individual snapshot for image " << ictx->name
+                     << dendl;
+      ictx->operations->execute_snap_rollback(ne, snap_name, pctx, on_finishes[i]);
+    } else {
+      on_finishes[i]->complete(r);
+    }
+  }
+
+  for (int i = 0; i < snap_count; ++i) {
+    r = on_finishes[i]->wait();
+    delete on_finishes[i];
+    if (r < 0 && r != -ENOENT) {
+      lderr(cct) << "Failed rolling back group to snapshot. Ret code: " << r << dendl;
+      ret_code = r;
+    }
+  }
+
+finish:
+  for (int i = 0; i < snap_count; ++i) {
+    if (ictxs[i] != nullptr) {
+      ictxs[i]->state->close();
+    }
+  }
+  return ret_code;
+}
+
 } // anonymous namespace
 
 template <typename I>
@@ -1049,6 +1170,45 @@ int Group<I>::snap_list(librados::IoCtx& group_ioctx, const char *group_name,
   return 0;
 }
 
+template <typename I>
+int Group<I>::snap_rollback(librados::IoCtx& group_ioctx,
+                            const char *group_name, const char *snap_name,
+                            ProgressContext& pctx)
+{
+  CephContext *cct = (CephContext *)group_ioctx.cct();
+
+  string group_id;
+  int r = cls_client::dir_get_id(&group_ioctx, RBD_GROUP_DIRECTORY,
+                                 group_name, &group_id);
+  if (r < 0) {
+    lderr(cct) << "error reading group id object: "
+               << cpp_strerror(r) << dendl;
+    return r;
+  }
+
+  std::vector<cls::rbd::GroupSnapshot> snaps;
+  r = group_snap_list(group_ioctx, group_name, &snaps);
+  if (r < 0) {
+    return r;
+  }
+
+  cls::rbd::GroupSnapshot *group_snap = nullptr;
+  for (auto &snap : snaps) {
+    if (snap.name == string(snap_name)) {
+      group_snap = &snap;
+      break;
+    }
+  }
+  if (group_snap == nullptr) {
+    return -ENOENT;
+  }
+
+  string group_header_oid = util::group_header_name(group_id);
+  r = group_snap_rollback_by_record(group_ioctx, *group_snap, group_id,
+                                    group_header_oid, pctx);
+  return r;
+}
+
 } // namespace api
 } // namespace librbd
 
index 4d3c761277980bab5d777977e61c6b7ecbde7ff6..6ef55288cf43b6fc92a70847017dfe3e3355ec4d 100644 (file)
@@ -46,6 +46,9 @@ struct Group {
                          const char *old_snap_name, const char *new_snap_name);
   static int snap_list(librados::IoCtx& group_ioctx, const char *group_name,
                        std::vector<group_snap_info_t> *snaps);
+  static int snap_rollback(librados::IoCtx& group_ioctx,
+                           const char *group_name, const char *snap_name,
+                           ProgressContext& pctx);
 
 };
 
index 0d63bfbbec33fd34ed1c684d2500a3b8c52eabdf..14e83b46a3c830cab62eb0016fe965a44cf3c78b 100644 (file)
@@ -969,6 +969,32 @@ namespace librbd {
     return r;
   }
 
+  int RBD::group_snap_rollback(IoCtx& group_ioctx, const char *group_name,
+                               const char *snap_name) {
+    TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
+    tracepoint(librbd, group_snap_rollback_enter,
+               group_ioctx.get_pool_name().c_str(),
+               group_ioctx.get_id(), group_name, snap_name);
+    librbd::NoOpProgressContext prog_ctx;
+    int r = librbd::api::Group<>::snap_rollback(group_ioctx, group_name,
+                                                snap_name, prog_ctx);
+    tracepoint(librbd, group_snap_rollback_exit, r);
+    return r;
+  }
+
+  int RBD::group_snap_rollback_with_progress(IoCtx& group_ioctx,
+                                             const char *group_name,
+                                             const char *snap_name,
+                                             ProgressContext& prog_ctx) {
+    TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
+    tracepoint(librbd, group_snap_rollback_enter,
+               group_ioctx.get_pool_name().c_str(),
+               group_ioctx.get_id(), group_name, snap_name);
+    int r = librbd::api::Group<>::snap_rollback(group_ioctx, group_name,
+                                                snap_name, prog_ctx);
+    tracepoint(librbd, group_snap_rollback_exit, r);
+    return r;
+  }
 
   RBD::AioCompletion::AioCompletion(void *cb_arg, callback_t complete_cb)
   {
@@ -5265,6 +5291,50 @@ extern "C" int rbd_group_snap_list_cleanup(rbd_group_snap_info_t *snaps,
   return 0;
 }
 
+extern "C" int rbd_group_snap_rollback(rados_ioctx_t group_p,
+                                       const char *group_name,
+                                       const char *snap_name)
+{
+  librados::IoCtx group_ioctx;
+  librados::IoCtx::from_rados_ioctx_t(group_p, group_ioctx);
+
+  TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
+  tracepoint(librbd, group_snap_rollback_enter,
+             group_ioctx.get_pool_name().c_str(),
+             group_ioctx.get_id(), group_name, snap_name);
+
+  librbd::NoOpProgressContext prog_ctx;
+  int r = librbd::api::Group<>::snap_rollback(group_ioctx, group_name,
+                                              snap_name, prog_ctx);
+
+  tracepoint(librbd, group_snap_rollback_exit, r);
+
+  return r;
+}
+
+extern "C" int rbd_group_snap_rollback_with_progress(rados_ioctx_t group_p,
+                                                     const char *group_name,
+                                                     const char *snap_name,
+                                                     librbd_progress_fn_t cb,
+                                                     void *cbdata)
+{
+  librados::IoCtx group_ioctx;
+  librados::IoCtx::from_rados_ioctx_t(group_p, group_ioctx);
+
+  TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
+  tracepoint(librbd, group_snap_rollback_enter,
+             group_ioctx.get_pool_name().c_str(),
+             group_ioctx.get_id(), group_name, snap_name);
+
+  librbd::CProgressContext prog_ctx(cb, cbdata);
+  int r = librbd::api::Group<>::snap_rollback(group_ioctx, group_name,
+                                              snap_name, prog_ctx);
+
+  tracepoint(librbd, group_snap_rollback_exit, r);
+
+  return r;
+}
+
 extern "C" int rbd_snap_get_namespace_type(rbd_image_t image,
                                           uint64_t snap_id,
                                           rbd_snap_namespace_type_t *namespace_type) {
index 160601758a2a6b678a9d7cb9b3d8122cf63af323..ce3cf2a54ea966d4461da421b93745f11b247e50 100644 (file)
@@ -207,6 +207,20 @@ TEST_F(TestGroup, add_snapshot)
   const char *group_name = "snap_group";
   const char *snap_name = "snap_snapshot";
 
+  const char orig_data[] = "orig data";
+  const char test_data[] = "test data";
+  char read_data[10];
+
+  rbd_image_t image;
+  ASSERT_EQ(0, rbd_open(ioctx, m_image_name.c_str(), &image, NULL));
+  BOOST_SCOPE_EXIT(image) {
+    EXPECT_EQ(0, rbd_close(image));
+  } BOOST_SCOPE_EXIT_END;
+
+  ASSERT_EQ(10, rbd_write(image, 0, 10, orig_data));
+  ASSERT_EQ(10, rbd_read(image, 0, 10, read_data));
+  ASSERT_EQ(0, memcmp(orig_data, read_data, 10));
+
   ASSERT_EQ(0, rbd_group_create(ioctx, group_name));
 
   ASSERT_EQ(0, rbd_group_image_add(ioctx, group_name, ioctx,
@@ -227,6 +241,14 @@ TEST_F(TestGroup, add_snapshot)
 
   ASSERT_STREQ(snap_name, snaps[0].name);
 
+  ASSERT_EQ(10, rbd_write(image, 11, 10, test_data));
+  ASSERT_EQ(10, rbd_read(image, 11, 10, read_data));
+  ASSERT_EQ(0, memcmp(test_data, read_data, 10));
+
+  ASSERT_EQ(0, rbd_group_snap_rollback(ioctx, group_name, snap_name));
+  ASSERT_EQ(10, rbd_read(image, 0, 10, read_data));
+  ASSERT_EQ(0, memcmp(orig_data, read_data, 10));
+
   ASSERT_EQ(0, rbd_group_snap_list_cleanup(snaps, sizeof(rbd_group_snap_info_t),
                                            num_snaps));
   ASSERT_EQ(0, rbd_group_snap_remove(ioctx, group_name, snap_name));
@@ -255,6 +277,15 @@ TEST_F(TestGroup, add_snapshotPP)
   ASSERT_EQ(0, rbd.group_image_add(ioctx, group_name, ioctx,
                                    m_image_name.c_str()));
 
+  librbd::Image image;
+  ASSERT_EQ(0, rbd.open(ioctx, image, m_image_name.c_str(), NULL));
+  bufferlist expect_bl;
+  bufferlist read_bl;
+  expect_bl.append(std::string(512, '1'));
+  ASSERT_EQ((ssize_t)expect_bl.length(), image.write(0, expect_bl.length(), expect_bl));
+  ASSERT_EQ(512, image.read(0, 512, read_bl));
+  ASSERT_TRUE(expect_bl.contents_equal(read_bl));
+
   ASSERT_EQ(0, rbd.group_snap_create(ioctx, group_name, snap_name));
 
   std::vector<librbd::group_snap_info_t> snaps;
@@ -264,6 +295,21 @@ TEST_F(TestGroup, add_snapshotPP)
 
   ASSERT_EQ(snap_name, snaps[0].name);
 
+  bufferlist write_bl;
+  write_bl.append(std::string(1024, '2'));
+  ASSERT_EQ(1024, image.write(513, write_bl.length(), write_bl));
+
+  read_bl.clear();
+  ASSERT_EQ(1024, image.read(513, 1024, read_bl));
+  ASSERT_TRUE(write_bl.contents_equal(read_bl));
+
+  ASSERT_EQ(0, rbd.group_snap_rollback(ioctx, group_name, snap_name));
+
+  ASSERT_EQ(512, image.read(0, 512, read_bl));
+  ASSERT_TRUE(expect_bl.contents_equal(read_bl));
+
+  ASSERT_EQ(0, image.close());
+
   ASSERT_EQ(0, rbd.group_snap_remove(ioctx, group_name, snap_name));
 
   snaps.clear();
index 3c189fb33f0d04a46eea89d0d22a9edb49dec484..cd13e45fd9aacbbc806db06331f5934dab995cd0 100644 (file)
@@ -2830,6 +2830,28 @@ TRACEPOINT_EVENT(librbd, group_snap_list_exit,
     )
 )
 
+TRACEPOINT_EVENT(librbd, group_snap_rollback_enter,
+    TP_ARGS(
+        const char*, pool_name,
+        int64_t, id,
+        const char*, group_name,
+        const char*, snap_name),
+    TP_FIELDS(
+        ctf_string(pool_name, pool_name)
+        ctf_integer(int64_t, id, id)
+        ctf_string(group_name, group_name)
+        ctf_string(snap_name, snap_name)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, group_snap_rollback_exit,
+    TP_ARGS(
+        int, retval),
+    TP_FIELDS(
+        ctf_integer(int, retval, retval)
+    )
+)
+
 TRACEPOINT_EVENT(librbd, list_watchers_enter,
     TP_ARGS(
         void*, imagectx,