rbd_mirror_image_status_t *mirror_image_status,
size_t status_size);
+// RBD consistency 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);
+CEPH_RBD_API int rbd_group_list(rados_ioctx_t p, char *names, size_t *size);
+
#ifdef __cplusplus
}
#endif
int mirror_image_status_summary(IoCtx& io_ctx,
std::map<mirror_image_status_state_t, int> *states);
+ // RBD consistency groups support functions
+ int group_create(IoCtx& io_ctx, const char *group_name);
+ int group_remove(IoCtx& io_ctx, const char *group_name);
+ int group_list(IoCtx& io_ctx, std::vector<std::string>& names);
+
private:
/* We don't allow assignment or copying */
RBD(const RBD& rhs);
namespace librbd {
namespace util {
+const std::string group_header_name(const std::string &group_id)
+{
+ return RBD_GROUP_HEADER_PREFIX + group_id;
+}
+
const std::string id_obj_name(const std::string &name)
{
return RBD_ID_PREFIX + name;
#define CEPH_LIBRBD_UTILS_H
#include "include/rados/librados.hpp"
+#include "include/rbd_types.h"
#include "include/Context.h"
#include <type_traits>
} // namespace detail
+const std::string group_header_name(const std::string &group_id);
const std::string id_obj_name(const std::string &name);
const std::string header_name(const std::string &image_id);
const std::string old_header_name(const std::string &image_name);
ictx->perfcounter->inc(l_librbd_readahead_bytes, readahead_length);
}
}
+
+ // Consistency groups functions
+
+ int group_create(librados::IoCtx& io_ctx, const char *group_name)
+ {
+ CephContext *cct = (CephContext *)io_ctx.cct();
+
+ Rados rados(io_ctx);
+ uint64_t bid = rados.get_instance_id();
+
+ uint32_t extra = rand() % 0xFFFFFFFF;
+ ostringstream bid_ss;
+ bid_ss << std::hex << bid << std::hex << extra;
+ string id = bid_ss.str();
+
+ ldout(cct, 2) << "adding consistency group to directory..." << dendl;
+
+ int r = cls_client::group_dir_add(&io_ctx, RBD_GROUP_DIRECTORY, group_name, id);
+ if (r < 0) {
+ lderr(cct) << "error adding consistency group to directory: "
+ << cpp_strerror(r)
+ << dendl;
+ return r;
+ }
+ string header_oid = util::group_header_name(id);
+
+ r = cls_client::group_create(&io_ctx, header_oid);
+ if (r < 0) {
+ lderr(cct) << "error writing header: " << cpp_strerror(r) << dendl;
+ goto err_remove_from_dir;
+ }
+
+ return 0;
+
+ err_remove_from_dir:
+ int remove_r = cls_client::group_dir_remove(&io_ctx, RBD_GROUP_DIRECTORY,
+ group_name, id);
+ if (remove_r < 0) {
+ lderr(cct) << "error cleaning up consistency group from rbd_directory "
+ << "object after creation failed: " << cpp_strerror(remove_r)
+ << dendl;
+ }
+
+ return r;
+ }
+
+ int group_remove(librados::IoCtx& io_ctx, const char *group_name)
+ {
+ CephContext *cct((CephContext *)io_ctx.cct());
+ ldout(cct, 20) << "group_remove " << &io_ctx << " " << group_name << dendl;
+
+ std::string group_id;
+ int r = cls_client::dir_get_id(&io_ctx, RBD_GROUP_DIRECTORY,
+ std::string(group_name), &group_id);
+ if (r < 0 && r != -ENOENT) {
+ lderr(cct) << "error getting id of group" << dendl;
+ return r;
+ }
+
+ string header_oid = util::group_header_name(group_id);
+
+ r = io_ctx.remove(header_oid);
+ if (r < 0 && r != -ENOENT) {
+ lderr(cct) << "error removing header: " << cpp_strerror(-r) << dendl;
+ return r;
+ }
+
+ r = cls_client::group_dir_remove(&io_ctx, RBD_GROUP_DIRECTORY,
+ group_name, group_id);
+ if (r < 0 && r != -ENOENT) {
+ lderr(cct) << "error removing group from directory" << dendl;
+ return r;
+ }
+
+ return 0;
+ }
+
+ int group_list(IoCtx& io_ctx, vector<string>& names)
+ {
+ CephContext *cct = (CephContext *)io_ctx.cct();
+ ldout(cct, 20) << "group_list " << &io_ctx << dendl;
+
+ int max_read = 1024;
+ string last_read = "";
+ int r;
+ do {
+ map<string, string> groups;
+ r = cls_client::group_dir_list(&io_ctx, RBD_GROUP_DIRECTORY, last_read, max_read, &groups);
+ if (r < 0) {
+ lderr(cct) << "error listing group in directory: "
+ << cpp_strerror(r) << dendl;
+ return r;
+ }
+ for (pair<string, string> group : groups) {
+ names.push_back(group.first);
+ }
+ if (!groups.empty()) {
+ last_read = groups.rbegin()->first;
+ }
+ r = groups.size();
+ } while (r == max_read);
+
+ return 0;
+ }
}
size_t info_size);
int mirror_image_get_status(ImageCtx *ictx, mirror_image_status_t *status,
size_t status_size);
+
+ // Consistency groups functions
+ int group_create(librados::IoCtx& io_ctx, const char *imgname);
+ int group_remove(librados::IoCtx& io_ctx, const char *group_name);
+ int group_list(librados::IoCtx& io_ctx, std::vector<std::string>& names);
}
#endif
return librbd::mirror_image_status_summary(io_ctx, states);
}
+ int RBD::group_create(IoCtx& io_ctx, const char *group_name)
+ {
+ TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
+ tracepoint(librbd, group_create_enter, io_ctx.get_pool_name().c_str(),
+ io_ctx.get_id(), group_name);
+ int r = librbd::group_create(io_ctx, group_name);
+ tracepoint(librbd, group_create_exit, r);
+ return r;
+ }
+
+ int RBD::group_remove(IoCtx& io_ctx, const char *group_name)
+ {
+ TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
+ tracepoint(librbd, group_remove_enter, io_ctx.get_pool_name().c_str(),
+ io_ctx.get_id(), group_name);
+ int r = librbd::group_remove(io_ctx, group_name);
+ tracepoint(librbd, group_remove_exit, r);
+ return r;
+ }
+
+ int RBD::group_list(IoCtx& io_ctx, vector<string>& names)
+ {
+ TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
+ tracepoint(librbd, group_list_enter, io_ctx.get_pool_name().c_str(),
+ io_ctx.get_id());
+
+ int r = librbd::group_list(io_ctx, names);
+ if (r >= 0) {
+ for (auto itr : names) {
+ tracepoint(librbd, group_list_entry, itr.c_str());
+ }
+ }
+ tracepoint(librbd, group_list_exit, r);
+ return r;
+ }
+
RBD::AioCompletion::AioCompletion(void *cb_arg, callback_t complete_cb)
{
pc = reinterpret_cast<void*>(librbd::AioCompletion::create(
librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
comp->release();
}
+
+extern "C" int rbd_group_create(rados_ioctx_t p, const char *name)
+{
+ librados::IoCtx io_ctx;
+ librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
+ TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
+ tracepoint(librbd, group_create_enter, io_ctx.get_pool_name().c_str(),
+ io_ctx.get_id(), name);
+ int r = librbd::group_create(io_ctx, name);
+ tracepoint(librbd, group_create_exit, r);
+ return r;
+}
+
+extern "C" int rbd_group_remove(rados_ioctx_t p, const char *name)
+{
+ librados::IoCtx io_ctx;
+ librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
+ TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
+ tracepoint(librbd, group_remove_enter, io_ctx.get_pool_name().c_str(),
+ io_ctx.get_id(), name);
+ int r = librbd::group_remove(io_ctx, name);
+ tracepoint(librbd, group_remove_exit, r);
+ return r;
+}
+
+extern "C" int rbd_group_list(rados_ioctx_t p, char *names, size_t *size)
+{
+ librados::IoCtx io_ctx;
+ librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
+ TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
+ tracepoint(librbd, group_list_enter, io_ctx.get_pool_name().c_str(),
+ io_ctx.get_id());
+
+ vector<string> cpp_names;
+ int r = librbd::list(io_ctx, cpp_names);
+
+ if (r == -ENOENT) {
+ *size = 0;
+ *names = '\0';
+ tracepoint(librbd, group_list_exit, 0);
+ return 0;
+ }
+
+ if (r < 0) {
+ tracepoint(librbd, group_list_exit, r);
+ return r;
+ }
+
+ size_t expected_size = 0;
+
+ for (size_t i = 0; i < cpp_names.size(); i++) {
+ expected_size += cpp_names[i].size() + 1;
+ }
+ if (*size < expected_size) {
+ *size = expected_size;
+ tracepoint(librbd, group_list_exit, -ERANGE);
+ return -ERANGE;
+ }
+
+ if (!names)
+ return -EINVAL;
+
+ names[expected_size] = '\0';
+ for (int i = 0; i < (int)cpp_names.size(); i++) {
+ const char* name = cpp_names[i].c_str();
+ tracepoint(librbd, group_list_entry, name);
+ strcpy(names, name);
+ names += strlen(names) + 1;
+ }
+ tracepoint(librbd, group_list_exit, (int)expected_size);
+ return (int)expected_size;
+}
test/librbd/test_mirroring.cc \
test/librbd/test_MirroringWatcher.cc \
test/librbd/test_ObjectMap.cc \
+ test/librbd/test_ConsistencyGroups.cc \
test/librbd/journal/test_Entries.cc \
test/librbd/journal/test_Replay.cc
librbd_test_la_CXXFLAGS = $(UNITTEST_CXXFLAGS)
feature enable Enable the specified image feature.
flatten Fill clone with parent data (make it
independent).
+ group create Create a consistency group.
+ group list (group ls) List rbd consistency groups.
+ group remove (group rm) Delete a consistency group.
image-meta get Image metadata get the value associated with
the key.
image-meta list Image metadata list keys with values.
--image arg image name
--no-progress disable progress output
+ rbd help group create
+ usage: rbd group create [--pool <pool>] [--group <group>]
+ <group-spec>
+
+ Create a consistency group.
+
+ Positional arguments
+ <group-spec> group specification
+ (example: [<pool-name>/]<group-name>)
+
+ Optional arguments
+ -p [ --pool ] arg pool name
+ --group arg group name
+
+ rbd help group list
+ usage: rbd group list [--pool <pool>] [--format <format>] [--pretty-format]
+
+ List rbd consistency groups.
+
+ Optional arguments
+ -p [ --pool ] arg pool name
+ --format arg output format [plain, json, or xml]
+ --pretty-format pretty formatting (json and xml)
+
+ rbd help group remove
+ usage: rbd group remove [--pool <pool>] [--group <group>]
+ <group-spec>
+
+ Delete a consistency group.
+
+ Positional arguments
+ <group-spec> group specification
+ (example: [<pool-name>/]<group-name>)
+
+ Optional arguments
+ -p [ --pool ] arg pool name
+ --group arg group name
+
rbd help image-meta get
usage: rbd image-meta get [--pool <pool>] [--image <image>]
<image-spec> <key>
--- /dev/null
+// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+#include "test/librbd/test_fixture.h"
+#include "test/librbd/test_support.h"
+#include "include/int_types.h"
+#include "include/stringify.h"
+#include "include/rados/librados.h"
+#include "include/rbd/librbd.hpp"
+#include "common/Cond.h"
+#include "common/errno.h"
+#include "common/Mutex.h"
+#include "common/RWLock.h"
+#include "cls/lock/cls_lock_client.h"
+#include "cls/lock/cls_lock_types.h"
+#include "librbd/AioCompletion.h"
+#include "librbd/AioImageRequestWQ.h"
+#include "librbd/internal.h"
+#include "librbd/ImageCtx.h"
+#include "librbd/ImageWatcher.h"
+#include "librbd/WatchNotifyTypes.h"
+#include "test/librados/test.h"
+#include "gtest/gtest.h"
+#include <boost/assign/std/set.hpp>
+#include <boost/assign/std/map.hpp>
+#include <boost/bind.hpp>
+#include <boost/scope_exit.hpp>
+#include <boost/thread/thread.hpp>
+#include <iostream>
+#include <map>
+#include <set>
+#include <sstream>
+#include <vector>
+
+using namespace ceph;
+using namespace boost::assign;
+using namespace librbd::watch_notify;
+
+void register_test_consistency_groups() {
+}
+
+class TestLibCG : public TestFixture {
+
+};
+
+TEST_F(TestLibCG, group_create)
+{
+ librados::IoCtx ioctx;
+ ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
+
+ librbd::RBD rbd;
+ ASSERT_EQ(0, rbd.group_create(ioctx, "mygroup"));
+
+ vector<string> groups;
+ ASSERT_EQ(0, rbd.group_list(ioctx, groups));
+ ASSERT_EQ(1U, groups.size());
+ ASSERT_EQ("mygroup", groups[0]);
+
+ ASSERT_EQ(0, rbd.group_remove(ioctx, "mygroup"));
+
+ groups.clear();
+ ASSERT_EQ(0, rbd.group_list(ioctx, groups));
+ ASSERT_EQ(0U, groups.size());
+}
extern void register_test_object_map();
extern void register_test_mirroring();
extern void register_test_mirroring_watcher();
+extern void register_test_consistency_groups();
#endif // TEST_LIBRBD_INTERNALS
int main(int argc, char **argv)
register_test_object_map();
register_test_mirroring();
register_test_mirroring_watcher();
+ register_test_consistency_groups();
#endif // TEST_LIBRBD_INTERNALS
::testing::InitGoogleTest(&argc, argv);
ctf_array_text(char, parent_name, info->parent_name, RBD_MAX_IMAGE_NAME_SIZE)
)
)
+
+TRACEPOINT_EVENT(librbd, group_create_enter,
+ TP_ARGS(
+ const char*, pool_name,
+ int64_t, id,
+ const char*, groupname),
+ TP_FIELDS(
+ ctf_string(pool_name, pool_name)
+ ctf_integer(int64_t, id, id)
+ ctf_string(groupname, groupname)
+ )
+)
+
+TRACEPOINT_EVENT(librbd, group_create_exit,
+ TP_ARGS(
+ int, retval),
+ TP_FIELDS(
+ ctf_integer(int, retval, retval)
+ )
+)
+
+TRACEPOINT_EVENT(librbd, group_remove_enter,
+ TP_ARGS(
+ const char*, pool_name,
+ int64_t, id,
+ const char*, groupname),
+ TP_FIELDS(
+ ctf_string(pool_name, pool_name)
+ ctf_integer(int64_t, id, id)
+ ctf_string(groupname, groupname)
+ )
+)
+
+TRACEPOINT_EVENT(librbd, group_remove_exit,
+ TP_ARGS(
+ int, retval),
+ TP_FIELDS(
+ ctf_integer(int, retval, retval)
+ )
+)
+
+TRACEPOINT_EVENT(librbd, group_list_enter,
+ TP_ARGS(
+ const char*, pool_name,
+ int64_t, id),
+ TP_FIELDS(
+ ctf_string(pool_name, pool_name)
+ ctf_integer(int64_t, id, id)
+ )
+)
+
+TRACEPOINT_EVENT(librbd, group_list_entry,
+ TP_ARGS(
+ const char*, name),
+ TP_FIELDS(
+ ctf_string(name, name)
+ )
+)
+
+TRACEPOINT_EVENT(librbd, group_list_exit,
+ TP_ARGS(
+ int, retval),
+ TP_FIELDS(
+ ctf_integer(int, retval, retval)
+ )
+)