]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: extend group snap create API to support flags
authorMykola Golub <mgolub@suse.com>
Wed, 2 Dec 2020 17:43:16 +0000 (17:43 +0000)
committerMykola Golub <mgolub@suse.com>
Thu, 10 Dec 2020 06:12:56 +0000 (06:12 +0000)
Signed-off-by: Mykola Golub <mgolub@suse.com>
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/pybind/rbd/c_rbd.pxd
src/pybind/rbd/mock_rbd.pxi
src/pybind/rbd/rbd.pyx
src/test/librbd/test_Groups.cc
src/test/pybind/test_rbd.py

index bde2a43274dad83bae14ada7e6670a75917753e5..a0eb57eef3a72148ebb02a5d42c80b4e3c4be88b 100644 (file)
@@ -1364,6 +1364,10 @@ CEPH_RBD_API int rbd_group_image_list_cleanup(rbd_group_image_info_t *images,
 CEPH_RBD_API int rbd_group_snap_create(rados_ioctx_t group_p,
                                        const char *group_name,
                                        const char *snap_name);
+CEPH_RBD_API int rbd_group_snap_create2(rados_ioctx_t group_p,
+                                        const char *group_name,
+                                        const char *snap_name,
+                                        uint32_t flags);
 CEPH_RBD_API int rbd_group_snap_remove(rados_ioctx_t group_p,
                                        const char *group_name,
                                        const char *snap_name);
index 63c1f759cd59ecb10885debaa408b8981437a0d6..71e955b25249415f1f019a8830489da5ff0c7faa 100644 (file)
@@ -406,6 +406,8 @@ public:
 
   int group_snap_create(IoCtx& io_ctx, const char *group_name,
                        const char *snap_name);
+  int group_snap_create2(IoCtx& io_ctx, const char *group_name,
+                         const char *snap_name, uint32_t flags);
   int group_snap_remove(IoCtx& io_ctx, const char *group_name,
                        const char *snap_name);
   int group_snap_rename(IoCtx& group_ioctx, const char *group_name,
index b33b3f4998f878bbe96528af832723b10141522a..72a99cf47672cc5343466280727de77489f9fda1 100644 (file)
@@ -440,6 +440,10 @@ finish:
 template <typename I>
 void notify_unquiesce(std::vector<I*> &ictxs,
                       const std::vector<uint64_t> &requests) {
+  if (requests.empty()) {
+    return;
+  }
+
   ceph_assert(requests.size() == ictxs.size());
   int image_count = ictxs.size();
   std::vector<C_SaferCond> on_finishes(image_count);
@@ -878,8 +882,8 @@ int Group<I>::image_get_group(I *ictx, group_info_t *group_info)
 
 template <typename I>
 int Group<I>::snap_create(librados::IoCtx& group_ioctx,
-    const char *group_name, const char *snap_name)
-{
+                          const char *group_name, const char *snap_name,
+                          uint32_t flags) {
   CephContext *cct = (CephContext *)group_ioctx.cct();
 
   string group_id;
@@ -891,9 +895,17 @@ int Group<I>::snap_create(librados::IoCtx& group_ioctx,
   std::vector<C_SaferCond*> on_finishes;
   std::vector<uint64_t> quiesce_requests;
   NoOpProgressContext prog_ctx;
+  uint64_t internal_flags = 0;
 
-  int r = cls_client::dir_get_id(&group_ioctx, RBD_GROUP_DIRECTORY,
-                                group_name, &group_id);
+  int r = util::snap_create_flags_api_to_internal(cct, flags, &internal_flags);
+  if (r < 0) {
+    return r;
+  }
+  internal_flags &= ~(SNAP_CREATE_FLAG_SKIP_NOTIFY_QUIESCE |
+                      SNAP_CREATE_FLAG_IGNORE_NOTIFY_QUIESCE_ERROR);
+
+  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)
@@ -979,10 +991,12 @@ int Group<I>::snap_create(librados::IoCtx& group_ioctx,
     goto remove_record;
   }
 
-  ldout(cct, 20) << "Sending quiesce notification" << dendl;
-  ret_code = notify_quiesce(ictxs, prog_ctx, &quiesce_requests);
-  if (ret_code != 0) {
-    goto remove_record;
+  if ((flags & RBD_SNAP_CREATE_SKIP_QUIESCE) == 0) {
+    ldout(cct, 20) << "Sending quiesce notification" << dendl;
+    ret_code = notify_quiesce(ictxs, prog_ctx, &quiesce_requests);
+    if (ret_code != 0 && (flags & RBD_SNAP_CREATE_IGNORE_QUIESCE_ERROR) == 0) {
+      goto remove_record;
+    }
   }
 
   ldout(cct, 20) << "Requesting exclusive locks for images" << dendl;
index 59b978a89477cd159620f6c24664e79ae1c670f6..9d3abcc59e832f8846a162b29d7f60ec23870a28 100644 (file)
@@ -38,7 +38,8 @@ struct Group {
   static int image_get_group(ImageCtxT *ictx, group_info_t *group_info);
 
   static int snap_create(librados::IoCtx& group_ioctx,
-                         const char *group_name, const char *snap_name);
+                         const char *group_name, const char *snap_name,
+                         uint32_t flags);
   static int snap_remove(librados::IoCtx& group_ioctx,
                          const char *group_name, const char *snap_name);
   static int snap_rename(librados::IoCtx& group_ioctx, const char *group_name,
index 2068048dc30b1ab4a5445f4e84c94e5dbdb7f969..6d5956453fad8f75188bec7a212a9dc64718c0cf 100644 (file)
@@ -1329,7 +1329,19 @@ namespace librbd {
                group_ioctx.get_pool_name().c_str(),
               group_ioctx.get_id(), group_name, snap_name);
     int r = librbd::api::Group<>::snap_create(group_ioctx, group_name,
-                                              snap_name);
+                                              snap_name, 0);
+    tracepoint(librbd, group_snap_create_exit, r);
+    return r;
+  }
+
+  int RBD::group_snap_create2(IoCtx& group_ioctx, const char *group_name,
+                              const char *snap_name, uint32_t flags) {
+    TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
+    tracepoint(librbd, group_snap_create_enter,
+               group_ioctx.get_pool_name().c_str(),
+              group_ioctx.get_id(), group_name, snap_name);
+    int r = librbd::api::Group<>::snap_create(group_ioctx, group_name,
+                                              snap_name, flags);
     tracepoint(librbd, group_snap_create_exit, r);
     return r;
   }
@@ -6942,8 +6954,28 @@ extern "C" int rbd_group_snap_create(rados_ioctx_t group_p,
              group_ioctx.get_pool_name().c_str(),
             group_ioctx.get_id(), group_name, snap_name);
 
-  int r = librbd::api::Group<>::snap_create(group_ioctx, group_name, snap_name);
+  int r = librbd::api::Group<>::snap_create(group_ioctx, group_name,
+                                            snap_name, 0);
+  tracepoint(librbd, group_snap_create_exit, r);
+
+  return r;
+}
+
+extern "C" int rbd_group_snap_create2(rados_ioctx_t group_p,
+                                      const char *group_name,
+                                      const char *snap_name,
+                                      uint32_t flags)
+{
+  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_create_enter,
+             group_ioctx.get_pool_name().c_str(),
+            group_ioctx.get_id(), group_name, snap_name);
 
+  int r = librbd::api::Group<>::snap_create(group_ioctx, group_name, snap_name,
+                                            flags);
   tracepoint(librbd, group_snap_create_exit, r);
 
   return r;
index ab1a8a76081deea71ee9da77803286b58490e110..410927507a398184ab0845993ee5c7fd6df5ec33 100644 (file)
@@ -645,8 +645,8 @@ cdef extern from "rbd/librbd.h" nogil:
     void rbd_group_image_list_cleanup(rbd_group_image_info_t *images,
                                       size_t group_image_info_size, size_t len)
 
-    int rbd_group_snap_create(rados_ioctx_t group_p, const char *group_name,
-                              const char *snap_name)
+    int rbd_group_snap_create2(rados_ioctx_t group_p, const char *group_name,
+                               const char *snap_name, uint32_t flags)
 
     int rbd_group_snap_remove(rados_ioctx_t group_p, const char *group_name,
                               const char *snap_name)
index c972ba7b97c28bc058a067263c517956fb77ae87..bfcb07c413a55492866b9e7220c57a23f992780f 100644 (file)
@@ -824,8 +824,8 @@ cdef nogil:
     void rbd_group_image_list_cleanup(rbd_group_image_info_t *images,
                                       size_t group_image_info_size, size_t len):
         pass
-    int rbd_group_snap_create(rados_ioctx_t group_p, const char *group_name,
-                              const char *snap_name):
+    int rbd_group_snap_create2(rados_ioctx_t group_p, const char *group_name,
+                               const char *snap_name, uint32_t flags):
         pass
     int rbd_group_snap_remove(rados_ioctx_t group_p, const char *group_name,
                               const char *snap_name):
index ba0d108efb99e70cf57d6b16ef6c99cf0b3300ec..60b47e17938029b4f21d961424569e7c661f479b 100644 (file)
@@ -2668,11 +2668,12 @@ cdef class Group(object):
         """
         return GroupImageIterator(self)
 
-    def create_snap(self, snap_name):
+    def create_snap(self, snap_name, flags=0):
         """
         Create a snapshot for the group.
 
         :param snap_name: the name of the snapshot to create
+        :param flags: create snapshot flags
         :type name: str
 
         :raises: :class:`ObjectNotFound`
@@ -2683,8 +2684,10 @@ cdef class Group(object):
         snap_name = cstr(snap_name, 'snap_name')
         cdef:
             char *_snap_name = snap_name
+            uint32_t _flags = flags
         with nogil:
-            ret = rbd_group_snap_create(self._ioctx, self._name, _snap_name)
+            ret = rbd_group_snap_create2(self._ioctx, self._name, _snap_name,
+                                         _flags)
         if ret != 0:
             raise make_ex(ret, 'error creating group snapshot', group_errno_to_exception)
 
index ce3cf2a54ea966d4461da421b93745f11b247e50..3182d2a2004e23ce7214671ca97ac3dd40daf6d6 100644 (file)
@@ -9,6 +9,7 @@
 #include "gtest/gtest.h"
 
 #include <boost/scope_exit.hpp>
+#include <chrono>
 #include <vector>
 
 void register_test_groups() {
@@ -226,7 +227,52 @@ TEST_F(TestGroup, add_snapshot)
   ASSERT_EQ(0, rbd_group_image_add(ioctx, group_name, ioctx,
                                    m_image_name.c_str()));
 
+  struct Watcher {
+    static void quiesce_cb(void *arg) {
+      Watcher *watcher = static_cast<Watcher *>(arg);
+      watcher->handle_quiesce();
+    }
+    static void unquiesce_cb(void *arg) {
+      Watcher *watcher = static_cast<Watcher *>(arg);
+      watcher->handle_unquiesce();
+    }
+
+    rbd_image_t &image;
+    uint64_t handle = 0;
+    size_t quiesce_count = 0;
+    size_t unquiesce_count = 0;
+    int r = 0;
+
+    ceph::mutex lock = ceph::make_mutex("lock");
+    ceph::condition_variable cv;
+
+    Watcher(rbd_image_t &image) : image(image) {
+    }
+
+    void handle_quiesce() {
+      ASSERT_EQ(quiesce_count, unquiesce_count);
+      quiesce_count++;
+      rbd_quiesce_complete(image, handle, r);
+    }
+    void handle_unquiesce() {
+      std::unique_lock locker(lock);
+      unquiesce_count++;
+      cv.notify_one();
+    }
+    bool wait_for_unquiesce(size_t c) {
+      std::unique_lock locker(lock);
+      return cv.wait_for(locker, std::chrono::seconds(60),
+                         [this, c]() { return unquiesce_count >= c; });
+    }
+  } watcher(image);
+
+  ASSERT_EQ(0, rbd_quiesce_watch(image, Watcher::quiesce_cb,
+                                 Watcher::unquiesce_cb, &watcher,
+                                 &watcher.handle));
+
   ASSERT_EQ(0, rbd_group_snap_create(ioctx, group_name, snap_name));
+  ASSERT_TRUE(watcher.wait_for_unquiesce(1U));
+  ASSERT_EQ(1U, watcher.quiesce_count);
 
   size_t num_snaps = 0;
   ASSERT_EQ(-ERANGE, rbd_group_snap_list(ioctx, group_name, NULL,
@@ -258,6 +304,40 @@ TEST_F(TestGroup, add_snapshot)
                                    &num_snaps));
   ASSERT_EQ(0U, num_snaps);
 
+  ASSERT_EQ(-EINVAL, rbd_group_snap_create2(ioctx, group_name, snap_name,
+                                            RBD_SNAP_CREATE_SKIP_QUIESCE |
+                                            RBD_SNAP_CREATE_IGNORE_QUIESCE_ERROR));
+  watcher.r = -EINVAL;
+  ASSERT_EQ(-EINVAL, rbd_group_snap_create2(ioctx, group_name, snap_name, 0));
+
+  num_snaps = 1;
+  ASSERT_EQ(0, rbd_group_snap_list(ioctx, group_name, snaps,
+                                   sizeof(rbd_group_snap_info_t),
+                                   &num_snaps));
+
+  watcher.quiesce_count = 0;
+  watcher.unquiesce_count = 0;
+  ASSERT_EQ(0, rbd_group_snap_create2(ioctx, group_name, snap_name,
+                                      RBD_SNAP_CREATE_SKIP_QUIESCE));
+  ASSERT_EQ(0U, watcher.quiesce_count);
+  num_snaps = 1;
+  ASSERT_EQ(1, rbd_group_snap_list(ioctx, group_name, snaps,
+                                   sizeof(rbd_group_snap_info_t),
+                                   &num_snaps));
+  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));
+
+  ASSERT_EQ(0, rbd_group_snap_create2(ioctx, group_name, snap_name,
+                                      RBD_SNAP_CREATE_IGNORE_QUIESCE_ERROR));
+  ASSERT_EQ(1, rbd_group_snap_list(ioctx, group_name, snaps,
+                                   sizeof(rbd_group_snap_info_t),
+                                   &num_snaps));
+  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));
+
+  ASSERT_EQ(0, rbd_quiesce_unwatch(image, watcher.handle));
   ASSERT_EQ(0, rbd_group_remove(ioctx, group_name));
 }
 
