From bb34123e1d637c386fb4865d08c4dfcb2b49def3 Mon Sep 17 00:00:00 2001 From: Mykola Golub Date: Wed, 2 Dec 2020 17:43:16 +0000 Subject: [PATCH] librbd: extend group snap create API to support flags Signed-off-by: Mykola Golub --- src/include/rbd/librbd.h | 4 ++ src/include/rbd/librbd.hpp | 2 + src/librbd/api/Group.cc | 30 +++++++--- src/librbd/api/Group.h | 3 +- src/librbd/librbd.cc | 36 +++++++++++- src/pybind/rbd/c_rbd.pxd | 4 +- src/pybind/rbd/mock_rbd.pxi | 4 +- src/pybind/rbd/rbd.pyx | 7 ++- src/test/librbd/test_Groups.cc | 102 +++++++++++++++++++++++++++++++++ src/test/pybind/test_rbd.py | 21 +++++++ 10 files changed, 196 insertions(+), 17 deletions(-) diff --git a/src/include/rbd/librbd.h b/src/include/rbd/librbd.h index bde2a43274d..a0eb57eef3a 100644 --- a/src/include/rbd/librbd.h +++ b/src/include/rbd/librbd.h @@ -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); diff --git a/src/include/rbd/librbd.hpp b/src/include/rbd/librbd.hpp index 63c1f759cd5..71e955b2524 100644 --- a/src/include/rbd/librbd.hpp +++ b/src/include/rbd/librbd.hpp @@ -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, diff --git a/src/librbd/api/Group.cc b/src/librbd/api/Group.cc index b33b3f4998f..72a99cf4767 100644 --- a/src/librbd/api/Group.cc +++ b/src/librbd/api/Group.cc @@ -440,6 +440,10 @@ finish: template void notify_unquiesce(std::vector &ictxs, const std::vector &requests) { + if (requests.empty()) { + return; + } + ceph_assert(requests.size() == ictxs.size()); int image_count = ictxs.size(); std::vector on_finishes(image_count); @@ -878,8 +882,8 @@ int Group::image_get_group(I *ictx, group_info_t *group_info) template int Group::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::snap_create(librados::IoCtx& group_ioctx, std::vector on_finishes; std::vector 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::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; diff --git a/src/librbd/api/Group.h b/src/librbd/api/Group.h index 59b978a8947..9d3abcc59e8 100644 --- a/src/librbd/api/Group.h +++ b/src/librbd/api/Group.h @@ -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, diff --git a/src/librbd/librbd.cc b/src/librbd/librbd.cc index 2068048dc30..6d5956453fa 100644 --- a/src/librbd/librbd.cc +++ b/src/librbd/librbd.cc @@ -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(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(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; diff --git a/src/pybind/rbd/c_rbd.pxd b/src/pybind/rbd/c_rbd.pxd index ab1a8a76081..410927507a3 100644 --- a/src/pybind/rbd/c_rbd.pxd +++ b/src/pybind/rbd/c_rbd.pxd @@ -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) diff --git a/src/pybind/rbd/mock_rbd.pxi b/src/pybind/rbd/mock_rbd.pxi index c972ba7b97c..bfcb07c413a 100644 --- a/src/pybind/rbd/mock_rbd.pxi +++ b/src/pybind/rbd/mock_rbd.pxi @@ -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): diff --git a/src/pybind/rbd/rbd.pyx b/src/pybind/rbd/rbd.pyx index ba0d108efb9..60b47e17938 100644 --- a/src/pybind/rbd/rbd.pyx +++ b/src/pybind/rbd/rbd.pyx @@ -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) diff --git a/src/test/librbd/test_Groups.cc b/src/test/librbd/test_Groups.cc index ce3cf2a54ea..3182d2a2004 100644 --- a/src/test/librbd/test_Groups.cc +++ b/src/test/librbd/test_Groups.cc @@ -9,6 +9,7 @@ #include "gtest/gtest.h" #include +#include #include 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(arg); + watcher->handle_quiesce(); + } + static void unquiesce_cb(void *arg) { + Watcher *watcher = static_cast(arg); + watcher->handle_unquiesce(); + } + + rbd_image_t ℑ + 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)); } diff --git a/src/test/pybind/test_rbd.py b/src/test/pybind/test_rbd.py index e0b21a0a9ed..74cde0764d6 100644 --- a/src/test/pybind/test_rbd.py +++ b/src/test/pybind/test_rbd.py @@ -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())) -- 2.39.5