]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
librbd: Implement consistency group images operations
authorVictor Denisov <denisovenator@gmail.com>
Fri, 24 Jun 2016 23:19:46 +0000 (16:19 -0700)
committerVictor Denisov <denisovenator@gmail.com>
Sat, 6 Aug 2016 02:09:28 +0000 (19:09 -0700)
Signed-off-by: Victor Denisov <denisovenator@gmail.com>
13 files changed:
src/include/rbd/librbd.h
src/include/rbd/librbd.hpp
src/librbd/ImageCtx.h
src/librbd/image/RefreshRequest.cc
src/librbd/image/RefreshRequest.h
src/librbd/internal.cc
src/librbd/internal.h
src/librbd/librbd.cc
src/test/librbd/image/test_mock_RefreshRequest.cc
src/test/librbd/mock/MockImageCtx.h
src/test/librbd/test_ConsistencyGroups.cc
src/test/librbd/test_librbd.cc
src/tracing/librbd.tp

index c505a4b1be688b1f47bffd9bdd56091d11ff9266..700e6d6b3036c50a77e4c83084675a1495460e61 100644 (file)
@@ -138,6 +138,26 @@ typedef struct {
   bool up;
 } rbd_mirror_image_status_t;
 
+typedef enum {
+  GROUP_IMAGE_STATE_ATTACHED,
+  GROUP_IMAGE_STATE_INCOMPLETE
+} rbd_group_image_state_t;
+
+typedef struct {
+  char *name;
+  int64_t pool;
+} rbd_group_image_spec_t;
+
+typedef struct {
+  rbd_group_image_spec_t spec;
+  rbd_group_image_state_t state;
+} rbd_group_image_status_t;
+
+typedef struct {
+  char *name;
+  int64_t pool;
+} rbd_group_spec_t;
+
 CEPH_RBD_API void rbd_version(int *major, int *minor, int *extra);
 
 /* image options */
@@ -697,6 +717,26 @@ CEPH_RBD_API int rbd_update_watch(rbd_image_t image, uint64_t *handle,
 CEPH_RBD_API int rbd_update_unwatch(rbd_image_t image, uint64_t handle);
 
 
+CEPH_RBD_API int rbd_group_image_add(
+                               rados_ioctx_t group_p, const char *group_name,
+                               rados_ioctx_t image_p, const char *image_name);
+CEPH_RBD_API int rbd_group_image_remove(
+                               rados_ioctx_t group_p, const char *group_name,
+                               rados_ioctx_t image_p, const char *image_name);
+CEPH_RBD_API int rbd_group_image_list(
+                                 rados_ioctx_t group_p, const char *group_name,
+                                 rbd_group_image_status_t *images,
+                                 size_t *image_size);
+CEPH_RBD_API int rbd_image_get_group(rados_ioctx_t image_p,
+                                    const char *image_name,
+                                    rbd_group_spec_t *group_spec);
+CEPH_RBD_API void rbd_group_spec_cleanup(rbd_group_spec_t *group_spec);
+CEPH_RBD_API void rbd_group_image_status_cleanup(
+                                               rbd_group_image_status_t *image
+                                               );
+CEPH_RBD_API void rbd_group_image_status_list_cleanup(
+                                             rbd_group_image_status_t *images,
+                                             size_t len);
 #ifdef __cplusplus
 }
 #endif
index 57ccb98747de7bee46dd87b030ca4faf1926bf92..4e9b7a6fbdd1b8f40ce8b909c02c62fcf56190ad 100644 (file)
@@ -71,6 +71,19 @@ namespace librbd {
     bool up;
   } mirror_image_status_t;
 
+  typedef rbd_group_image_state_t group_image_state_t;
+
+  typedef struct {
+    std::string name;
+    int64_t pool;
+    group_image_state_t state;
+  } group_image_status_t;
+
+  typedef struct {
+    std::string name;
+    int64_t pool;
+  } group_spec_t;
+
   typedef rbd_image_info_t image_info_t;
 
   class CEPH_RBD_API ProgressContext
@@ -153,6 +166,13 @@ public:
   int group_remove(IoCtx& io_ctx, const char *group_name);
   int group_list(IoCtx& io_ctx, std::vector<std::string>& names);
 