@@ -317,5 +397,27 @@ TEST_F(TestGroup, add_snapshotPP)
                                    sizeof(librbd::group_snap_info_t)));
   ASSERT_EQ(0U, snaps.size());
 
+  ASSERT_EQ(0, rbd.group_snap_create(ioctx, group_name, snap_name));
+  ASSERT_EQ(0, rbd.group_snap_list(ioctx, group_name, &snaps,
+                                   sizeof(librbd::group_snap_info_t)));
+  ASSERT_EQ(1U, snaps.size());
+  ASSERT_EQ(0, rbd.group_snap_remove(ioctx, group_name, snap_name));
+
+  ASSERT_EQ(-EINVAL, rbd.group_snap_create2(ioctx, group_name, snap_name,
+                                            RBD_SNAP_CREATE_SKIP_QUIESCE |
+                                            RBD_SNAP_CREATE_IGNORE_QUIESCE_ERROR));
+  snaps.clear();
+  ASSERT_EQ(0, rbd.group_snap_list(ioctx, group_name, &snaps,
+                                   sizeof(librbd::group_snap_info_t)));
+  ASSERT_EQ(0U, snaps.size());
+
+  ASSERT_EQ(0, rbd.group_snap_create2(ioctx, group_name, snap_name,
+                                      RBD_SNAP_CREATE_SKIP_QUIESCE));
+  snaps.clear();
+  ASSERT_EQ(0, rbd.group_snap_list(ioctx, group_name, &snaps,
+                                   sizeof(librbd::group_snap_info_t)));
+  ASSERT_EQ(1U, snaps.size());
+
+  ASSERT_EQ(0, rbd.group_snap_remove(ioctx, group_name, snap_name));
   ASSERT_EQ(0, rbd.group_remove(ioctx, group_name));
 }
