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);
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,
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);
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;
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)
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;
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,
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;
}
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;
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)
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):
"""
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`
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)
#include "gtest/gtest.h"
#include <boost/scope_exit.hpp>
+#include <chrono>
#include <vector>
void register_test_groups() {
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 ℑ
+ 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,
&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));
}
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));
}
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()))