+  int group_image_add(IoCtx& io_ctx, const char *group_name,
+                     IoCtx& image_io_ctx, const char *image_name);
+  int group_image_remove(IoCtx& io_ctx, const char *group_name,
+                        IoCtx& image_io_ctx, const char *image_name);
+  int group_image_list(IoCtx& io_ctx, const char *group_name,
+                      std::vector<group_image_status_t>& images);
+
 private:
   /* We don't allow assignment or copying */
   RBD(const RBD& rhs);
@@ -207,6 +227,7 @@ public:
                      std::string *parent_snapname);
   int old_format(uint8_t *old);
   int size(uint64_t *size);
+  int get_group(group_spec_t *group_spec);
   int features(uint64_t *features);
   int update_features(uint64_t features, bool enabled);
   int overlap(uint64_t *overlap);
index 51d7a94af890b994bc5e66a61c7e65c232b1ea92..d7e6280bfe65152f4e4b281cd209ebcd7cdee9ab 100644 (file)
@@ -119,6 +119,7 @@ namespace librbd {
     std::string id; // only used for new-format images
     parent_info parent_md;
     ImageCtx *parent;
+    cls::rbd::GroupSpec group_spec;
     uint64_t stripe_unit, stripe_count;
     uint64_t flags;
 
index fdab92b6027a323c42c665edd8b1c7e332ebf73f..dc23ca63b0b456e7c06a525cd1fd5d2baff7b957 100644 (file)
@@ -249,7 +249,8 @@ Context *RefreshRequest<I>::handle_v2_get_mutable_metadata(int *result) {
                                                       &m_lockers,
                                                       &m_exclusive_locked,
                                                       &m_lock_tag, &m_snapc,
-                                                      &m_parent_md);
+                                                      &m_parent_md,
+                                                     &m_group_spec);
   }
   if (*result < 0) {
     lderr(cct) << "failed to retrieve mutable metadata: "
@@ -865,6 +866,8 @@ void RefreshRequest<I>::apply() {
       m_image_ctx.parent_md = m_parent_md;
     }
 
+     m_image_ctx.group_spec = m_group_spec;
+
     for (size_t i = 0; i < m_snapc.snaps.size(); ++i) {
       std::vector<librados::snap_t>::const_iterator it = std::find(
         m_image_ctx.snaps.begin(), m_image_ctx.snaps.end(),
index 79b5d9e816d2ed98e30686982f9f5dbc7b4926f5..33e6d0bcca03196339d3e20046d55ac6b8368103 100644 (file)
@@ -116,6 +116,7 @@ private:
   uint64_t m_flags;
   std::string m_object_prefix;
   parent_info m_parent_md;
+  cls::rbd::GroupSpec m_group_spec;
 
   ::SnapContext m_snapc;
   std::vector<std::string> m_snap_names;
index e1ad623787d5d4eeb5ddeb14b37f25f3749ca7fc..c97643fe200fb6fc071885462d67c8ef4192f50d 100644 (file)
@@ -16,6 +16,7 @@
 #include "include/stringify.h"
 
 #include "cls/rbd/cls_rbd.h"
+#include "cls/rbd/cls_rbd_types.h"
 #include "cls/rbd/cls_rbd_client.h"
 #include "cls/journal/cls_journal_types.h"
 #include "cls/journal/cls_journal_client.h"
@@ -2222,6 +2223,15 @@ int mirror_image_disable_internal(ImageCtx *ictx, bool force,
         return -EBUSY;
       }
 
+      cls::rbd::GroupSpec s;
+      r = cls_client::image_get_group(&io_ctx, header_oid, s);
+      if (s.is_valid()) {
+       lderr(cct) << "image is in a consistency group - not removing" << dendl;
+       ictx->owner_lock.put_read();
+       ictx->state->close();
+       return -EMLINK;
+      }
+
       trim_image(ictx, 0, prog_ctx);
 
       ictx->parent_lock.get_read();
@@ -3938,9 +3948,27 @@ int mirror_image_disable_internal(ImageCtx *ictx, bool force,
     CephContext *cct((CephContext *)io_ctx.cct());
     ldout(cct, 20) << "group_remove " << &io_ctx << " " << group_name << dendl;
 
+    std::vector<group_image_status_t> images;
+    int r = group_image_list(io_ctx, group_name, images);
+    if (r < 0 && r != -ENOENT) {
+      lderr(cct) << "error listing group images" << dendl;
+      return r;
+    }
+
+    for (auto i : images) {
+      librados::Rados rados(io_ctx);
+      IoCtx image_ioctx;
+      rados.ioctx_create2(i.pool, image_ioctx);
+      r = group_image_remove(io_ctx, group_name, image_ioctx, i.name.c_str());
+      if (r < 0 && r != -ENOENT) {
+       lderr(cct) << "error removing image from a group" << dendl;
+       return r;
+      }
+    }
+
     std::string group_id;
-    int r = cls_client::dir_get_id(&io_ctx, RBD_GROUP_DIRECTORY,
-                              std::string(group_name), &group_id);
+    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;
@@ -3991,4 +4019,239 @@ int mirror_image_disable_internal(ImageCtx *ictx, bool force,
 
     return 0;
   }
+
+  int group_image_add(librados::IoCtx& group_ioctx, const char *group_name,
+                     librados::IoCtx& image_ioctx, const char *image_name)
+  {
+    CephContext *cct = (CephContext *)group_ioctx.cct();
+    ldout(cct, 20) << "group_image_add " << &group_ioctx
+                   << " group name " << group_name << " image "
+                  << &image_ioctx << " name " << image_name << dendl;
+
+    string group_id;
+
+    int r = cls_client::dir_get_id(&group_ioctx, RBD_GROUP_DIRECTORY, group_name, &group_id);
+    if (r < 0) {
+      lderr(cct) << "error reading consistency group id object: "
+                 << cpp_strerror(r)
+                << dendl;
+      return r;
+    }
+    string group_header_oid = util::group_header_name(group_id);
+
+
+    ldout(cct, 20) << "adding image to group name " << group_name
+                   << " group id " << group_header_oid << dendl;
+
+    string image_id;
+
+    r = cls_client::dir_get_id(&image_ioctx, RBD_DIRECTORY, image_name, &image_id);
+    if (r < 0) {
+      lderr(cct) << "error reading image id object: "
+                << cpp_strerror(-r) << dendl;
+      return r;
+    }
+
+    string image_header_oid = util::header_name(image_id);
+
+    ldout(cct, 20) << "adding image " << image_name
+                   << " image id " << image_header_oid << dendl;
+
+    cls::rbd::GroupImageStatus incomplete_st(image_id, image_ioctx.get_id(),
+                                 cls::rbd::GROUP_IMAGE_LINK_STATE_INCOMPLETE);
+    cls::rbd::GroupImageStatus attached_st(image_id, image_ioctx.get_id(),
+                                   cls::rbd::GROUP_IMAGE_LINK_STATE_ATTACHED);
+
+    r = cls_client::group_image_set(&group_ioctx, group_header_oid,
+                                   incomplete_st);
+
+    cls::rbd::GroupSpec group_spec(group_id, group_ioctx.get_id());
+
+    if (r < 0) {
+      lderr(cct) << "error adding image reference to consistency group: "
+                << cpp_strerror(-r) << dendl;
+      return r;
+    }
+
+    r = cls_client::image_add_group(&image_ioctx, image_header_oid,
+                                          group_spec);
+    if (r < 0) {
+      lderr(cct) << "error adding group reference to image: "
+                << cpp_strerror(-r) << dendl;
+      cls::rbd::GroupImageSpec spec(image_id, image_ioctx.get_id());
+      cls_client::group_image_remove(&group_ioctx, group_header_oid, spec);
+      // Ignore errors in the clean up procedure.
+      return r;
+    }
+
+    r = cls_client::group_image_set(&group_ioctx, group_header_oid,
+                                   attached_st);
+
+    return r;
+  }
+
+  int group_image_remove(librados::IoCtx& group_ioctx, const char *group_name,
+                        librados::IoCtx& image_ioctx, const char *image_name)
+  {
+    CephContext *cct = (CephContext *)group_ioctx.cct();
+    ldout(cct, 20) << "group_remove_image " << &group_ioctx
+                   << " group name " << group_name << " image "
+                  << &image_ioctx << " name " << image_name << dendl;
+
+    string group_id;
+
+    int r = cls_client::dir_get_id(&group_ioctx, RBD_GROUP_DIRECTORY, group_name, &group_id);
+    if (r < 0) {
+      lderr(cct) << "error reading consistency group id object: "
+                 << cpp_strerror(r)
+                << dendl;
+      return r;
+    }
+    string group_header_oid = util::group_header_name(group_id);
+
+    ldout(cct, 20) << "adding image to group name " << group_name
+                   << " group id " << group_header_oid << dendl;
+
+    string image_id;
+    r = cls_client::dir_get_id(&image_ioctx, RBD_DIRECTORY, image_name, &image_id);
+    if (r < 0) {
+      lderr(cct) << "error reading image id object: "
+                << cpp_strerror(-r) << dendl;
+      return r;
+    }
+
+    string image_header_oid = util::header_name(image_id);
+
+    ldout(cct, 20) << "removing image " << image_name
+                   << " image id " << image_header_oid << dendl;
+
+    cls::rbd::GroupSpec group_spec(group_id, group_ioctx.get_id());
+
+    cls::rbd::GroupImageStatus incomplete_st(image_id, image_ioctx.get_id(),
+                                 cls::rbd::GROUP_IMAGE_LINK_STATE_INCOMPLETE);
+
+    cls::rbd::GroupImageSpec spec(image_id, image_ioctx.get_id());
+
+    r = cls_client::group_image_set(&group_ioctx, group_header_oid,
+                                   incomplete_st);
+
+    if (r < 0) {
+      lderr(cct) << "couldn't put image into removing state: "
+                << cpp_strerror(-r) << dendl;
+      return r;
+    }
+
+    r = cls_client::image_remove_group(&image_ioctx, image_header_oid,
+                                      group_spec);
+    if ((r < 0) && (r != -ENOENT)) {
+      lderr(cct) << "couldn't remove group reference from image"
+                << cpp_strerror(-r) << dendl;
+      return r;
+    }
+
+    r = cls_client::group_image_remove(&group_ioctx, group_header_oid, spec);
+    if (r < 0) {
+      lderr(cct) << "couldn't remove image from group"
+                << cpp_strerror(-r) << dendl;
+      return r;
+    }
+
+    return 0;
+  }
+
+  int group_image_list(librados::IoCtx& group_ioctx,
+                      const char *group_name,
+                      std::vector<group_image_status_t>& images)
+  {
+    CephContext *cct = (CephContext *)group_ioctx.cct();
+    ldout(cct, 20) << "group_image_list " << &group_ioctx
+                   << " group name " << group_name << dendl;
+
+    string group_id;
+
+    int r = cls_client::dir_get_id(&group_ioctx, RBD_GROUP_DIRECTORY,
+                                  group_name, &group_id);
+    if (r < 0) {
+      lderr(cct) << "error reading consistency group id object: "
+                 << cpp_strerror(r)
+                << dendl;
+      return r;
+    }
+    string group_header_oid = util::group_header_name(group_id);
+
+    ldout(cct, 20) << "listing images in group name "
+                   << group_name << " group id " << group_header_oid << dendl;
+
+    std::vector<cls::rbd::GroupImageStatus> image_ids;
+
+    const int max_read = 1024;
+    do {
+      std::vector<cls::rbd::GroupImageStatus> image_ids_page;
+      cls::rbd::GroupImageSpec start_last;
+
+      r = cls_client::group_image_list(&group_ioctx, group_header_oid,
+         start_last, max_read, image_ids_page);
+
+      if (r < 0) {
+       lderr(cct) << "error reading image list from consistency group: "
+         << cpp_strerror(-r) << dendl;
+       return r;
+      }
+      image_ids.insert(image_ids.end(),
+                      image_ids_page.begin(), image_ids_page.end());
+
+      if (image_ids_page.size() > 0)
+       start_last = image_ids_page.rbegin()->spec;
+
+      r = image_ids_page.size();
+    } while (r == max_read);
+
+    for (auto i : image_ids) {
+      librados::Rados rados(group_ioctx);
+      IoCtx ioctx;
+      rados.ioctx_create2(i.spec.pool_id, ioctx);
+      std::string image_name;
+      r = cls_client::dir_get_name(&ioctx, RBD_DIRECTORY,
+                                   i.spec.image_id, &image_name);
+      if (r < 0) {
+        return r;
+      }
+
+      images.push_back(
+         group_image_status_t {
+            image_name,
+            i.spec.pool_id,
+            static_cast<group_image_state_t>(i.state)});
+    }
+
+    return 0;
+  }
+
+  int image_get_group(ImageCtx *ictx, group_spec_t *group_spec)
+  {
+    int r = ictx->state->refresh_if_required();
+    if (r < 0)
+      return r;
+
+    if (-1 != ictx->group_spec.pool_id) {
+      librados::Rados rados(ictx->md_ctx);
+      IoCtx ioctx;
+      rados.ioctx_create2(ictx->group_spec.pool_id, ioctx);
+
+      std::string group_name;
+      r = cls_client::dir_get_name(&ioctx, RBD_GROUP_DIRECTORY,
+                                  ictx->group_spec.group_id, &group_name);
+      if (r < 0)
+       return r;
+      group_spec->pool = ictx->group_spec.pool_id;
+      group_spec->name = group_name;
+    } else {
+      group_spec->pool = -1;
+      group_spec->name = "";
+    }
+
+    return 0;
+  }
+
+
 }
index e73d1d01785e5248d4a6fd8d6661d941a52b748d..472f12c4628bdedcc33656b5dc78c8f3e1182205 100644 (file)
@@ -226,6 +226,13 @@ namespace librbd {
   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);
+  int group_image_add(librados::IoCtx& group_ioctx, const char *group_name,
+                     librados::IoCtx& image_ioctx, const char *image_name);
+  int group_image_remove(librados::IoCtx& group_ioctx, const char *group_name,
+                        librados::IoCtx& image_ioctx, const char *image_name);
+  int group_image_list(librados::IoCtx& group_ioctx, const char *group_name,
+                      std::vector<group_image_status_t>& images);
+  int image_get_group(ImageCtx *ictx, group_spec_t *group_spec);
 }
 
 #endif
index 094beaa4d9badd1fc6683bba5b043fc5f4e5bedc..9d91a8a56e06607cf80e323a429b9c02a5d75687 100644 (file)
@@ -141,6 +141,19 @@ struct C_UpdateWatchCB : public librbd::UpdateWatchCtx {
   }
 };
 
+void group_image_status_cpp_to_c(const librbd::group_image_status_t &cpp_status,
+                                rbd_group_image_status_t *c_status) {
+  c_status->spec.name = strdup(cpp_status.name.c_str());
+  c_status->spec.pool = cpp_status.pool;
+  c_status->state = cpp_status.state;
+}
+
+void group_spec_cpp_to_c(const librbd::group_spec_t &cpp_spec,
+                        rbd_group_spec_t *c_spec) {
+  c_spec->name = strdup(cpp_spec.name.c_str());
+  c_spec->pool = cpp_spec.pool;
+}
+
 void mirror_image_info_cpp_to_c(const librbd::mirror_image_info_t &cpp_info,
                                rbd_mirror_image_info_t *c_info) {
   c_info->global_id = strdup(cpp_info.global_id.c_str());
@@ -483,6 +496,42 @@ namespace librbd {
     return r;
   }
 
+  int RBD::group_image_add(IoCtx& group_ioctx, const char *group_name,
+                           IoCtx& image_ioctx, const char *image_name)
+  {
+    TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
+    tracepoint(librbd, group_image_add_enter, group_ioctx.get_pool_name().c_str(),
+              group_ioctx.get_id(), group_name, image_ioctx.get_pool_name().c_str(),
+              image_ioctx.get_id(), image_name);
+    int r = librbd::group_image_add(group_ioctx, group_name, image_ioctx, image_name);
+    tracepoint(librbd, group_image_add_exit, r);
+    return r;
+  }
+
+  int RBD::group_image_remove(IoCtx& group_ioctx, const char *group_name,
+                              IoCtx& image_ioctx, const char *image_name)
+  {
+    TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
+    tracepoint(librbd, group_image_remove_enter, group_ioctx.get_pool_name().c_str(),
+              group_ioctx.get_id(), group_name, image_ioctx.get_pool_name().c_str(),
+              image_ioctx.get_id(), image_name);
+    int r = librbd::group_image_remove(group_ioctx, group_name, image_ioctx, image_name);
+    tracepoint(librbd, group_image_remove_exit, r);
+    return r;
+  }
+
+  int RBD::group_image_list(IoCtx& group_ioctx, const char *group_name,
+                            std::vector<group_image_status_t>& images)
+  {
+    TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
+    tracepoint(librbd, group_image_list_enter, group_ioctx.get_pool_name().c_str(),
+              group_ioctx.get_id(), group_name);
+    int r = librbd::group_image_list(group_ioctx, group_name, images);
+    tracepoint(librbd, group_image_list_exit, r);
+    return r;
+  }
+
+
   RBD::AioCompletion::AioCompletion(void *cb_arg, callback_t complete_cb)
   {
     pc = reinterpret_cast<void*>(librbd::AioCompletion::create(
@@ -678,6 +727,15 @@ namespace librbd {
     return r;
   }
 
+  int Image::get_group(group_spec_t *group_spec)
+  {
+    ImageCtx *ictx = (ImageCtx *)ctx;
+    tracepoint(librbd, image_get_group_enter, ictx->name.c_str());
+    int r = librbd::image_get_group(ictx, group_spec);
+    tracepoint(librbd, image_get_group_exit, r);
+    return r;
+  }
+
   int Image::features(uint64_t *features)
   {
     ImageCtx *ictx = (ImageCtx *)ctx;
@@ -3026,3 +3084,124 @@ extern "C" int rbd_group_list(rados_ioctx_t p, char *names, size_t *size)
   tracepoint(librbd, group_list_exit, (int)expected_size);
   return (int)expected_size;
 }
+
+extern "C" int rbd_group_image_add(
+                                 rados_ioctx_t group_p, const char *group_name,
+                                 rados_ioctx_t image_p, const char *image_name)
+{
+  librados::IoCtx group_ioctx;
+  librados::IoCtx image_ioctx;
+
+  librados::IoCtx::from_rados_ioctx_t(group_p, group_ioctx);
+  librados::IoCtx::from_rados_ioctx_t(image_p, image_ioctx);
+
+  TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
+  tracepoint(librbd, group_image_add_enter, group_ioctx.get_pool_name().c_str(),
+            group_ioctx.get_id(), group_name, image_ioctx.get_pool_name().c_str(),
+            image_ioctx.get_id(), image_name);
+
+  int r = librbd::group_image_add(group_ioctx, group_name, image_ioctx, image_name);
+
+  tracepoint(librbd, group_image_add_exit, r);
+  return r;
+}
+
+extern "C" int rbd_group_image_remove(
+                                rados_ioctx_t group_p, const char *group_name,
+                                rados_ioctx_t image_p, const char *image_name)
+{
+  librados::IoCtx group_ioctx;
+  librados::IoCtx image_ioctx;
+
+  librados::IoCtx::from_rados_ioctx_t(group_p, group_ioctx);
+  librados::IoCtx::from_rados_ioctx_t(image_p, image_ioctx);
+
+  TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
+  tracepoint(librbd, group_image_remove_enter, group_ioctx.get_pool_name().c_str(),
+            group_ioctx.get_id(), group_name, image_ioctx.get_pool_name().c_str(),
+            image_ioctx.get_id(), image_name);
+
+  int r = librbd::group_image_remove(group_ioctx, group_name, image_ioctx, image_name);
+
+  tracepoint(librbd, group_image_remove_exit, r);
+  return r;
+}
+
+extern "C" int rbd_group_image_list(rados_ioctx_t group_p,
+                                   const char *group_name,
+                                   rbd_group_image_status_t *images,
+                                   size_t *image_size)
+{
+  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_image_list_enter, group_ioctx.get_pool_name().c_str(),
+            group_ioctx.get_id(), group_name);
+
+  std::vector<librbd::group_image_status_t> cpp_images;
+  int r = librbd::group_image_list(group_ioctx, group_name, cpp_images);
+
+  if (r == -ENOENT) {
+    tracepoint(librbd, group_image_list_exit, 0);
+    return 0;
+  }
+
+  if (r < 0) {
+    tracepoint(librbd, group_image_list_exit, r);
+    return r;
+  }
+
+  if (*image_size < cpp_images.size()) {
+    tracepoint(librbd, group_image_list_exit, -ERANGE);
+    return -ERANGE;
+  }
+
+  for (size_t i = 0; i < cpp_images.size(); ++i) {
+    group_image_status_cpp_to_c(cpp_images[i], &images[i]);
+  }
+
+  tracepoint(librbd, group_image_list_exit, r);
+  return r;
+}
+
+extern "C" int rbd_image_get_group(rados_ioctx_t image_p,
+                                  const char *image_name,
+                                  rbd_group_spec_t *c_group_spec)
+{
+  librados::IoCtx io_ctx;
+  librados::IoCtx::from_rados_ioctx_t(image_p, io_ctx);
+
+  librbd::ImageCtx *ictx = new librbd::ImageCtx(image_name, "", "", io_ctx, false);
+  int r = ictx->state->open();
+  if (r < 0) {
+    delete ictx;
+    tracepoint(librbd, open_image_exit, r);
+    return r;
+  }
+
+  tracepoint(librbd, image_get_group_enter, ictx->name.c_str());
+  librbd::group_spec_t group_spec;
+  r = librbd::image_get_group(ictx, &group_spec);
+  group_spec_cpp_to_c(group_spec, c_group_spec);
+  tracepoint(librbd, image_get_group_exit, r);
+  ictx->state->close();
+  return r;
+}
+
+extern "C" void rbd_group_spec_cleanup(rbd_group_spec_t *group_spec) {
+  free(group_spec->name);
+}
+
+extern "C" void rbd_group_image_status_cleanup(
+                                             rbd_group_image_status_t *image) {
+    free(image->spec.name);
+}
+
+extern "C" void rbd_group_image_status_list_cleanup(
+                                             rbd_group_image_status_t *images,
+                                             size_t len) {
+  for (size_t i = 0; i < len; ++i) {
+    rbd_group_image_status_cleanup(&images[i]);
+  }
+}
index b24033d3bbeb0c1ab6a8215658342e0798281f60..091a7fc4191410cc2a43435bc7063daf6ebc73e4 100644 (file)
@@ -150,6 +150,9 @@ public:
       EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
                   exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("get_parent"), _, _, _))
                     .WillOnce(DoDefault());
+      EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
+                  exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("image_get_group"), _, _, _))
+                    .WillOnce(DoDefault());
       EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
                   exec(mock_image_ctx.header_oid, _, StrEq("lock"), StrEq("get_info"), _, _, _))
                     .WillOnce(DoDefault());
