From 366e6075cab2748efab395cd23882eaee4ba402f Mon Sep 17 00:00:00 2001 From: Jason Dillaman Date: Thu, 6 Oct 2016 12:48:22 -0400 Subject: [PATCH] librbd: new API methods to retrieve image id and block name prefix Signed-off-by: Jason Dillaman --- src/include/rbd/librbd.h | 12 +++-- src/include/rbd/librbd.hpp | 3 ++ src/librbd/librbd.cc | 56 ++++++++++++++++++++++ src/pybind/rbd/rbd.pyx | 51 ++++++++++++++++++++ src/test/librbd/test_librbd.cc | 84 +++++++++++++++++++++++++++++++++ src/test/librbd/test_support.cc | 9 +--- src/test/pybind/test_rbd.py | 13 +++-- 7 files changed, 213 insertions(+), 15 deletions(-) diff --git a/src/include/rbd/librbd.h b/src/include/rbd/librbd.h index a27fae8c4cd..9f2e060e650 100644 --- a/src/include/rbd/librbd.h +++ b/src/include/rbd/librbd.h @@ -32,7 +32,7 @@ extern "C" { #define LIBRBD_VER_MAJOR 0 #define LIBRBD_VER_MINOR 1 -#define LIBRBD_VER_EXTRA 10 +#define LIBRBD_VER_EXTRA 11 #define LIBRBD_VERSION(maj, min, extra) ((maj << 16) + (min << 8) + extra) @@ -90,9 +90,9 @@ typedef struct { uint64_t obj_size; uint64_t num_objs; int order; - char block_name_prefix[RBD_MAX_BLOCK_NAME_SIZE]; - int64_t parent_pool; /* deprecated */ - char parent_name[RBD_MAX_IMAGE_NAME_SIZE]; /* deprecated */ + char block_name_prefix[RBD_MAX_BLOCK_NAME_SIZE]; /* deprecated */ + int64_t parent_pool; /* deprecated */ + char parent_name[RBD_MAX_IMAGE_NAME_SIZE]; /* deprecated */ } rbd_image_info_t; typedef enum { @@ -321,6 +321,10 @@ CEPH_RBD_API int rbd_get_stripe_unit(rbd_image_t image, uint64_t *stripe_unit); CEPH_RBD_API int rbd_get_stripe_count(rbd_image_t image, uint64_t *stripe_count); CEPH_RBD_API int rbd_get_overlap(rbd_image_t image, uint64_t *overlap); +CEPH_RBD_API int rbd_get_id(rbd_image_t image, char *id, size_t id_len); +CEPH_RBD_API int rbd_get_block_name_prefix(rbd_image_t image, + char *prefix, size_t prefix_len); +CEPH_RBD_API int64_t rbd_get_data_pool_id(rbd_image_t image); CEPH_RBD_API int rbd_get_parent_info(rbd_image_t image, char *parent_poolname, size_t ppoolnamelen, char *parent_name, size_t pnamelen, diff --git a/src/include/rbd/librbd.hpp b/src/include/rbd/librbd.hpp index 618ce962075..fb5e6d0ebcd 100644 --- a/src/include/rbd/librbd.hpp +++ b/src/include/rbd/librbd.hpp @@ -223,6 +223,9 @@ public: int resize2(uint64_t size, bool allow_shrink, ProgressContext& pctx); int resize_with_progress(uint64_t size, ProgressContext& pctx); int stat(image_info_t &info, size_t infosize); + int get_id(std::string *id); + std::string get_block_name_prefix(); + int64_t get_data_pool_id(); int parent_info(std::string *parent_poolname, std::string *parent_name, std::string *parent_snapname); int old_format(uint8_t *old); diff --git a/src/librbd/librbd.cc b/src/librbd/librbd.cc index ebc656a7a9d..52ee192a13e 100644 --- a/src/librbd/librbd.cc +++ b/src/librbd/librbd.cc @@ -782,6 +782,28 @@ namespace librbd { return r; } + int Image::get_id(std::string *id) + { + ImageCtx *ictx = reinterpret_cast(ctx); + if (ictx->old_format) { + return -EINVAL; + } + *id = ictx->id; + return 0; + } + + std::string Image::get_block_name_prefix() + { + ImageCtx *ictx = reinterpret_cast(ctx); + return ictx->object_prefix; + } + + int64_t Image::get_data_pool_id() + { + ImageCtx *ictx = reinterpret_cast(ctx); + return ictx->data_ctx.get_id(); + } + int Image::parent_info(string *parent_pool_name, string *parent_name, string *parent_snap_name) { @@ -2196,6 +2218,40 @@ extern "C" int rbd_get_overlap(rbd_image_t image, uint64_t *overlap) return r; } +extern "C" int rbd_get_id(rbd_image_t image, char *id, size_t id_len) +{ + librbd::ImageCtx *ictx = reinterpret_cast(image); + if (ictx->old_format) { + return -EINVAL; + } + if (ictx->id.size() >= id_len) { + return -ERANGE; + } + + strncpy(id, ictx->id.c_str(), id_len - 1); + id[id_len - 1] = '\0'; + return 0; +} + +extern "C" int rbd_get_block_name_prefix(rbd_image_t image, char *prefix, + size_t prefix_len) +{ + librbd::ImageCtx *ictx = reinterpret_cast(image); + if (ictx->object_prefix.size() >= prefix_len) { + return -ERANGE; + } + + strncpy(prefix, ictx->object_prefix.c_str(), prefix_len - 1); + prefix[prefix_len - 1] = '\0'; + return 0; +} + +extern "C" int64_t rbd_get_data_pool_id(rbd_image_t image) +{ + librbd::ImageCtx *ictx = reinterpret_cast(image); + return ictx->data_ctx.get_id(); +} + extern "C" int rbd_get_parent_info(rbd_image_t image, char *parent_pool_name, size_t ppool_namelen, char *parent_name, size_t pnamelen, char *parent_snap_name, size_t psnap_namelen) diff --git a/src/pybind/rbd/rbd.pyx b/src/pybind/rbd/rbd.pyx index b73923a43d9..5f570337130 100644 --- a/src/pybind/rbd/rbd.pyx +++ b/src/pybind/rbd/rbd.pyx @@ -200,6 +200,9 @@ cdef extern from "rbd/librbd.h" nogil: int rbd_get_stripe_unit(rbd_image_t image, uint64_t *stripe_unit) int rbd_get_stripe_count(rbd_image_t image, uint64_t *stripe_count) int rbd_get_overlap(rbd_image_t image, uint64_t *overlap) + int rbd_get_id(rbd_image_t image, char *id, size_t id_len) + int rbd_get_block_name_prefix(rbd_image_t image, char *prefix, + size_t prefix_len) int rbd_get_parent_info(rbd_image_t image, char *parent_poolname, size_t ppoolnamelen, char *parent_name, size_t pnamelen, @@ -1313,6 +1316,54 @@ cdef class Image(object): 'parent_name' : info.parent_name } + def id(self): + """ + Get the RBD v2 internal image id + + :returns: str - image id + """ + cdef: + int ret = -errno.ERANGE + size_t size = 32 + char *image_id = NULL + try: + while ret == -errno.ERANGE and size <= 4096: + image_id = realloc_chk(image_id, size) + with nogil: + ret = rbd_get_id(self.image, image_id, size) + if ret == -errno.ERANGE: + size *= 2 + + if ret != 0: + raise make_ex(ret, 'error getting id for image %s' % (self.name,)) + return decode_cstr(image_id) + finally: + free(image_id) + + def block_name_prefix(self): + """ + Get the RBD block name prefix + + :returns: str - block name prefix + """ + cdef: + int ret = -errno.ERANGE + size_t size = 32 + char *prefix = NULL + try: + while ret == -errno.ERANGE and size <= 4096: + prefix = realloc_chk(prefix, size) + with nogil: + ret = rbd_get_block_name_prefix(self.image, prefix, size) + if ret == -errno.ERANGE: + size *= 2 + + if ret != 0: + raise make_ex(ret, 'error getting block name prefix for image %s' % (self.name,)) + return decode_cstr(prefix) + finally: + free(prefix) + def parent_info(self): """ Get information about a cloned image's parent (if any) diff --git a/src/test/librbd/test_librbd.cc b/src/test/librbd/test_librbd.cc index 5da8c80bc25..9edcb839fb0 100644 --- a/src/test/librbd/test_librbd.cc +++ b/src/test/librbd/test_librbd.cc @@ -277,6 +277,90 @@ TEST_F(TestLibRBD, CreateAndStatPP) ioctx.close(); } +TEST_F(TestLibRBD, GetId) +{ + rados_ioctx_t ioctx; + ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx)); + + rbd_image_t image; + int order = 0; + std::string name = get_temp_image_name(); + + ASSERT_EQ(0, create_image(ioctx, name.c_str(), 0, &order)); + ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL)); + + char id[4096]; + if (!is_feature_enabled(0)) { + // V1 image + ASSERT_EQ(-EINVAL, rbd_get_id(image, id, sizeof(id))); + } else { + ASSERT_EQ(-ERANGE, rbd_get_id(image, id, 0)); + ASSERT_EQ(0, rbd_get_id(image, id, sizeof(id))); + ASSERT_LT(0U, strlen(id)); + } + + ASSERT_EQ(0, rbd_close(image)); + rados_ioctx_destroy(ioctx); +} + +TEST_F(TestLibRBD, GetIdPP) +{ + librados::IoCtx ioctx; + ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx)); + + librbd::RBD rbd; + librbd::Image image; + int order = 0; + std::string name = get_temp_image_name(); + + std::string id; + ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), 0, &order)); + ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL)); + if (!is_feature_enabled(0)) { + // V1 image + ASSERT_EQ(-EINVAL, image.get_id(&id)); + } else { + ASSERT_EQ(0, image.get_id(&id)); + ASSERT_LT(0U, id.size()); + } +} + +TEST_F(TestLibRBD, GetBlockNamePrefix) +{ + rados_ioctx_t ioctx; + ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx)); + + rbd_image_t image; + int order = 0; + std::string name = get_temp_image_name(); + + ASSERT_EQ(0, create_image(ioctx, name.c_str(), 0, &order)); + ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL)); + + char prefix[4096]; + ASSERT_EQ(-ERANGE, rbd_get_block_name_prefix(image, prefix, 0)); + ASSERT_EQ(0, rbd_get_block_name_prefix(image, prefix, sizeof(prefix))); + ASSERT_LT(0U, strlen(prefix)); + + ASSERT_EQ(0, rbd_close(image)); + rados_ioctx_destroy(ioctx); +} + +TEST_F(TestLibRBD, GetBlockNamePrefixPP) +{ + librados::IoCtx ioctx; + ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx)); + + librbd::RBD rbd; + librbd::Image image; + int order = 0; + std::string name = get_temp_image_name(); + + ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), 0, &order)); + ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL)); + ASSERT_LT(0U, image.get_block_name_prefix().size()); +} + TEST_F(TestLibRBD, OpenAio) { rados_ioctx_t ioctx; diff --git a/src/test/librbd/test_support.cc b/src/test/librbd/test_support.cc index 5b5adf3d2d3..e9f63bd2cda 100644 --- a/src/test/librbd/test_support.cc +++ b/src/test/librbd/test_support.cc @@ -41,17 +41,10 @@ int create_image_pp(librbd::RBD &rbd, librados::IoCtx &ioctx, int get_image_id(librbd::Image &image, std::string *image_id) { - librbd::image_info_t info; - int r = image.stat(info, sizeof(info)); + int r = image.get_id(image_id); if (r < 0) { return r; } - - char prefix[RBD_MAX_BLOCK_NAME_SIZE + 1]; - strncpy(prefix, info.block_name_prefix, RBD_MAX_BLOCK_NAME_SIZE); - prefix[RBD_MAX_BLOCK_NAME_SIZE] = '\0'; - - *image_id = std::string(prefix + strlen(RBD_DATA_PREFIX)); return 0; } diff --git a/src/test/pybind/test_rbd.py b/src/test/pybind/test_rbd.py index 414374c583d..f637c8a0aba 100644 --- a/src/test/pybind/test_rbd.py +++ b/src/test/pybind/test_rbd.py @@ -6,7 +6,7 @@ import time import sys from nose import with_setup, SkipTest -from nose.tools import eq_ as eq, assert_raises +from nose.tools import eq_ as eq, assert_raises, assert_not_equal from rados import (Rados, LIBRADOS_OP_FLAG_FADVISE_DONTNEED, LIBRADOS_OP_FLAG_FADVISE_NOCACHE, @@ -191,14 +191,14 @@ def test_create_defaults(): check_default_params(2, 20, RBD_FEATURE_STRIPINGV2, 1, 1 << 16) check_default_params(2, 20, RBD_FEATURE_STRIPINGV2, 10, 1 << 20) check_default_params(2, 20, RBD_FEATURE_STRIPINGV2, 10, 1 << 16) - check_default_params(2, 20, RBD_FEATURE_STRIPINGV2, 0, 0) + check_default_params(2, 20, 0, 0, 0) # make sure invalid combinations of stripe unit and order are still invalid check_default_params(2, 22, RBD_FEATURE_STRIPINGV2, 10, 1 << 50, exception=InvalidArgument) check_default_params(2, 22, RBD_FEATURE_STRIPINGV2, 10, 100, exception=InvalidArgument) check_default_params(2, 22, RBD_FEATURE_STRIPINGV2, 0, 1, exception=InvalidArgument) check_default_params(2, 22, RBD_FEATURE_STRIPINGV2, 1, 0, exception=InvalidArgument) # 0 stripe unit and count are still ignored - check_default_params(2, 22, RBD_FEATURE_STRIPINGV2, 0, 0) + check_default_params(2, 22, 0, 0, 0) def test_context_manager(): with Rados(conffile='') as cluster: @@ -317,6 +317,13 @@ class TestImage(object): image.close() RBD().remove(ioctx, image_name) + @require_new_format() + def test_id(self): + assert_not_equal(b'', self.image.id()) + + def test_block_name_prefix(self): + assert_not_equal(b'', self.image.block_name_prefix()) + def test_invalidate_cache(self): self.image.write(b'abc', 0) eq(b'abc', self.image.read(0, 3)) -- 2.39.5