From 05295eff568aec5ff9f5d01bb73b7c7bd1dee581 Mon Sep 17 00:00:00 2001 From: Jason Dillaman Date: Thu, 6 Oct 2016 12:48:22 -0400 Subject: [PATCH 1/2] librbd: new API methods to retrieve image id and block name prefix Signed-off-by: Jason Dillaman (cherry picked from commit 366e6075cab2748efab395cd23882eaee4ba402f) --- 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 c6364946cc485..418e121e5eede 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) @@ -86,9 +86,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 { @@ -287,6 +287,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 4dd4e6b991c9e..81179b586b115 100644 --- a/src/include/rbd/librbd.hpp +++ b/src/include/rbd/librbd.hpp @@ -197,6 +197,9 @@ class CEPH_RBD_API Image int resize(uint64_t size); 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 2d6d80c7f1856..e1114f3e2b190 100644 --- a/src/librbd/librbd.cc +++ b/src/librbd/librbd.cc @@ -678,6 +678,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) { @@ -2024,6 +2046,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 5dadc37b72a97..7755c3b9e9674 100644 --- a/src/pybind/rbd/rbd.pyx +++ b/src/pybind/rbd/rbd.pyx @@ -190,6 +190,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, @@ -1126,6 +1129,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 ff91f25564d83..cc180681efbbc 100644 --- a/src/test/librbd/test_librbd.cc +++ b/src/test/librbd/test_librbd.cc @@ -276,6 +276,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 5b5adf3d2d387..e9f63bd2cda33 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 386087dc8aa66..f1b4a433328c4 100644 --- a/src/test/pybind/test_rbd.py +++ b/src/test/pybind/test_rbd.py @@ -5,7 +5,7 @@ import time 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, @@ -190,14 +190,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: @@ -315,6 +315,13 @@ def test_create_with_params(self): 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)) From aa8e57d0d4fa855ec6b2201274dd78504ab9e5c9 Mon Sep 17 00:00:00 2001 From: Jason Dillaman Date: Thu, 6 Oct 2016 12:56:31 -0400 Subject: [PATCH 2/2] rbd: utilize new API methods for image id and block name prefix Signed-off-by: Jason Dillaman (cherry picked from commit 0a0a88c71552aa5858384fa802a3161da90e7c86) Conflicts: src/tools/rbd/action/Info.cc (jewel does not have 653bc453e3c8f1062cdbc4d0d8f77f623f48915b) --- src/tools/rbd/Utils.cc | 13 ++++--------- src/tools/rbd/action/Info.cc | 4 +--- src/tools/rbd/action/Status.cc | 14 +++++--------- src/tools/rbd/action/Watch.cc | 12 +++--------- 4 files changed, 13 insertions(+), 30 deletions(-) diff --git a/src/tools/rbd/Utils.cc b/src/tools/rbd/Utils.cc index bc67f5dfa2899..618d257a463ae 100644 --- a/src/tools/rbd/Utils.cc +++ b/src/tools/rbd/Utils.cc @@ -644,17 +644,12 @@ int snap_set(librbd::Image &image, const std::string &snap_name) { } std::string image_id(librbd::Image& image) { - librbd::image_info_t info; - int r = image.stat(info, sizeof(info)); + std::string id; + int r = image.get_id(&id); if (r < 0) { - return string(); + return std::string(); } - - 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'; - - return string(prefix + strlen(RBD_DATA_PREFIX)); + return id; } std::string mirror_image_state(librbd::mirror_image_state_t state) { diff --git a/src/tools/rbd/action/Info.cc b/src/tools/rbd/action/Info.cc index 8e31e45028da0..3be863a2a1f23 100644 --- a/src/tools/rbd/action/Info.cc +++ b/src/tools/rbd/action/Info.cc @@ -108,9 +108,7 @@ static int do_show_info(const char *imgname, librbd::Image& image, } } - 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'; + std::string prefix = image.get_block_name_prefix(); if (f) { f->open_object_section("image"); diff --git a/src/tools/rbd/action/Status.cc b/src/tools/rbd/action/Status.cc index ab37bc8644c1b..a6944f0d1a571 100644 --- a/src/tools/rbd/action/Status.cc +++ b/src/tools/rbd/action/Status.cc @@ -20,7 +20,6 @@ namespace po = boost::program_options; static int do_show_status(librados::IoCtx &io_ctx, librbd::Image &image, const char *imgname, Formatter *f) { - librbd::image_info_t info; uint8_t old_format; int r; std::string header_oid; @@ -34,16 +33,13 @@ static int do_show_status(librados::IoCtx &io_ctx, librbd::Image &image, header_oid = imgname; header_oid += RBD_SUFFIX; } else { - r = image.stat(info, sizeof(info)); - if (r < 0) + std::string id; + r = image.get_id(&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'; - - header_oid = RBD_HEADER_PREFIX; - header_oid.append(prefix + strlen(RBD_DATA_PREFIX)); + header_oid = RBD_HEADER_PREFIX + id; } r = io_ctx.list_watchers(header_oid, &watchers); diff --git a/src/tools/rbd/action/Watch.cc b/src/tools/rbd/action/Watch.cc index 65be93d6dea88..80caeeee463b6 100644 --- a/src/tools/rbd/action/Watch.cc +++ b/src/tools/rbd/action/Watch.cc @@ -61,19 +61,13 @@ static int do_watch(librados::IoCtx& pp, librbd::Image &image, if (old_format != 0) { header_oid = std::string(imgname) + RBD_SUFFIX; } else { - librbd::image_info_t info; - r = image.stat(info, sizeof(info)); + std::string id; + r = image.get_id(&id); if (r < 0) { - std::cerr << "failed to stat image" << std::endl; 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'; - - std::string image_id(prefix + strlen(RBD_DATA_PREFIX)); - header_oid = RBD_HEADER_PREFIX + image_id; + header_oid = RBD_HEADER_PREFIX + id; } uint64_t cookie;