index 2818eb566dacf779d5b519317661b023e63f015a..428d1b9d5976ab57930db1489cfde123b896404d 100644 (file)
@@ -35,7 +35,6 @@ struct MockImageCtx {
     assert(s_instance != nullptr);
     return s_instance;
   }
-
   MockImageCtx(librbd::ImageCtx &image_ctx)
     : image_ctx(&image_ctx),
       cct(image_ctx.cct),
@@ -73,6 +72,7 @@ struct MockImageCtx {
       name(image_ctx.name),
       parent_md(image_ctx.parent_md),
       format_string(image_ctx.format_string),
+      group_spec(image_ctx.group_spec),
       layout(image_ctx.layout),
       aio_work_queue(new MockAioImageRequestWQ()),
       op_work_queue(new MockContextWQ()),
@@ -222,6 +222,7 @@ struct MockImageCtx {
   std::string name;
   parent_info parent_md;
   char *format_string;
+  cls::rbd::GroupSpec group_spec;
 
   file_layout_t layout;
 
index a6a1c24193c0789bcb3fa2bc7d20a7833da0cdb7..71c01a1d8d90c2ce26c0ebb1f1b40390c2a1858d 100644 (file)
@@ -61,3 +61,31 @@ TEST_F(TestLibCG, group_create)
   ASSERT_EQ(0, rbd.group_list(ioctx, groups));
   ASSERT_EQ(0U, groups.size());
 }
+
+TEST_F(TestLibCG, add_image)
+{
+  librados::IoCtx ioctx;
+  ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
+
+  const char *group_name = "mycg";
+  const char *image_name = "myimage";
+  librbd::RBD rbd;
+  ASSERT_EQ(0, rbd.group_create(ioctx, group_name));
+  int order = 14;
+  ASSERT_EQ(0, rbd.create2(ioctx, image_name, 65535,
+                          RBD_FEATURE_LAYERING, &order)); // Specified features make image of new format.
+
+  ASSERT_EQ(0, rbd.group_image_add(ioctx, group_name, ioctx, image_name));
+
+  vector<librbd::group_image_status_t> images;
+  ASSERT_EQ(0, rbd.group_image_list(ioctx, group_name, images));
+  ASSERT_EQ(1U, images.size());
+  ASSERT_EQ("myimage", images[0].name);
+  ASSERT_EQ(ioctx.get_id(), images[0].pool);
+
+  ASSERT_EQ(0, rbd.group_image_remove(ioctx, group_name, ioctx, image_name));
+
+  images.clear();
+  ASSERT_EQ(0, rbd.group_image_list(ioctx, group_name, images));
+  ASSERT_EQ(0U, images.size());
+}
index 8391c7ad3d438dffe866e92b0540bd3ed57b46bc..72b131409e216c7ac39dd8ff9eb87c11f326ce1a 100644 (file)
@@ -604,6 +604,7 @@ int test_ls(rados_ioctx_t io_ctx, size_t num_expected, ...)
     if (it != image_names.end()) {
       printf("found %s\n", expected);
       image_names.erase(it);
+      printf("erased %s\n", expected);
     } else {
       ADD_FAILURE() << "Unable to find image " << expected;
       va_end(ap);
index 45330a3d2ee78a081595c2042d4458963f64fbea..0726f86cff53ae7d9f4f5cd59d1c1ff4ee1c849b 100644 (file)
@@ -1965,3 +1965,91 @@ TRACEPOINT_EVENT(librbd, update_unwatch_exit,
         ctf_integer(int, retval, retval)
     )
 )
+
+TRACEPOINT_EVENT(librbd, group_image_add_enter,
+    TP_ARGS(
+        const char*, pool_name,
+        int64_t, id,
+        const char*, group_name,
+        const char*, image_pool_name,
+        int64_t, image_id,
+        const char*, image_name),
+    TP_FIELDS(
+        ctf_string(pool_name, pool_name)
+        ctf_integer(int64_t, id, id)
+        ctf_string(group_name, group_name)
+        ctf_string(image_pool_name, image_pool_name)
+        ctf_integer(int64_t, image_id, image_id)
+        ctf_string(image_name, image_name)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, group_image_add_exit,
+    TP_ARGS(
+        int, retval),
+    TP_FIELDS(
+        ctf_integer(int, retval, retval)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, group_image_remove_enter,
+    TP_ARGS(
+        const char*, pool_name,
+        int64_t, id,
+        const char*, group_name,
+        const char*, image_pool_name,
+        int64_t, image_id,
+        const char*, image_name),
+    TP_FIELDS(
+        ctf_string(pool_name, pool_name)
+        ctf_integer(int64_t, id, id)
+        ctf_string(group_name, group_name)
+        ctf_string(image_pool_name, image_pool_name)
+        ctf_integer(int64_t, image_id, image_id)
+        ctf_string(image_name, image_name)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, group_image_remove_exit,
+    TP_ARGS(
+        int, retval),
+    TP_FIELDS(
+        ctf_integer(int, retval, retval)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, group_image_list_enter,
+    TP_ARGS(
+        const char*, pool_name,
+        int64_t, id,
+        const char*, group_name),
+    TP_FIELDS(
+        ctf_string(pool_name, pool_name)
+        ctf_integer(int64_t, id, id)
+        ctf_string(group_name, group_name)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, group_image_list_exit,
+    TP_ARGS(
+           int, retval),
+    TP_FIELDS(
+        ctf_integer(int, retval, retval)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, image_get_group_enter,
+    TP_ARGS(
+        const char*, image_name),
+    TP_FIELDS(
+        ctf_string(image_name, image_name)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, image_get_group_exit,
+    TP_ARGS(
+           int, retval),
+    TP_FIELDS(
+        ctf_integer(int, retval, retval)
+    )
+)