index e0b21a0a9ede5620486bb2c14c28a5d83fbc72a0..74cde0764d6bc183dcc9447e06a9bd90c5bbc108 100644 (file)
@@ -2528,6 +2528,27 @@ class TestGroups(object):
         self.group.remove_snap(snap_name)
         eq([], list(self.group.list_snaps()))
 
+    def test_group_snap_flags(self):
+        global snap_name
+        eq([], list(self.group.list_snaps()))
+
+        self.group.create_snap(snap_name, 0)
+        eq([snap_name], [snap['name'] for snap in self.group.list_snaps()])
+        self.group.remove_snap(snap_name)
+
+        self.group.create_snap(snap_name, RBD_SNAP_CREATE_SKIP_QUIESCE)
+        eq([snap_name], [snap['name'] for snap in self.group.list_snaps()])
+        self.group.remove_snap(snap_name)
+
+        self.group.create_snap(snap_name, RBD_SNAP_CREATE_IGNORE_QUIESCE_ERROR)
+        eq([snap_name], [snap['name'] for snap in self.group.list_snaps()])
+        self.group.remove_snap(snap_name)
+
+        assert_raises(InvalidArgument, self.group.create_snap, snap_name,
+                      RBD_SNAP_CREATE_SKIP_QUIESCE |
+                      RBD_SNAP_CREATE_IGNORE_QUIESCE_ERROR)
+        eq([], list(self.group.list_snaps()))
+
     def test_group_snap_list_many(self):
         global snap_name
         eq([], list(self.group.list_snaps()))