From: Jason Dillaman Date: Fri, 15 Jun 2018 13:20:55 +0000 (-0400) Subject: librbd: add namespace create/remove/list API methods X-Git-Tag: v14.0.1~1063^2~2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=0fca6ead10c658e401ce95eaf5cb3141b2c5a476;p=ceph.git librbd: add namespace create/remove/list API methods Signed-off-by: Jason Dillaman --- diff --git a/src/include/rbd/librbd.h b/src/include/rbd/librbd.h index ee86d8aad230..811bccb7ea82 100644 --- a/src/include/rbd/librbd.h +++ b/src/include/rbd/librbd.h @@ -978,6 +978,13 @@ 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_namespace_create(rados_ioctx_t io, + const char *namespace_name); +CEPH_RBD_API int rbd_namespace_remove(rados_ioctx_t io, + const char *namespace_name); +CEPH_RBD_API int rbd_namespace_list(rados_ioctx_t io, char *namespace_names, + size_t *size); + #ifdef __cplusplus } #endif diff --git a/src/include/rbd/librbd.hpp b/src/include/rbd/librbd.hpp index bbfb7b1e36b7..5db6f44a37aa 100644 --- a/src/include/rbd/librbd.hpp +++ b/src/include/rbd/librbd.hpp @@ -239,6 +239,10 @@ public: std::vector *snaps, size_t group_snap_info_size); + int namespace_create(IoCtx& ioctx, const char *namespace_name); + int namespace_remove(IoCtx& ioctx, const char *namespace_name); + int namespace_list(IoCtx& io_ctx, std::vector* namespace_names); + private: /* We don't allow assignment or copying */ RBD(const RBD& rhs); diff --git a/src/librbd/CMakeLists.txt b/src/librbd/CMakeLists.txt index 88682ef9c165..768902e55a60 100644 --- a/src/librbd/CMakeLists.txt +++ b/src/librbd/CMakeLists.txt @@ -28,6 +28,7 @@ set(librbd_internal_srcs api/Group.cc api/Image.cc api/Mirror.cc + api/Namespace.cc api/Snapshot.cc cache/ImageWriteback.cc cache/ObjectCacherObjectDispatch.cc diff --git a/src/librbd/api/Namespace.cc b/src/librbd/api/Namespace.cc new file mode 100644 index 000000000000..f73ae845486c --- /dev/null +++ b/src/librbd/api/Namespace.cc @@ -0,0 +1,161 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "common/errno.h" +#include "cls/rbd/cls_rbd_client.h" +#include "librbd/api/Namespace.h" +#include "librbd/ImageCtx.h" + +#define dout_subsys ceph_subsys_rbd +#undef dout_prefix +#define dout_prefix *_dout << "librbd::api::Namespace: " << __func__ << ": " + +namespace librbd { +namespace api { + +template +int Namespace::create(librados::IoCtx& io_ctx, const std::string& name) +{ + CephContext *cct = (CephContext *)io_ctx.cct(); + ldout(cct, 5) << "name=" << name << dendl; + + if (name.empty()) { + return -EINVAL; + } + + librados::IoCtx default_ns_ctx; + default_ns_ctx.dup(io_ctx); + default_ns_ctx.set_namespace(""); + + int r = cls_client::namespace_add(&default_ns_ctx, name); + if (r < 0) { + lderr(cct) << "failed to add namespace: " << cpp_strerror(r) << dendl; + return r; + } + + librados::IoCtx ns_ctx; + ns_ctx.dup(io_ctx); + ns_ctx.set_namespace(name); + + r = cls_client::dir_state_set(&ns_ctx, RBD_DIRECTORY, + cls::rbd::DIRECTORY_STATE_READY); + if (r < 0) { + lderr(cct) << "failed to initialize image directory: " << cpp_strerror(r) + << dendl; + goto rollback; + } + + return 0; + +rollback: + int ret_val = cls_client::namespace_remove(&default_ns_ctx, name); + if (ret_val < 0) { + lderr(cct) << "failed to remove namespace: " << cpp_strerror(r) << dendl; + } + + return r; +} + +template +int Namespace::remove(librados::IoCtx& io_ctx, const std::string& name) +{ + CephContext *cct = (CephContext *)io_ctx.cct(); + ldout(cct, 5) << "name=" << name << dendl; + + if (name.empty()) { + return -EINVAL; + } + + librados::IoCtx default_ns_ctx; + default_ns_ctx.dup(io_ctx); + default_ns_ctx.set_namespace(""); + + librados::IoCtx ns_ctx; + ns_ctx.dup(io_ctx); + ns_ctx.set_namespace(name); + + std::map trash_entries; + + librados::ObjectWriteOperation dir_op; + librbd::cls_client::dir_state_set( + &dir_op, cls::rbd::DIRECTORY_STATE_ADD_DISABLED); + dir_op.remove(); + + int r = ns_ctx.operate(RBD_DIRECTORY, &dir_op); + if (r == -EBUSY) { + ldout(cct, 5) << "image directory not empty" << dendl; + goto rollback; + } else if (r < 0 && r != -ENOENT) { + lderr(cct) << "failed to disable the namespace: " << cpp_strerror(r) + << dendl; + return r; + } + + r = cls_client::trash_list(&ns_ctx, "", 1, &trash_entries); + if (r < 0 && r != -ENOENT) { + lderr(cct) << "failed to list trash directory: " << cpp_strerror(r) + << dendl; + return r; + } else if (!trash_entries.empty()) { + ldout(cct, 5) << "image trash not empty" << dendl; + goto rollback; + } + + r = cls_client::namespace_remove(&default_ns_ctx, name); + if (r < 0) { + lderr(cct) << "failed to remove namespace: " << cpp_strerror(r) << dendl; + return r; + } + + return 0; + +rollback: + + r = librbd::cls_client::dir_state_set( + &ns_ctx, RBD_DIRECTORY, cls::rbd::DIRECTORY_STATE_READY); + if (r < 0) { + lderr(cct) << "failed to restore directory state: " << cpp_strerror(r) + << dendl; + } + + return -EBUSY; +} + +template +int Namespace::list(IoCtx& io_ctx, vector *names) +{ + CephContext *cct = (CephContext *)io_ctx.cct(); + ldout(cct, 5) << dendl; + + librados::IoCtx default_ns_ctx; + default_ns_ctx.dup(io_ctx); + default_ns_ctx.set_namespace(""); + + int r; + int max_read = 1024; + std::string last_read = ""; + do { + std::list name_list; + r = cls_client::namespace_list(&default_ns_ctx, last_read, max_read, + &name_list); + if (r == -ENOENT) { + return 0; + } else if (r < 0) { + lderr(cct) << "error listing namespaces: " << cpp_strerror(r) << dendl; + return r; + } + + names->insert(names->end(), name_list.begin(), name_list.end()); + if (!name_list.empty()) { + last_read = name_list.back(); + } + r = name_list.size(); + } while (r == max_read); + + return 0; +} + +} // namespace api +} // namespace librbd + +template class librbd::api::Namespace; diff --git a/src/librbd/api/Namespace.h b/src/librbd/api/Namespace.h new file mode 100644 index 000000000000..c892a3bc11ef --- /dev/null +++ b/src/librbd/api/Namespace.h @@ -0,0 +1,33 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#ifndef CEPH_LIBRBD_API_NAMESPACE_H +#define CEPH_LIBRBD_API_NAMESPACE_H + +#include "include/rbd/librbd.hpp" +#include +#include + +namespace librados { struct IoCtx; } + +namespace librbd { + +struct ImageCtx; + +namespace api { + +template +struct Namespace { + + static int create(librados::IoCtx& io_ctx, const std::string& name); + static int remove(librados::IoCtx& io_ctx, const std::string& name); + static int list(librados::IoCtx& io_ctx, std::vector* names); + +}; + +} // namespace api +} // namespace librbd + +extern template class librbd::api::Namespace; + +#endif // CEPH_LIBRBD_API_NAMESPACE_H diff --git a/src/librbd/librbd.cc b/src/librbd/librbd.cc index 7bd023d4781b..d46a46f713e8 100644 --- a/src/librbd/librbd.cc +++ b/src/librbd/librbd.cc @@ -30,6 +30,7 @@ #include "librbd/api/Group.h" #include "librbd/api/Image.h" #include "librbd/api/Mirror.h" +#include "librbd/api/Namespace.h" #include "librbd/api/Snapshot.h" #include "librbd/io/AioCompletion.h" #include "librbd/io/ImageRequestWQ.h" @@ -615,6 +616,19 @@ namespace librbd { return r; } + int RBD::namespace_create(IoCtx& io_ctx, const char *namespace_name) { + return librbd::api::Namespace<>::create(io_ctx, namespace_name); + } + + int RBD::namespace_remove(IoCtx& io_ctx, const char *namespace_name) { + return librbd::api::Namespace<>::remove(io_ctx, namespace_name); + } + + int RBD::namespace_list(IoCtx& io_ctx, + std::vector* namespace_names) { + return librbd::api::Namespace<>::list(io_ctx, namespace_names); + } + int RBD::list(IoCtx& io_ctx, vector& names) { TracepointProvider::initialize(get_cct(io_ctx)); @@ -2684,6 +2698,54 @@ extern "C" int rbd_trash_restore(rados_ioctx_t p, const char *id, return r; } +extern "C" int rbd_namespace_create(rados_ioctx_t io, + const char *namespace_name) { + librados::IoCtx io_ctx; + librados::IoCtx::from_rados_ioctx_t(io, io_ctx); + + return librbd::api::Namespace<>::create(io_ctx, namespace_name); +} + +extern "C" int rbd_namespace_remove(rados_ioctx_t io, + const char *namespace_name) { + librados::IoCtx io_ctx; + librados::IoCtx::from_rados_ioctx_t(io, io_ctx); + + return librbd::api::Namespace<>::remove(io_ctx, namespace_name); +} + +extern "C" int rbd_namespace_list(rados_ioctx_t io, char *names, size_t *size) { + librados::IoCtx io_ctx; + librados::IoCtx::from_rados_ioctx_t(io, io_ctx); + + if (names == nullptr || size == nullptr) { + return -EINVAL; + } + + std::vector cpp_names; + int r = librbd::api::Namespace<>::list(io_ctx, &cpp_names); + if (r < 0) { + 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; + return -ERANGE; + } + + for (int i = 0; i < (int)cpp_names.size(); i++) { + const char* name = cpp_names[i].c_str(); + strcpy(names, name); + names += strlen(names) + 1; + } + + return (int)expected_size; +} + extern "C" int rbd_copy(rbd_image_t image, rados_ioctx_t dest_p, const char *destname) { diff --git a/src/test/librbd/test_librbd.cc b/src/test/librbd/test_librbd.cc index d4e17b6d5450..10666fcc0992 100644 --- a/src/test/librbd/test_librbd.cc +++ b/src/test/librbd/test_librbd.cc @@ -6623,6 +6623,57 @@ TEST_F(TestLibRBD, TestSetSnapById) { ASSERT_EQ(0, image.snap_set_by_id(CEPH_NOSNAP)); } +TEST_F(TestLibRBD, Namespaces) { + rados_ioctx_t ioctx; + ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx)); + rados_remove(ioctx, RBD_NAMESPACE); + + ASSERT_EQ(0, rbd_namespace_create(ioctx, "name1")); + ASSERT_EQ(0, rbd_namespace_create(ioctx, "name2")); + ASSERT_EQ(0, rbd_namespace_create(ioctx, "name3")); + ASSERT_EQ(0, rbd_namespace_remove(ioctx, "name2")); + + char names[1024]; + size_t max_size = sizeof(names); + int len = rbd_namespace_list(ioctx, names, &max_size); + + std::vector cpp_names; + for (char* cur_name = names; cur_name < names + len; ) { + cpp_names.push_back(cur_name); + cur_name += strlen(cur_name) + 1; + } + ASSERT_EQ(2U, cpp_names.size()); + ASSERT_EQ("name1", cpp_names[0]); + ASSERT_EQ("name3", cpp_names[1]); + + rados_ioctx_destroy(ioctx); +} + +TEST_F(TestLibRBD, NamespacesPP) { + librados::IoCtx ioctx; + ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx)); + ioctx.remove(RBD_NAMESPACE); + + librbd::RBD rbd; + ASSERT_EQ(-EINVAL, rbd.namespace_create(ioctx, "")); + ASSERT_EQ(-EINVAL, rbd.namespace_remove(ioctx, "")); + + ASSERT_EQ(0, rbd.namespace_create(ioctx, "name1")); + ASSERT_EQ(-EEXIST, rbd.namespace_create(ioctx, "name1")); + ASSERT_EQ(0, rbd.namespace_create(ioctx, "name2")); + ASSERT_EQ(0, rbd.namespace_create(ioctx, "name3")); + ASSERT_EQ(0, rbd.namespace_remove(ioctx, "name2")); + ASSERT_EQ(-ENOENT, rbd.namespace_remove(ioctx, "name2")); + + std::vector names; + ASSERT_EQ(0, rbd.namespace_list(ioctx, &names)); + ASSERT_EQ(2U, names.size()); + + ASSERT_EQ(2U, names.size()); + ASSERT_EQ("name1", names[0]); + ASSERT_EQ("name3", names[1]); +} + // poorman's assert() namespace ceph { void __ceph_assert_fail(const char *assertion, const char *file, int line,