]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
librbd: expand API to include namespaces and image ids
authorJason Dillaman <dillaman@redhat.com>
Wed, 21 Nov 2018 00:06:23 +0000 (19:06 -0500)
committerJason Dillaman <dillaman@redhat.com>
Sun, 25 Nov 2018 12:59:40 +0000 (07:59 -0500)
The get parent and list children methods now return a common
struct that includes the full pool details (including the
optional namespace). Additionally, a new image list method has
been added which includes both the name and id (of v2 images).

Fixes: http://tracker.ceph.com/issues/36650
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
12 files changed:
src/include/rbd/librbd.h
src/include/rbd/librbd.hpp
src/librbd/api/Image.cc
src/librbd/api/Image.h
src/librbd/api/Mirror.cc
src/librbd/api/Pool.cc
src/librbd/internal.cc
src/librbd/internal.h
src/librbd/librbd.cc
src/pybind/rbd/rbd.pyx
src/test/librbd/test_librbd.cc
src/test/pybind/test_rbd.py

index cbbd42b90e1e99c26a9fb825ffb0d4daae6cd69d..976a6cbeff9bec92ce5282b582306db6849c5dbb 100644 (file)
@@ -68,6 +68,32 @@ typedef int (*librbd_progress_fn_t)(uint64_t offset, uint64_t total, void *ptr);
 
 typedef void (*rbd_update_callback_t)(void *arg);
 
+typedef enum {
+  RBD_SNAP_NAMESPACE_TYPE_USER  = 0,
+  RBD_SNAP_NAMESPACE_TYPE_GROUP = 1,
+  RBD_SNAP_NAMESPACE_TYPE_TRASH = 2
+} rbd_snap_namespace_type_t;
+
+typedef struct {
+  char *id;
+  char *name;
+} rbd_image_spec_t;
+
+typedef struct {
+  int64_t pool_id;
+  char *pool_name;
+  char *pool_namespace;
+  char *image_id;
+  char *image_name;
+  bool trash;
+} rbd_linked_image_spec_t;
+
+typedef struct {
+  uint64_t id;
+  rbd_snap_namespace_type_t namespace_type;
+  char *name;
+} rbd_snap_spec_t;
+
 typedef struct {
   uint64_t id;
   uint64_t size;
@@ -179,12 +205,6 @@ typedef struct {
   rbd_group_snap_state_t state;
 } rbd_group_snap_info_t;
 
-typedef enum {
-  RBD_SNAP_NAMESPACE_TYPE_USER  = 0,
-  RBD_SNAP_NAMESPACE_TYPE_GROUP = 1,
-  RBD_SNAP_NAMESPACE_TYPE_TRASH = 2
-} rbd_snap_namespace_type_t;
-
 typedef struct {
   int64_t group_pool;
   char *group_name;
@@ -296,8 +316,21 @@ CEPH_RBD_API int rbd_image_options_unset(rbd_image_options_t opts, int optname);
 CEPH_RBD_API void rbd_image_options_clear(rbd_image_options_t opts);
 CEPH_RBD_API int rbd_image_options_is_empty(rbd_image_options_t opts);
 
+/* helpers */
+CEPH_RBD_API void rbd_image_spec_cleanup(rbd_image_spec_t *image);
+CEPH_RBD_API void rbd_image_spec_list_cleanup(rbd_image_spec_t *images,
+                                              size_t num_images);
+CEPH_RBD_API void rbd_linked_image_spec_cleanup(rbd_linked_image_spec_t *image);
+CEPH_RBD_API void rbd_linked_image_spec_list_cleanup(
+    rbd_linked_image_spec_t *images, size_t num_images);
+CEPH_RBD_API void rbd_snap_spec_cleanup(rbd_snap_spec_t *snap);
+
 /* images */
-CEPH_RBD_API int rbd_list(rados_ioctx_t io, char *names, size_t *size);
+CEPH_RBD_API int rbd_list(rados_ioctx_t io, char *names, size_t *size)
+    __attribute__((deprecated));
+CEPH_RBD_API int rbd_list2(rados_ioctx_t io, rbd_image_spec_t* images,
+                           size_t *max_images);
+
 CEPH_RBD_API int rbd_create(rados_ioctx_t io, const char *name, uint64_t size,
                             int *order);
 CEPH_RBD_API int rbd_create2(rados_ioctx_t io, const char *name, uint64_t size,
@@ -352,8 +385,10 @@ CEPH_RBD_API int rbd_trash_list(rados_ioctx_t io,
 CEPH_RBD_API void rbd_trash_list_cleanup(rbd_trash_image_info_t *trash_entries,
                                          size_t num_entries);
 CEPH_RBD_API int rbd_trash_remove(rados_ioctx_t io, const char *id, bool force);
-CEPH_RBD_API int rbd_trash_remove_with_progress(rados_ioctx_t io, const char *id,
-                                                bool force, librbd_progress_fn_t cb,
+CEPH_RBD_API int rbd_trash_remove_with_progress(rados_ioctx_t io,
+                                                const char *id,
+                                                bool force,
+                                                librbd_progress_fn_t cb,
                                                 void *cbdata);
 CEPH_RBD_API int rbd_trash_restore(rados_ioctx_t io, const char *id,
                                    const char *name);
@@ -527,18 +562,25 @@ 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,
                                     char *parent_snapname,
-                                     size_t psnapnamelen);
+                                     size_t psnapnamelen)
+    __attribute__((deprecated));
 CEPH_RBD_API int rbd_get_parent_info2(rbd_image_t image,
                                       char *parent_poolname,
                                       size_t ppoolnamelen,
                                       char *parent_name, size_t pnamelen,
                                       char *parent_id, size_t pidlen,
                                       char *parent_snapname,
-                                      size_t psnapnamelen);
+                                      size_t psnapnamelen)
+    __attribute__((deprecated));
+CEPH_RBD_API int rbd_get_parent(rbd_image_t image,
+                                rbd_linked_image_spec_t *parent_image,
+                                rbd_snap_spec_t *parent_snap);
+
 CEPH_RBD_API int rbd_get_flags(rbd_image_t image, uint64_t *flags);
 CEPH_RBD_API int rbd_get_group(rbd_image_t image, rbd_group_info_t *group_info,
                                size_t group_info_size);
@@ -603,8 +645,9 @@ CEPH_RBD_API int rbd_snap_list(rbd_image_t image, rbd_snap_info_t *snaps,
 CEPH_RBD_API void rbd_snap_list_end(rbd_snap_info_t *snaps);
 CEPH_RBD_API int rbd_snap_create(rbd_image_t image, const char *snapname);
 CEPH_RBD_API int rbd_snap_remove(rbd_image_t image, const char *snapname);
-CEPH_RBD_API int rbd_snap_remove2(rbd_image_t image, const char *snap_name, uint32_t flags,
-                                 librbd_progress_fn_t cb, void *cbdata);
+CEPH_RBD_API int rbd_snap_remove2(rbd_image_t image, const char *snap_name,
+                                  uint32_t flags, librbd_progress_fn_t cb,
+                                  void *cbdata);
 CEPH_RBD_API int rbd_snap_remove_by_id(rbd_image_t image, uint64_t snap_id);
 CEPH_RBD_API int rbd_snap_rollback(rbd_image_t image, const char *snapname);
 CEPH_RBD_API int rbd_snap_rollback_with_progress(rbd_image_t image,
@@ -710,13 +753,21 @@ CEPH_RBD_API int rbd_flatten_with_progress(rbd_image_t image,
  */
 CEPH_RBD_API ssize_t rbd_list_children(rbd_image_t image, char *pools,
                                        size_t *pools_len, char *images,
-                                       size_t *images_len);
+                                       size_t *images_len)
+    __attribute__((deprecated));
 CEPH_RBD_API int rbd_list_children2(rbd_image_t image,
                                     rbd_child_info_t *children,
-                                    int *max_children);
-CEPH_RBD_API void rbd_list_child_cleanup(rbd_child_info_t *child);
+                                    int *max_children)
+    __attribute__((deprecated));
+CEPH_RBD_API void rbd_list_child_cleanup(rbd_child_info_t *child)
+    __attribute__((deprecated));
 CEPH_RBD_API void rbd_list_children_cleanup(rbd_child_info_t *children,
-                                            size_t num_children);
+                                            size_t num_children)
+    __attribute__((deprecated));
+
+CEPH_RBD_API int rbd_list_children3(rbd_image_t image,
+                                    rbd_linked_image_spec_t *images,
+                                    size_t *max_images);
 
 /**
  * @defgroup librbd_h_locking Advisory Locking
index 93703b1b40aaeaff926a9fdb00e49981df25e5c9..926158e1a1432d7387e077a818067c5144138526 100644 (file)
@@ -34,14 +34,34 @@ namespace librbd {
   typedef void *completion_t;
   typedef void (*callback_t)(completion_t cb, void *arg);
 
+  typedef struct {
+    std::string id;
+    std::string name;
+  } image_spec_t;
+
+  typedef struct {
+    int64_t pool_id;
+    std::string pool_name;
+    std::string pool_namespace;
+    std::string image_id;
+    std::string image_name;
+    bool trash;
+  } linked_image_spec_t;
+
+  typedef rbd_snap_namespace_type_t snap_namespace_type_t;
+
+  typedef struct {
+    uint64_t id;
+    snap_namespace_type_t namespace_type;
+    std::string name;
+  } snap_spec_t;
+
   typedef struct {
     uint64_t id;
     uint64_t size;
     std::string name;
   } snap_info_t;
 
-  typedef rbd_snap_namespace_type_t snap_namespace_type_t;
-
   typedef struct {
     int64_t group_pool;
     std::string group_name;
@@ -190,7 +210,11 @@ public:
                         const char *snapname, RBD::AioCompletion *c);
   int aio_open_by_id_read_only(IoCtx& io_ctx, Image& image, const char *id,
                                const char *snapname, RBD::AioCompletion *c);
-  int list(IoCtx& io_ctx, std::vector<std::string>& names);
+
+  int list(IoCtx& io_ctx, std::vector<std::string>& names)
+    __attribute__((deprecated));
+  int list2(IoCtx& io_ctx, std::vector<image_spec_t>* images);
+
   int create(IoCtx& io_ctx, const char *name, uint64_t size, int *order);
   int create2(IoCtx& io_ctx, const char *name, uint64_t size,
              uint64_t features, int *order);
@@ -383,9 +407,13 @@ public:
   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);
+                 std::string *parent_snapname)
+      __attribute__((deprecated));
   int parent_info2(std::string *parent_poolname, std::string *parent_name,
-                   std::string *parent_id, std::string *parent_snapname);
+                   std::string *parent_id, std::string *parent_snapname)
+      __attribute__((deprecated));
+  int get_parent(linked_image_spec_t *parent_image, snap_spec_t *parent_snap);
+
   int old_format(uint8_t *old);
   int size(uint64_t *size);
   int get_group(group_info_t *group_info, size_t group_info_size);
@@ -442,12 +470,15 @@ public:
    * Returns a pair of poolname, imagename for each clone
    * of this image at the currently set snapshot.
    */
-  int list_children(std::set<std::pair<std::string, std::string> > *children);
+  int list_children(std::set<std::pair<std::string, std::string> > *children)
+      __attribute__((deprecated));
   /**
   * Returns a structure of poolname, imagename, imageid and trash flag
   * for each clone of this image at the currently set snapshot.
   */
-  int list_children2(std::vector<librbd::child_info_t> *children);
+  int list_children2(std::vector<librbd::child_info_t> *children)
+      __attribute__((deprecated));
+  int list_children3(std::vector<linked_image_spec_t> *images);
 
   /* advisory locking (see librbd.h for details) */
   int list_lockers(std::list<locker_t> *lockers,
index c2d887e48f9da617d89366ac915555b7a46364d0..a13e60bc31c28d256ca5cb5f1439550f02a51256 100644 (file)
 namespace librbd {
 namespace api {
 
+namespace {
+
+bool compare_by_pool(const librbd::linked_image_spec_t& lhs,
+                     const librbd::linked_image_spec_t& rhs)
+{
+  if (lhs.pool_id != rhs.pool_id) {
+    return lhs.pool_id < rhs.pool_id;
+  } else if (lhs.pool_namespace != rhs.pool_namespace) {
+    return lhs.pool_namespace < rhs.pool_namespace;
+  }
+  return false;
+}
+
+bool compare(const librbd::linked_image_spec_t& lhs,
+             const librbd::linked_image_spec_t& rhs)
+{
+  if (lhs.pool_name != rhs.pool_name) {
+    return lhs.pool_name < rhs.pool_name;
+  } else if (lhs.pool_id != rhs.pool_id) {
+    return lhs.pool_id < rhs.pool_id;
+  } else if (lhs.pool_namespace != rhs.pool_namespace) {
+    return lhs.pool_namespace < rhs.pool_namespace;
+  } else if (lhs.image_name != rhs.image_name) {
+    return lhs.image_name < rhs.image_name;
+  } else if (lhs.image_id != rhs.image_id) {
+    return lhs.image_id < rhs.image_id;
+  }
+  return false;
+}
+
+
+} // anonymous namespace
+
 template <typename I>
 int Image<I>::get_op_features(I *ictx, uint64_t *op_features) {
   CephContext *cct = ictx->cct;
@@ -41,7 +74,54 @@ int Image<I>::get_op_features(I *ictx, uint64_t *op_features) {
 }
 
 template <typename I>
-int Image<I>::list_images(librados::IoCtx& io_ctx, ImageNameToIds *images) {
+int Image<I>::list_images(librados::IoCtx& io_ctx,
+                          std::vector<image_spec_t> *images) {
+  CephContext *cct = (CephContext *)io_ctx.cct();
+  ldout(cct, 20) << "list " << &io_ctx << dendl;
+
+  int r;
+  images->clear();
+
+  if (io_ctx.get_namespace().empty()) {
+    bufferlist bl;
+    r = io_ctx.read(RBD_DIRECTORY, bl, 0, 0);
+    if (r == -ENOENT) {
+      return 0;
+    } else if (r < 0) {
+      lderr(cct) << "error listing v1 images: " << cpp_strerror(r) << dendl;
+      return r;
+    }
+
+    // old format images are in a tmap
+    if (bl.length()) {
+      auto p = bl.cbegin();
+      bufferlist header;
+      std::map<std::string, bufferlist> m;
+      decode(header, p);
+      decode(m, p);
+      for (auto& it : m) {
+        images->push_back({.id ="", .name = it.first});
+      }
+    }
+  }
+
+  std::map<std::string, std::string> image_names_to_ids;
+  r = list_images_v2(io_ctx, &image_names_to_ids);
+  if (r < 0) {
+    lderr(cct) << "error listing v2 images: " << cpp_strerror(r) << dendl;
+    return r;
+  }
+
+  for (const auto& img_pair : image_names_to_ids) {
+    images->push_back({.id = img_pair.second,
+                       .name = img_pair.first});
+  }
+
+  return 0;
+}
+
+template <typename I>
+int Image<I>::list_images_v2(librados::IoCtx& io_ctx, ImageNameToIds *images) {
   CephContext *cct = (CephContext *)io_ctx.cct();
   ldout(cct, 20) << "io_ctx=" << &io_ctx << dendl;
 
@@ -51,8 +131,8 @@ int Image<I>::list_images(librados::IoCtx& io_ctx, ImageNameToIds *images) {
   string last_read = "";
   do {
     map<string, string> images_page;
-    r = cls_client::dir_list(&io_ctx, RBD_DIRECTORY,
-                  last_read, max_read, &images_page);
+    r = cls_client::dir_list(&io_ctx, RBD_DIRECTORY, last_read, max_read,
+                             &images_page);
     if (r < 0 && r != -ENOENT) {
       lderr(cct) << "error listing image in directory: "
                  << cpp_strerror(r) << dendl;
@@ -73,23 +153,103 @@ int Image<I>::list_images(librados::IoCtx& io_ctx, ImageNameToIds *images) {
   return 0;
 }
 
+template <typename I>
+int Image<I>::get_parent(I *ictx,
+                         librbd::linked_image_spec_t *parent_image,
+                         librbd::snap_spec_t *parent_snap) {
+  auto cct = ictx->cct;
+  ldout(cct, 20) << "image_ctx=" << ictx << dendl;
+
+  int r = ictx->state->refresh_if_required();
+  if (r < 0) {
+    return r;
+  }
+
+  RWLock::RLocker snap_locker(ictx->snap_lock);
+  RWLock::RLocker parent_locker(ictx->parent_lock);
+  if (ictx->parent == nullptr) {
+    return -ENOENT;
+  }
+
+  cls::rbd::ParentImageSpec parent_spec;
+  if (ictx->snap_id == CEPH_NOSNAP) {
+    parent_spec = ictx->parent_md.spec;
+  } else {
+    r = ictx->get_parent_spec(ictx->snap_id, &parent_spec);
+    if (r < 0) {
+      lderr(cct) << "error looking up snapshot id " << ictx->snap_id << dendl;
+      return r;
+    }
+    if (parent_spec.pool_id == -1) {
+      return -ENOENT;
+    }
+  }
+
+  parent_image->pool_id = parent_spec.pool_id;
+  parent_image->pool_name = ictx->parent->md_ctx.get_pool_name();
+  parent_image->pool_namespace = ictx->parent->md_ctx.get_namespace();
+
+  RWLock::RLocker parent_snap_locker(ictx->parent->snap_lock);
+  parent_snap->id = parent_spec.snap_id;
+  parent_snap->namespace_type = RBD_SNAP_NAMESPACE_TYPE_USER;
+  if (parent_spec.snap_id != CEPH_NOSNAP) {
+    auto snap_info = ictx->parent->get_snap_info(parent_spec.snap_id);
+    if (snap_info == nullptr) {
+      lderr(cct) << "error finding parent snap name: " << cpp_strerror(r)
+                 << dendl;
+      return -ENOENT;
+    }
+
+    parent_snap->namespace_type = static_cast<snap_namespace_type_t>(
+      cls::rbd::get_snap_namespace_type(snap_info->snap_namespace));
+    parent_snap->name = snap_info->name;
+  }
+
+  parent_image->image_id = ictx->parent->id;
+  parent_image->image_name = ictx->parent->name;
+  parent_image->trash = true;
+
+  librbd::trash_image_info_t trash_info;
+  r = Trash<I>::get(ictx->parent->md_ctx, ictx->parent->id,
+                    &trash_info);
+  if (r == -ENOENT || r == -EOPNOTSUPP) {
+    parent_image->trash = false;
+  } else if (r < 0) {
+    lderr(cct) << "error looking up trash status: " << cpp_strerror(r)
+               << dendl;
+    return r;
+  }
+
+  return 0;
+}
+
+template <typename I>
+int Image<I>::list_children(I *ictx,
+                            std::vector<librbd::linked_image_spec_t> *images) {
+  RWLock::RLocker l(ictx->snap_lock);
+  cls::rbd::ParentImageSpec parent_spec{ictx->md_ctx.get_id(),
+                                        ictx->md_ctx.get_namespace(),
+                                        ictx->id, ictx->snap_id};
+  return list_children(ictx, parent_spec, images);
+}
+
 template <typename I>
 int Image<I>::list_children(I *ictx,
                             const cls::rbd::ParentImageSpec &parent_spec,
-                            PoolImageIds *pool_image_ids)
-{
+                            std::vector<librbd::linked_image_spec_t> *images) {
   CephContext *cct = ictx->cct;
+  ldout(cct, 20) << "ictx=" << ictx << dendl;
 
   // no children for non-layered or old format image
   if (!ictx->test_features(RBD_FEATURE_LAYERING, ictx->snap_lock)) {
     return 0;
   }
 
-  pool_image_ids->clear();
+  images->clear();
 
   librados::Rados rados(ictx->md_ctx);
 
-  // search all pools for clone v1 children depending on this snapshot
+  // search all pools for clone v1 children dependent on this snapshot
   std::list<std::pair<int64_t, std::string> > pools;
   int r = rados.pool_list2(pools);
   if (r < 0) {
@@ -97,40 +257,43 @@ int Image<I>::list_children(I *ictx,
     return r;
   }
 
-  for (auto it = pools.begin(); it != pools.end(); ++it) {
+  for (auto& it : pools) {
     int64_t base_tier;
-    r = rados.pool_get_base_tier(it->first, &base_tier);
+    r = rados.pool_get_base_tier(it.first, &base_tier);
     if (r == -ENOENT) {
-      ldout(cct, 1) << "pool " << it->second << " no longer exists" << dendl;
+      ldout(cct, 1) << "pool " << it.second << " no longer exists" << dendl;
       continue;
     } else if (r < 0) {
-      lderr(cct) << "error retrieving base tier for pool " << it->second
+      lderr(cct) << "error retrieving base tier for pool " << it.second
                  << dendl;
       return r;
     }
-    if (it->first != base_tier) {
+    if (it.first != base_tier) {
       // pool is a cache; skip it
       continue;
     }
 
     IoCtx ioctx;
-    r = util::create_ioctx(ictx->md_ctx, "child image", it->first, {}, &ioctx);
+    r = util::create_ioctx(ictx->md_ctx, "child image", it.first, {}, &ioctx);
     if (r == -ENOENT) {
       continue;
     } else if (r < 0) {
       return r;
     }
 
-    set<string> image_ids;
+    std::set<std::string> image_ids;
     r = cls_client::get_children(&ioctx, RBD_CHILDREN, parent_spec,
                                  image_ids);
     if (r < 0 && r != -ENOENT) {
-      lderr(cct) << "error reading list of children from pool " << it->second
+      lderr(cct) << "error reading list of children from pool " << it.second
                  << dendl;
       return r;
     }
-    pool_image_ids->insert({
-      {it->first, it->second, ictx->md_ctx.get_namespace()}, image_ids});
+
+    for (auto& image_id : image_ids) {
+      images->push_back({
+        it.first, "", ictx->md_ctx.get_namespace(), image_id, "", false});
+    }
   }
 
   // retrieve clone v2 children attached to this snapshot
@@ -151,18 +314,70 @@ int Image<I>::list_children(I *ictx,
   }
 
   for (auto& child_image : child_images) {
-    IoCtx io_ctx;
-    r = util::create_ioctx(ictx->md_ctx, "child image", child_image.pool_id,
-                           child_image.pool_namespace, &io_ctx);
-    if (r == -ENOENT) {
-      continue;
+    images->push_back({
+      child_image.pool_id, "", child_image.pool_namespace,
+      child_image.image_id, "", false});
+  }
+
+  // batch lookups by pool + namespace
+  std::sort(images->begin(), images->end(), compare_by_pool);
+
+  int64_t child_pool_id = -1;
+  librados::IoCtx child_io_ctx;
+  std::map<std::string, std::pair<std::string, bool>> child_image_id_to_info;
+  for (auto& image : *images) {
+    if (child_pool_id == -1 || child_pool_id != image.pool_id ||
+        child_io_ctx.get_namespace() != image.pool_namespace) {
+      r = util::create_ioctx(ictx->md_ctx, "child image", image.pool_id,
+                             image.pool_namespace, &child_io_ctx);
+      if (r < 0) {
+        return r;
+      }
+      child_pool_id = image.pool_id;
+
+      child_image_id_to_info.clear();
+
+      std::map<std::string, std::string> image_names_to_ids;
+      r = list_images_v2(child_io_ctx, &image_names_to_ids);
+      if (r < 0) {
+        lderr(cct) << "error listing v2 images: " << cpp_strerror(r) << dendl;
+        return r;
+      }
+
+      for (auto& it : image_names_to_ids) {
+        child_image_id_to_info[it.second] = {it.first, false};
+      }
+
+      std::vector<librbd::trash_image_info_t> trash_images;
+      r = Trash<I>::list(child_io_ctx, trash_images);
+      if (r < 0 && r != -EOPNOTSUPP) {
+        lderr(cct) << "error listing trash images: " << cpp_strerror(r)
+                   << dendl;
+        return r;
+      }
+
+      for (auto& it : trash_images) {
+        child_image_id_to_info[it.id] = {it.name, true};
+      }
+    }
+
+    auto it = child_image_id_to_info.find(image.image_id);
+    if (it == child_image_id_to_info.end()) {
+          lderr(cct) << "error looking up name for image id "
+                     << image.image_id << " in pool "
+                     << child_io_ctx.get_pool_name()
+                     << (image.pool_namespace.empty() ?
+                          "" : "/" + image.pool_namespace) << dendl;
+      return -ENOENT;
     }
 
-    PoolSpec pool_spec = {child_image.pool_id, io_ctx.get_pool_name(),
-                          child_image.pool_namespace};
-    (*pool_image_ids)[pool_spec].insert(child_image.image_id);
+    image.pool_name = child_io_ctx.get_pool_name();
+    image.image_name = it->second.first;
+    image.trash = it->second.second;
   }
 
+  // final sort by pool + image names
+  std::sort(images->begin(), images->end(), compare);
   return 0;
 }
 
index a46104d5226a0d2108288c1985e6df4e535afabe..8c8ddbea27f93244cb8672121393b155b9565123 100644 (file)
@@ -4,6 +4,7 @@
 #ifndef LIBRBD_API_IMAGE_H
 #define LIBRBD_API_IMAGE_H
 
+#include "include/rbd/librbd.hpp"
 #include "librbd/Types.h"
 #include <map>
 #include <set>
@@ -22,19 +23,24 @@ namespace api {
 
 template <typename ImageCtxT = librbd::ImageCtx>
 struct Image {
-  typedef std::tuple<int64_t, std::string, std::string> PoolSpec;
-  typedef std::set<std::string> ImageIds;
-  typedef std::map<PoolSpec, ImageIds> PoolImageIds;
   typedef std::map<std::string, std::string> ImageNameToIds;
 
   static int get_op_features(ImageCtxT *ictx, uint64_t *op_features);
 
   static int list_images(librados::IoCtx& io_ctx,
-                         ImageNameToIds *images);
+                         std::vector<image_spec_t> *images);
+  static int list_images_v2(librados::IoCtx& io_ctx,
+                            ImageNameToIds *images);
 
+  static int get_parent(ImageCtxT *ictx,
+                        librbd::linked_image_spec_t *parent_image,
+                        librbd::snap_spec_t *parent_snap);
+
+  static int list_children(ImageCtxT *ictx,
+                           std::vector<librbd::linked_image_spec_t> *images);
   static int list_children(ImageCtxT *ictx,
                            const cls::rbd::ParentImageSpec &parent_spec,
-                           PoolImageIds *pool_image_ids);
+                           std::vector<librbd::linked_image_spec_t> *images);
 
   static int deep_copy(ImageCtxT *ictx, librados::IoCtx& dest_md_ctx,
                        const char *destname, ImageOptions& opts,
index f02503828c7ce7bf333aa8bd3fd1c52fd517a656..9fe240bc67097ff514dee54bb7d680f693915d33 100644 (file)
@@ -303,36 +303,44 @@ int Mirror<I>::image_disable(I *ictx, bool force) {
         cls::rbd::ParentImageSpec parent_spec{ictx->md_ctx.get_id(),
                                               ictx->md_ctx.get_namespace(),
                                               ictx->id, info.first};
-        map< tuple<int64_t, string, string>, set<string> > image_info;
-
-        r = Image<I>::list_children(ictx, parent_spec, &image_info);
+        std::vector<librbd::linked_image_spec_t> child_images;
+        r = Image<I>::list_children(ictx, parent_spec, &child_images);
         if (r < 0) {
           rollback = true;
           return r;
         }
-        if (image_info.empty())
-          continue;
 
-        for (auto &info: image_info) {
-          librados::IoCtx ioctx;
-          r = util::create_ioctx(ictx->md_ctx, "child image",
-                                 std::get<0>(info.first),
-                                 std::get<2>(info.first), &ioctx);
-          if (r < 0) {
-            rollback = true;
-            return r;
-          }
+        if (child_images.empty()) {
+          continue;
+        }
 
-          for (auto &id_it : info.second) {
-            cls::rbd::MirrorImage mirror_image_internal;
-            r = cls_client::mirror_image_get(&ioctx, id_it,
-                                             &mirror_image_internal);
-            if (r != -ENOENT) {
+        librados::IoCtx child_io_ctx;
+        int64_t child_pool_id = -1;
+        for (auto &child_image : child_images){
+          std::string pool = child_image.pool_name;
+          if (child_pool_id == -1 ||
+              child_pool_id != child_image.pool_id ||
+              child_io_ctx.get_namespace() != child_image.pool_namespace) {
+            r = util::create_ioctx(ictx->md_ctx, "child image",
+                                   child_image.pool_id,
+                                   child_image.pool_namespace,
+                                   &child_io_ctx);
+            if (r < 0) {
               rollback = true;
-              lderr(cct) << "mirroring is enabled on one or more children "
-                         << dendl;
-              return -EBUSY;
+              return r;
             }
+
+            child_pool_id = child_image.pool_id;
+          }
+
+          cls::rbd::MirrorImage mirror_image_internal;
+          r = cls_client::mirror_image_get(&child_io_ctx, child_image.image_id,
+                                           &mirror_image_internal);
+          if (r != -ENOENT) {
+            rollback = true;
+            lderr(cct) << "mirroring is enabled on one or more children "
+                       << dendl;
+            return -EBUSY;
           }
         }
       }
@@ -634,7 +642,7 @@ int Mirror<I>::mode_set(librados::IoCtx& io_ctx,
 
   if (next_mirror_mode == cls::rbd::MIRROR_MODE_POOL) {
     map<string, string> images;
-    r = Image<I>::list_images(io_ctx, &images);
+    r = Image<I>::list_images_v2(io_ctx, &images);
     if (r < 0) {
       lderr(cct) << "failed listing images: " << cpp_strerror(r) << dendl;
       return r;
@@ -984,7 +992,7 @@ int Mirror<I>::image_status_list(librados::IoCtx& io_ctx,
   map<string, string> id_to_name;
   {
     map<string, string> name_to_id;
-    r = Image<I>::list_images(io_ctx, &name_to_id);
+    r = Image<I>::list_images_v2(io_ctx, &name_to_id);
     if (r < 0) {
       return r;
     }
index 6e36231199574009a1619b5430c822e299ce94d0..533106d0e611b0197214f8ca6c355c2ff5552f22 100644 (file)
@@ -294,7 +294,7 @@ int Pool<I>::get_stats(librados::IoCtx& io_ctx, StatOptions* stat_options) {
   if (image_count != nullptr || provisioned_bytes != nullptr ||
       max_provisioned_bytes != nullptr || snapshot_count != nullptr) {
     typename Image<I>::ImageNameToIds images;
-    int r = Image<I>::list_images(io_ctx, &images);
+    int r = Image<I>::list_images_v2(io_ctx, &images);
     if (r < 0) {
       return r;
     }
index 12d8da2f905a3172a446f97d3901b3af3569df6a..52a3ae9cc1a1ce6bce8e3e5f90149db2febd9dda 100644 (file)
@@ -113,16 +113,6 @@ int validate_pool(IoCtx &io_ctx, CephContext *cct) {
   return 0;
 }
 
-bool compare_by_name(const child_info_t& c1, const child_info_t& c2)
-{
-  if (c1.pool_name != c2.pool_name)
-    return c1.pool_name < c2.pool_name;
-  else if (c1.image_name != c2.image_name)
-    return c1.image_name < c2.image_name;
-  else
-    return false;
-}
-
 } // anonymous namespace
 
   int detect_format(IoCtx &io_ctx, const string &name,
@@ -520,45 +510,6 @@ bool compare_by_name(const child_info_t& c1, const child_info_t& c2)
     return (*opts_)->empty();
   }
 
-  int list(IoCtx& io_ctx, vector<string>& names)
-  {
-    CephContext *cct = (CephContext *)io_ctx.cct();
-    ldout(cct, 20) << "list " << &io_ctx << dendl;
-
-    bufferlist bl;
-    int r = io_ctx.read(RBD_DIRECTORY, bl, 0, 0);
-    if (r < 0) {
-      if (r == -ENOENT) {
-        r = 0;
-      }
-      return r;
-    }
-
-    // old format images are in a tmap
-    if (bl.length()) {
-      auto p = bl.cbegin();
-      bufferlist header;
-      map<string,bufferlist> m;
-      decode(header, p);
-      decode(m, p);
-      for (map<string,bufferlist>::iterator q = m.begin(); q != m.end(); ++q) {
-       names.push_back(q->first);
-      }
-    }
-
-    map<string, string> images;
-    r = api::Image<>::list_images(io_ctx, &images);
-    if (r < 0) {
-      lderr(cct) << "error listing v2 images: " << cpp_strerror(r) << dendl;
-      return r;
-    }
-    for (const auto& img_pair : images) {
-      names.push_back(img_pair.first);
-    }
-
-    return 0;
-  }
-
   int flatten_children(ImageCtx *ictx, const char* snap_name,
                        ProgressContext& pctx)
   {
@@ -577,135 +528,71 @@ bool compare_by_name(const child_info_t& c1, const child_info_t& c2)
     cls::rbd::ParentImageSpec parent_spec{ictx->md_ctx.get_id(),
                                           ictx->md_ctx.get_namespace(),
                                           ictx->id, snap_id};
-    map< tuple<int64_t, string, string>, set<string> > image_info;
-
-    r = api::Image<>::list_children(ictx, parent_spec, &image_info);
+    std::vector<librbd::linked_image_spec_t> child_images;
+    r = api::Image<>::list_children(ictx, parent_spec, &child_images);
     if (r < 0) {
       return r;
     }
 
-    size_t size = image_info.size();
-    if (size == 0)
+    size_t size = child_images.size();
+    if (size == 0) {
       return 0;
+    }
 
+    librados::IoCtx child_io_ctx;
+    int64_t child_pool_id = -1;
     size_t i = 0;
-    for ( auto &info : image_info){
-      string pool = std::get<1>(info.first);
-      IoCtx ioctx;
-      r = util::create_ioctx(ictx->md_ctx, "child image",
-                             std::get<0>(info.first), std::get<2>(info.first),
-                             &ioctx);
-      if (r < 0) {
-        return r;
-      }
-      ioctx.set_namespace(std::get<2>(info.first));
-
-      for (auto &id_it : info.second) {
-       ImageCtx *imctx = new ImageCtx("", id_it, nullptr, ioctx, false);
-       int r = imctx->state->open(0);
-       if (r < 0) {
-         lderr(cct) << "error opening image: "
-                    << cpp_strerror(r) << dendl;
-         return r;
-       }
-
-        if ((imctx->features & RBD_FEATURE_DEEP_FLATTEN) == 0 &&
-            !imctx->snaps.empty()) {
-          lderr(cct) << "snapshot in-use by " << pool << "/" << imctx->name
-                     << dendl;
-          imctx->state->close();
-          return -EBUSY;
-        }
-
-       librbd::NoOpProgressContext prog_ctx;
-       r = imctx->operations->flatten(prog_ctx);
-       if (r < 0) {
-         lderr(cct) << "error flattening image: " << pool << "/" << id_it
-                    << cpp_strerror(r) << dendl;
-          imctx->state->close();
-         return r;
-       }
-
-       r = imctx->state->close();
+    for (auto &child_image : child_images){
+      std::string pool = child_image.pool_name;
+      if (child_pool_id == -1 ||
+          child_pool_id != child_image.pool_id ||
+          child_io_ctx.get_namespace() != child_image.pool_namespace) {
+        r = util::create_ioctx(ictx->md_ctx, "child image",
+                               child_image.pool_id, child_image.pool_namespace,
+                               &child_io_ctx);
         if (r < 0) {
-          lderr(cct) << "failed to close image: " << cpp_strerror(r) << dendl;
           return r;
         }
-      }
-      pctx.update_progress(++i, size);
-      ceph_assert(i <= size);
-    }
-
-    return 0;
-  }
-
-  int list_children(ImageCtx *ictx,
-                    vector<child_info_t> *names)
-  {
-    CephContext *cct = ictx->cct;
-    ldout(cct, 20) << "children list " << ictx->name << dendl;
 
-    int r = ictx->state->refresh_if_required();
-    if (r < 0) {
-      return r;
-    }
+        child_pool_id = child_image.pool_id;
+      }
 
-    RWLock::RLocker l(ictx->snap_lock);
-    cls::rbd::ParentImageSpec parent_spec{ictx->md_ctx.get_id(),
-                                          ictx->md_ctx.get_namespace(),
-                                          ictx->id, ictx->snap_id};
-    map< tuple<int64_t, string, string>, set<string> > image_info;
+      ImageCtx *imctx = new ImageCtx("", child_image.image_id, nullptr,
+                                     child_io_ctx, false);
+      r = imctx->state->open(0);
+      if (r < 0) {
+        lderr(cct) << "error opening image: " << cpp_strerror(r) << dendl;
+        return r;
+      }
 
-    r = api::Image<>::list_children(ictx, parent_spec, &image_info);
-    if (r < 0) {
-      return r;
-    }
+      if ((imctx->features & RBD_FEATURE_DEEP_FLATTEN) == 0 &&
+          !imctx->snaps.empty()) {
+        lderr(cct) << "snapshot in-use by " << pool << "/" << imctx->name
+                   << dendl;
+        imctx->state->close();
+        return -EBUSY;
+      }
 
-    for (auto &info : image_info) {
-      IoCtx ioctx;
-      r = util::create_ioctx(ictx->md_ctx, "child image",
-                             std::get<0>(info.first), std::get<2>(info.first),
-                             &ioctx);
+      librbd::NoOpProgressContext prog_ctx;
+      r = imctx->operations->flatten(prog_ctx);
       if (r < 0) {
+        lderr(cct) << "error flattening image: " << pool << "/"
+                   << (child_image.pool_namespace.empty() ?
+                        "" : "/" + child_image.pool_namespace)
+                   << child_image.image_name << cpp_strerror(r) << dendl;
+        imctx->state->close();
         return r;
       }
 
-      for (auto &id_it : info.second) {
-        string name;
-        bool trash = false;
-        r = cls_client::dir_get_name(&ioctx, RBD_DIRECTORY, id_it, &name);
-        if (r == -ENOENT) {
-          cls::rbd::TrashImageSpec trash_spec;
-          r = cls_client::trash_get(&ioctx, id_it, &trash_spec);
-          if (r < 0) {
-            if (r != -EOPNOTSUPP && r != -ENOENT) {
-              lderr(cct) << "Error looking up name for image id " << id_it
-                         << " in rbd trash" << dendl;
-              return r;
-            }
-            return -ENOENT;
-          }
-          name = trash_spec.name;
-          trash = true;
-        } else if (r < 0 && r != -ENOENT) {
-          lderr(cct) << "Error looking up name for image id " << id_it
-                     << " in pool " << std::get<1>(info.first)
-                     << (std::get<2>(info.first).empty() ?
-                          "" : "/" + std::get<2>(info.first))  << dendl;
-          return r;
-        }
-
-        // TODO support namespaces
-        names->push_back(
-        child_info_t {
-          std::get<1>(info.first),
-          name,
-          id_it,
-          trash
-        });
+      r = imctx->state->close();
+      if (r < 0) {
+        lderr(cct) << "failed to close image: " << cpp_strerror(r) << dendl;
+        return r;
       }
+
+      pctx.update_progress(++i, size);
+      ceph_assert(i <= size);
     }
-    std::sort(names->begin(), names->end(), compare_by_name);
 
     return 0;
   }
@@ -1092,67 +979,6 @@ bool compare_by_name(const child_info_t& c1, const child_info_t& c2)
     return ictx->get_parent_overlap(ictx->snap_id, overlap);
   }
 
-  int get_parent_info(ImageCtx *ictx, string *parent_pool_name,
-                      string *parent_name, string *parent_id,
-                      string *parent_snap_name)
-  {
-    int r = ictx->state->refresh_if_required();
-    if (r < 0)
-      return r;
-
-    RWLock::RLocker l(ictx->snap_lock);
-    RWLock::RLocker l2(ictx->parent_lock);
-    if (ictx->parent == NULL) {
-      return -ENOENT;
-    }
-
-    cls::rbd::ParentImageSpec parent_spec;
-
-    if (ictx->snap_id == CEPH_NOSNAP) {
-      parent_spec = ictx->parent_md.spec;
-    } else {
-      r = ictx->get_parent_spec(ictx->snap_id, &parent_spec);
-      if (r < 0) {
-       lderr(ictx->cct) << "Can't find snapshot id = " << ictx->snap_id
-                         << dendl;
-       return r;
-      }
-      if (parent_spec.pool_id == -1)
-       return -ENOENT;
-    }
-    if (parent_pool_name) {
-      Rados rados(ictx->md_ctx);
-      r = rados.pool_reverse_lookup(parent_spec.pool_id,
-                                   parent_pool_name);
-      if (r < 0) {
-       lderr(ictx->cct) << "error looking up pool name: " << cpp_strerror(r)
-                        << dendl;
-       return r;
-      }
-    }
-
-    if (parent_snap_name && parent_spec.snap_id != CEPH_NOSNAP) {
-      RWLock::RLocker l(ictx->parent->snap_lock);
-      r = ictx->parent->get_snap_name(parent_spec.snap_id,
-                                     parent_snap_name);
-      if (r < 0) {
-       lderr(ictx->cct) << "error finding parent snap name: "
-                        << cpp_strerror(r) << dendl;
-       return r;
-      }
-    }
-
-    if (parent_name) {
-      RWLock::RLocker snap_locker(ictx->parent->snap_lock);
-      *parent_name = ictx->parent->name;
-    }
-    if (parent_id) {
-      *parent_id = ictx->parent->id;
-    }
-
-    return 0;
-  }
-
   int get_flags(ImageCtx *ictx, uint64_t *flags)
   {
     int r = ictx->state->refresh_if_required();
index abb618d9971540ab41fd3f420b807906b18e5edb..1e1864f3a394b79b1ec28ac3828b74fc7d2d81af 100644 (file)
@@ -60,9 +60,6 @@ namespace librbd {
   void image_options_clear(rbd_image_options_t opts);
   bool image_options_is_empty(rbd_image_options_t opts);
 
-  int list(librados::IoCtx& io_ctx, std::vector<std::string>& names);
-  int list_children(ImageCtx *ictx,
-                    std::vector<child_info_t> *names);
   int create(librados::IoCtx& io_ctx, const char *imgname, uint64_t size,
             int *order);
   int create(librados::IoCtx& io_ctx, const char *imgname, uint64_t size,
@@ -88,9 +85,6 @@ namespace librbd {
   int get_size(ImageCtx *ictx, uint64_t *size);
   int get_features(ImageCtx *ictx, uint64_t *features);
   int get_overlap(ImageCtx *ictx, uint64_t *overlap);
-  int get_parent_info(ImageCtx *ictx, std::string *parent_pool_name,
-                      std::string *parent_name, std::string *parent_id,
-                      std::string *parent_snap_name);
   int get_flags(ImageCtx *ictx, uint64_t *flags);
   int set_image_notification(ImageCtx *ictx, int fd, int type);
   int is_exclusive_lock_owner(ImageCtx *ictx, bool *is_owner);
index 5f9aacd191d0fc056bed931f4007887ff443e1d5..12450be630f494f7dee0d280f9558aab9c197021 100644 (file)
@@ -677,13 +677,30 @@ namespace librbd {
   }
 
   int RBD::list(IoCtx& io_ctx, vector<string>& names)
+  {
+    std::vector<image_spec_t> image_specs;
+    int r = list2(io_ctx, &image_specs);
+    if (r < 0) {
+      return r;
+    }
+
+    names.clear();
+    for (auto& it : image_specs) {
+      names.push_back(it.name);
+    }
+    return 0;
+  }
+
+  int RBD::list2(IoCtx& io_ctx, std::vector<image_spec_t> *images)
   {
     TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
-    tracepoint(librbd, list_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id());
-    int r = librbd::list(io_ctx, names);
+    tracepoint(librbd, list_enter, io_ctx.get_pool_name().c_str(),
+               io_ctx.get_id());
+
+    int r = librbd::api::Image<>::list_images(io_ctx, images);
     if (r >= 0) {
-      for (vector<string>::iterator itr = names.begin(), end = names.end(); itr != end; ++itr) {
-       tracepoint(librbd, list_entry, itr->c_str());
+      for (auto& it : *images) {
+        tracepoint(librbd, list_entry, it.name.c_str());
       }
     }
     tracepoint(librbd, list_exit, r, r);
@@ -1425,23 +1442,60 @@ namespace librbd {
   int Image::parent_info(string *parent_pool_name, string *parent_name,
                         string *parent_snap_name)
   {
-    return parent_info2(parent_pool_name, parent_name, nullptr,
-                        parent_snap_name);
+    librbd::linked_image_spec_t parent_image;
+    librbd::snap_spec_t parent_snap;
+    int r = get_parent(&parent_image, &parent_snap);
+    if (r >= 0) {
+      if (parent_pool_name != nullptr) {
+        *parent_pool_name = parent_image.pool_name;
+      }
+      if (parent_name != nullptr) {
+        *parent_name = parent_image.image_name;
+      }
+      if (parent_snap_name != nullptr) {
+        *parent_snap_name = parent_snap.name;
+      }
+    }
+    return r;
   }
 
   int Image::parent_info2(string *parent_pool_name, string *parent_name,
                           string *parent_id, string *parent_snap_name)
   {
-    ImageCtx *ictx = (ImageCtx *)ctx;
+    librbd::linked_image_spec_t parent_image;
+    librbd::snap_spec_t parent_snap;
+    int r = get_parent(&parent_image, &parent_snap);
+    if (r >= 0) {
+      if (parent_pool_name != nullptr) {
+        *parent_pool_name = parent_image.pool_name;
+      }
+      if (parent_name != nullptr) {
+        *parent_name = parent_image.image_name;
+      }
+      if (parent_id != nullptr) {
+        *parent_id = parent_image.image_id;
+      }
+      if (parent_snap_name != nullptr) {
+        *parent_snap_name = parent_snap.name;
+      }
+    }
+    return r;
+  }
+
+  int Image::get_parent(linked_image_spec_t *parent_image,
+                        snap_spec_t *parent_snap)
+  {
+    auto ictx = reinterpret_cast<ImageCtx*>(ctx);
     tracepoint(librbd, get_parent_info_enter, ictx, ictx->name.c_str(),
                ictx->snap_name.c_str(), ictx->read_only);
-    int r = librbd::get_parent_info(ictx, parent_pool_name, parent_name,
-                                    parent_id, parent_snap_name);
+
+    int r = librbd::api::Image<>::get_parent(ictx, parent_image, parent_snap);
+
     tracepoint(librbd, get_parent_info_exit, r,
-               parent_pool_name ? parent_pool_name->c_str() : NULL,
-               parent_name ? parent_name->c_str() : NULL,
-               parent_id ? parent_id->c_str() : NULL,
-               parent_snap_name ? parent_snap_name->c_str() : NULL);
+               parent_image->pool_name.c_str(),
+               parent_image->image_name.c_str(),
+               parent_image->image_id.c_str(),
+               parent_snap->name.c_str());
     return r;
   }
 
@@ -1659,34 +1713,53 @@ namespace librbd {
 
   int Image::list_children(set<pair<string, string> > *children)
   {
-    ImageCtx *ictx = (ImageCtx *)ctx;
-    tracepoint(librbd, list_children_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
-    vector<librbd::child_info_t> children2;
-    int r = librbd::list_children(ictx, &children2);
-    if (r >= 0) {
-      for (std::vector<librbd::child_info_t>::iterator it = children2.begin();
-           it != children2.end(); ++it) {
-        if (!it->trash) {
-          children->insert(make_pair(it->pool_name, it->image_name));
-          tracepoint(librbd, list_children_entry, it->pool_name.c_str(), it->image_name.c_str());
-        }
+    std::vector<linked_image_spec_t> images;
+    int r = list_children3(&images);
+    if (r < 0) {
+      return r;
+    }
+
+    for (auto& image : images) {
+      if (!image.trash) {
+        children->insert({image.pool_name, image.image_name});
       }
     }
-    tracepoint(librbd, list_children_exit, r);
-    return r;
+    return 0;
   }
 
   int Image::list_children2(vector<librbd::child_info_t> *children)
   {
-    ImageCtx *ictx = (ImageCtx *)ctx;
-    tracepoint(librbd, list_children_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
-    int r = librbd::list_children(ictx, children);
+    std::vector<linked_image_spec_t> images;
+    int r = list_children3(&images);
+    if (r < 0) {
+      return r;
+    }
+
+    for (auto& image : images) {
+      children->push_back({
+        .pool_name = image.pool_name,
+        .image_name = image.image_name,
+        .image_id = image.image_id,
+        .trash = image.trash});
+    }
+
+    return 0;
+  }
+
+  int Image::list_children3(std::vector<linked_image_spec_t> *images)
+  {
+    auto ictx = reinterpret_cast<ImageCtx*>(ctx);
+    tracepoint(librbd, list_children_enter, ictx, ictx->name.c_str(),
+               ictx->snap_name.c_str(), ictx->read_only);
+
+    int r = librbd::api::Image<>::list_children(ictx, images);
     if (r >= 0) {
-      for (std::vector<librbd::child_info_t>::iterator it = children->begin();
-           it != children->end(); ++it) {
-        tracepoint(librbd, list_children_entry, it->pool_name.c_str(), it->image_name.c_str());
+      for (auto& it : *images) {
+        tracepoint(librbd, list_children_entry, it.pool_name.c_str(),
+                   it.image_name.c_str());
       }
     }
+
     tracepoint(librbd, list_children_exit, r);
     return r;
   }
@@ -2802,15 +2875,54 @@ extern "C" void rbd_mirror_image_instance_id_list_cleanup(
   }
 }
 
+/* helpers */
+
+extern "C" void rbd_image_spec_cleanup(rbd_image_spec_t *image)
+{
+  free(image->id);
+  free(image->name);
+}
+
+extern "C" void rbd_image_spec_list_cleanup(rbd_image_spec_t *images,
+                                            size_t num_images)
+{
+  for (size_t idx = 0; idx < num_images; ++idx) {
+    rbd_image_spec_cleanup(&images[idx]);
+  }
+}
+
+extern "C" void rbd_linked_image_spec_cleanup(rbd_linked_image_spec_t *image)
+{
+  free(image->pool_name);
+  free(image->pool_namespace);
+  free(image->image_id);
+  free(image->image_name);
+}
+
+extern "C" void rbd_linked_image_spec_list_cleanup(
+    rbd_linked_image_spec_t *images, size_t num_images)
+{
+  for (size_t idx = 0; idx < num_images; ++idx) {
+    rbd_linked_image_spec_cleanup(&images[idx]);
+  }
+}
+
+extern "C" void rbd_snap_spec_cleanup(rbd_snap_spec_t *snap)
+{
+  free(snap->name);
+}
+
 /* images */
 extern "C" int rbd_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, 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);
+  tracepoint(librbd, list_enter, io_ctx.get_pool_name().c_str(),
+             io_ctx.get_id());
+  std::vector<librbd::image_spec_t> cpp_image_specs;
+  int r = librbd::api::Image<>::list_images(io_ctx, &cpp_image_specs);
   if (r < 0) {
     tracepoint(librbd, list_exit, r, *size);
     return r;
@@ -2818,8 +2930,8 @@ extern "C" int rbd_list(rados_ioctx_t p, char *names, size_t *size)
 
   size_t expected_size = 0;
 
-  for (size_t i = 0; i < cpp_names.size(); i++) {
-    expected_size += cpp_names[i].size() + 1;
+  for (auto& it : cpp_image_specs) {
+    expected_size += it.name.size() + 1;
   }
   if (*size < expected_size) {
     *size = expected_size;
@@ -2832,8 +2944,8 @@ extern "C" int rbd_list(rados_ioctx_t p, char *names, size_t *size)
     return -EINVAL;
   }
 
-  for (int i = 0; i < (int)cpp_names.size(); i++) {
-    const char* name = cpp_names[i].c_str();
+  for (auto& it : cpp_image_specs) {
+    const char* name = it.name.c_str();
     tracepoint(librbd, list_entry, name);
     strcpy(names, name);
     names += strlen(names) + 1;
@@ -2842,6 +2954,38 @@ extern "C" int rbd_list(rados_ioctx_t p, char *names, size_t *size)
   return (int)expected_size;
 }
 
+extern "C" int rbd_list2(rados_ioctx_t p, rbd_image_spec_t *images,
+                         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, list_enter, io_ctx.get_pool_name().c_str(),
+             io_ctx.get_id());
+  std::vector<librbd::image_spec_t> cpp_image_specs;
+  int r = librbd::api::Image<>::list_images(io_ctx, &cpp_image_specs);
+  if (r < 0) {
+    tracepoint(librbd, list_exit, r, *size);
+    return r;
+  }
+
+  size_t expected_size = cpp_image_specs.size();
+  if (*size < expected_size) {
+    *size = expected_size;
+    tracepoint(librbd, list_exit, -ERANGE, *size);
+    return -ERANGE;
+  }
+
+  *size = expected_size;
+  for (size_t idx = 0; idx < expected_size; ++idx) {
+    images[idx].id = strdup(cpp_image_specs[idx].id.c_str());
+    images[idx].name = strdup(cpp_image_specs[idx].name.c_str());
+  }
+  tracepoint(librbd, list_exit, 0, *size);
+  return 0;
+}
+
 extern "C" int rbd_create(rados_ioctx_t p, const char *name, uint64_t size, int *order)
 {
   librados::IoCtx io_ctx;
@@ -3985,9 +4129,48 @@ extern "C" int rbd_get_parent_info(rbd_image_t image,
                                    char *parent_name, size_t pnamelen,
                                    char *parent_snap_name, size_t psnap_namelen)
 {
-  return rbd_get_parent_info2(image, parent_pool_name, ppool_namelen,
-                              parent_name, pnamelen, nullptr, 0,
-                              parent_snap_name, psnap_namelen);
+  auto ictx = reinterpret_cast<librbd::ImageCtx*>(image);
+  tracepoint(librbd, get_parent_info_enter, ictx, ictx->name.c_str(),
+             ictx->snap_name.c_str(), ictx->read_only);
+
+  librbd::linked_image_spec_t parent_image;
+  librbd::snap_spec_t parent_snap;
+  int r = librbd::api::Image<>::get_parent(ictx, &parent_image, &parent_snap);
+  if (r >= 0) {
+    if (parent_pool_name) {
+      if (parent_image.pool_name.length() + 1 > ppool_namelen) {
+        r = -ERANGE;
+      } else {
+        strcpy(parent_pool_name, parent_image.pool_name.c_str());
+      }
+    }
+    if (parent_name) {
+      if (parent_image.image_name.length() + 1 > pnamelen) {
+        r = -ERANGE;
+      } else {
+        strcpy(parent_name, parent_image.image_name.c_str());
+      }
+    }
+    if (parent_snap_name) {
+      if (parent_snap.name.length() + 1 > psnap_namelen) {
+        r = -ERANGE;
+      } else {
+        strcpy(parent_snap_name, parent_snap.name.c_str());
+      }
+    }
+  }
+
+  if (r < 0) {
+    tracepoint(librbd, get_parent_info_exit, r, NULL, NULL, NULL, NULL);
+    return r;
+  }
+
+  tracepoint(librbd, get_parent_info_exit, r,
+             parent_image.pool_name.c_str(),
+             parent_image.image_name.c_str(),
+             parent_image.image_id.c_str(),
+             parent_snap.name.c_str());
+  return 0;
 }
 
 extern "C" int rbd_get_parent_info2(rbd_image_t image,
@@ -3998,56 +4181,94 @@ extern "C" int rbd_get_parent_info2(rbd_image_t image,
                                     char *parent_snap_name,
                                     size_t psnap_namelen)
 {
-  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
+  auto ictx = reinterpret_cast<librbd::ImageCtx*>(image);
   tracepoint(librbd, get_parent_info_enter, ictx, ictx->name.c_str(),
              ictx->snap_name.c_str(), ictx->read_only);
-  string p_pool_name, p_name, p_id, p_snap_name;
-
-  int r = librbd::get_parent_info(ictx, &p_pool_name, &p_name, &p_id,
-                                  &p_snap_name);
-  if (r < 0) {
-    tracepoint(librbd, get_parent_info_exit, r, NULL, NULL, NULL, NULL);
-    return r;
-  }
 
-  if (parent_pool_name) {
-    if (p_pool_name.length() + 1 > ppool_namelen) {
-      tracepoint(librbd, get_parent_info_exit, -ERANGE, NULL, NULL, NULL, NULL);
-      return -ERANGE;
+  librbd::linked_image_spec_t parent_image;
+  librbd::snap_spec_t parent_snap;
+  int r = librbd::api::Image<>::get_parent(ictx, &parent_image, &parent_snap);
+  if (r >= 0) {
+    if (parent_pool_name) {
+      if (parent_image.pool_name.length() + 1 > ppool_namelen) {
+        r = -ERANGE;
+      } else {
+        strcpy(parent_pool_name, parent_image.pool_name.c_str());
+      }
     }
-
-    strcpy(parent_pool_name, p_pool_name.c_str());
-  }
-  if (parent_name) {
-    if (p_name.length() + 1 > pnamelen) {
-      tracepoint(librbd, get_parent_info_exit, -ERANGE, NULL, NULL, NULL, NULL);
-      return -ERANGE;
+    if (parent_name) {
+      if (parent_image.image_name.length() + 1 > pnamelen) {
+        r = -ERANGE;
+      } else {
+        strcpy(parent_name, parent_image.image_name.c_str());
+      }
     }
-
-    strcpy(parent_name, p_name.c_str());
+    if (parent_id) {
+      if (parent_image.image_id.length() + 1 > pidlen) {
+        r = -ERANGE;
+      } else {
+        strcpy(parent_id, parent_image.image_id.c_str());
+      }
   }
-  if (parent_id) {
-    if (p_id.length() + 1 > pidlen) {
-      tracepoint(librbd, get_parent_info_exit, -ERANGE, NULL, NULL, NULL, NULL);
-      return -ERANGE;
+    if (parent_snap_name) {
+      if (parent_snap.name.length() + 1 > psnap_namelen) {
+        r = -ERANGE;
+      } else {
+        strcpy(parent_snap_name, parent_snap.name.c_str());
+      }
     }
-
-    strcpy(parent_id, p_id.c_str());
   }
-  if (parent_snap_name) {
-    if (p_snap_name.length() + 1 > psnap_namelen) {
-      tracepoint(librbd, get_parent_info_exit, -ERANGE, NULL, NULL, NULL, NULL);
-      return -ERANGE;
-    }
 
-    strcpy(parent_snap_name, p_snap_name.c_str());
+  if (r < 0) {
+    tracepoint(librbd, get_parent_info_exit, r, NULL, NULL, NULL, NULL);
+    return r;
   }
 
-  tracepoint(librbd, get_parent_info_exit, 0, parent_pool_name, parent_name,
-             parent_id, parent_snap_name);
+  tracepoint(librbd, get_parent_info_exit, r,
+             parent_image.pool_name.c_str(),
+             parent_image.image_name.c_str(),
+             parent_image.image_id.c_str(),
+             parent_snap.name.c_str());
   return 0;
 }
 
+extern "C" int rbd_get_parent(rbd_image_t image,
+                              rbd_linked_image_spec_t *parent_image,
+                              rbd_snap_spec_t *parent_snap)
+{
+  auto ictx = reinterpret_cast<librbd::ImageCtx*>(image);
+  tracepoint(librbd, get_parent_info_enter, ictx, ictx->name.c_str(),
+             ictx->snap_name.c_str(), ictx->read_only);
+
+  librbd::linked_image_spec_t cpp_parent_image;
+  librbd::snap_spec_t cpp_parent_snap;
+  int r = librbd::api::Image<>::get_parent(ictx, &cpp_parent_image,
+                                           &cpp_parent_snap);
+  if (r < 0) {
+    memset(parent_image, 0, sizeof(rbd_linked_image_spec_t));
+    memset(parent_snap, 0, sizeof(rbd_snap_spec_t));
+  } else {
+    *parent_image = {
+      .pool_id = cpp_parent_image.pool_id,
+      .pool_name = strdup(cpp_parent_image.pool_name.c_str()),
+      .pool_namespace = strdup(cpp_parent_image.pool_namespace.c_str()),
+      .image_id = strdup(cpp_parent_image.image_id.c_str()),
+      .image_name = strdup(cpp_parent_image.image_name.c_str()),
+      .trash = cpp_parent_image.trash};
+    *parent_snap = {
+      .id = cpp_parent_snap.id,
+      .namespace_type = cpp_parent_snap.namespace_type,
+      .name = strdup(cpp_parent_snap.name.c_str())};
+  }
+
+  tracepoint(librbd, get_parent_info_exit, r,
+             parent_image->pool_name,
+             parent_image->image_name,
+             parent_image->image_id,
+             parent_snap->name);
+  return r;
+}
+
 extern "C" int rbd_get_flags(rbd_image_t image, uint64_t *flags)
 {
   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
@@ -4379,30 +4600,29 @@ extern "C" ssize_t rbd_list_children(rbd_image_t image, char *pools,
                                     size_t *pools_len, char *images,
                                     size_t *images_len)
 {
-  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
-  tracepoint(librbd, list_children_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
-  set<pair<string, string> > image_set;
-  vector<librbd::child_info_t> children;
+  auto ictx = reinterpret_cast<librbd::ImageCtx*>(image);
+  tracepoint(librbd, list_children_enter, ictx, ictx->name.c_str(),
+             ictx->snap_name.c_str(), ictx->read_only);
 
-  int r = librbd::list_children(ictx, &children);
+  std::vector<librbd::linked_image_spec_t> cpp_images;
+  int r = librbd::api::Image<>::list_children(ictx, &cpp_images);
   if (r < 0) {
     tracepoint(librbd, list_children_exit, r);
     return r;
   }
 
-  for (std::vector<librbd::child_info_t>::iterator it = children.begin();
-       it != children.end(); ++it) {
-    if (!it->trash) {
-      image_set.insert(make_pair(it->pool_name, it->image_name));
+  std::set<std::pair<std::string, std::string>> image_set;
+  for (auto& image : cpp_images) {
+    if (!image.trash) {
+      image_set.insert({image.pool_name, image.image_name});
     }
   }
 
   size_t pools_total = 0;
   size_t images_total = 0;
-  for (set<pair<string, string> >::const_iterator it = image_set.begin();
-       it != image_set.end(); ++it) {
-    pools_total += it->first.length() + 1;
-    images_total += it->second.length() + 1;
+  for (auto it : image_set) {
+    pools_total += it.first.length() + 1;
+    images_total += it.second.length() + 1;
   }
 
   bool too_short = false;
@@ -4419,14 +4639,13 @@ extern "C" ssize_t rbd_list_children(rbd_image_t image, char *pools,
 
   char *pools_p = pools;
   char *images_p = images;
-  for (set<pair<string, string> >::const_iterator it = image_set.begin();
-       it != image_set.end(); ++it) {
-    const char* pool = it->first.c_str();
+  for (auto it : image_set) {
+    const char* pool = it.first.c_str();
     strcpy(pools_p, pool);
-    pools_p += it->first.length() + 1;
-    const char* image = it->second.c_str();
+    pools_p += it.first.length() + 1;
+    const char* image = it.second.c_str();
     strcpy(images_p, image);
-    images_p += it->second.length() + 1;
+    images_p += it.second.length() + 1;
     tracepoint(librbd, list_children_entry, pool, image);
   }
 
@@ -4439,24 +4658,22 @@ extern "C" int rbd_list_children2(rbd_image_t image,
                                   rbd_child_info_t *children,
                                  int *max_children)
 {
-  vector<librbd::child_info_t> cpp_children;
-  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
-  tracepoint(librbd, list_children_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
+  auto ictx = reinterpret_cast<librbd::ImageCtx*>(image);
+  tracepoint(librbd, list_children_enter, ictx, ictx->name.c_str(),
+             ictx->snap_name.c_str(), ictx->read_only);
 
   if (!max_children) {
     tracepoint(librbd, list_children_exit, -EINVAL);
     return -EINVAL;
   }
 
-  int r = librbd::list_children(ictx, &cpp_children);
-  if (r == -ENOENT) {
-    tracepoint(librbd, list_children_exit, *max_children);
-    r = 0;
-  }
+  std::vector<librbd::linked_image_spec_t> cpp_children;
+  int r = librbd::api::Image<>::list_children(ictx, &cpp_children);
   if (r < 0) {
-    tracepoint(librbd, list_children_exit, *max_children);
+    tracepoint(librbd, list_children_exit, r);
     return r;
   }
+
   if (*max_children < (int)cpp_children.size() + 1) {
     *max_children = (int)cpp_children.size() + 1;
     tracepoint(librbd, list_children_exit, *max_children);
@@ -4469,13 +4686,8 @@ extern "C" int rbd_list_children2(rbd_image_t image,
     children[i].image_name = strdup(cpp_children[i].image_name.c_str());
     children[i].image_id = strdup(cpp_children[i].image_id.c_str());
     children[i].trash = cpp_children[i].trash;
-    if (!children[i].pool_name || !children[i].image_name ||
-        !children[i].image_id) {
-      rbd_list_children_cleanup(&children[i], i);
-      tracepoint(librbd, list_children_exit, *max_children);
-      return -ENOMEM;
-    }
-    tracepoint(librbd, list_children_entry, children[i].pool_name, children[i].image_name);
+    tracepoint(librbd, list_children_entry, children[i].pool_name,
+               children[i].image_name);
   }
   children[i].pool_name = NULL;
   children[i].image_name = NULL;
@@ -4497,8 +4709,45 @@ extern "C" void rbd_list_children_cleanup(rbd_child_info_t *children,
                                           size_t num_children)
 {
   for (size_t i=0; i < num_children; i++) {
-    rbd_list_child_cleanup(&children[i]);
+    free((void *)children[i].pool_name);
+    free((void *)children[i].image_name);
+    free((void *)children[i].image_id);
+  }
+}
+
+extern "C" int rbd_list_children3(rbd_image_t image,
+                                    rbd_linked_image_spec_t *images,
+                                    size_t *max_images)
+{
+  auto ictx = reinterpret_cast<librbd::ImageCtx*>(image);
+  tracepoint(librbd, list_children_enter, ictx, ictx->name.c_str(),
+             ictx->snap_name.c_str(), ictx->read_only);
+
+  std::vector<librbd::linked_image_spec_t> cpp_children;
+  int r = librbd::api::Image<>::list_children(ictx, &cpp_children);
+  if (r < 0) {
+    tracepoint(librbd, list_children_exit, r);
+    return r;
   }
+
+  if (*max_images < cpp_children.size()) {
+    *max_images = cpp_children.size();
+    return -ERANGE;
+  }
+
+  *max_images = cpp_children.size();
+  for (size_t idx = 0; idx < cpp_children.size(); ++idx) {
+    images[idx] = {
+      .pool_id = cpp_children[idx].pool_id,
+      .pool_name = strdup(cpp_children[idx].pool_name.c_str()),
+      .pool_namespace = strdup(cpp_children[idx].pool_namespace.c_str()),
+      .image_id = strdup(cpp_children[idx].image_id.c_str()),
+      .image_name = strdup(cpp_children[idx].image_name.c_str()),
+      .trash = cpp_children[idx].trash};
+    tracepoint(librbd, list_children_entry, images[idx].pool_name,
+               images[idx].image_name);
+  }
+  return 0;
 }
 
 extern "C" ssize_t rbd_list_lockers(rbd_image_t image, int *exclusive,
index 69f4493fb81fbf0ea04f8f85858d4c7fb4e16ea5..78b1c4c0c8d5de405e140582e803800b5527fb7d 100644 (file)
@@ -114,12 +114,28 @@ cdef extern from "rbd/librbd.h" nogil:
         char *name
         int64_t pool
 
-    ctypedef struct rbd_child_info_t:
+    ctypedef struct rbd_image_spec_t:
+        char *id
+        char *name
+
+    ctypedef struct rbd_linked_image_spec_t:
+        int64_t pool_id
         char *pool_name
-        char *image_name
+        char *pool_namespace
         char *image_id
+        char *image_name
         bint trash
 
+    ctypedef enum rbd_snap_namespace_type_t:
+        _RBD_SNAP_NAMESPACE_TYPE_USER "RBD_SNAP_NAMESPACE_TYPE_USER"
+        _RBD_SNAP_NAMESPACE_TYPE_GROUP "RBD_SNAP_NAMESPACE_TYPE_GROUP"
+        _RBD_SNAP_NAMESPACE_TYPE_TRASH "RBD_SNAP_NAMESPACE_TYPE_TRASH"
+
+    ctypedef struct rbd_snap_spec_t:
+        uint64_t id
+        rbd_snap_namespace_type_t namespace_type
+        char *name
+
     ctypedef enum rbd_mirror_mode_t:
         _RBD_MIRROR_MODE_DISABLED "RBD_MIRROR_MODE_DISABLED"
         _RBD_MIRROR_MODE_IMAGE "RBD_MIRROR_MODE_IMAGE"
@@ -160,11 +176,6 @@ cdef extern from "rbd/librbd.h" nogil:
         time_t last_update
         bint up
 
-    ctypedef enum rbd_snap_namespace_type_t:
-        _RBD_SNAP_NAMESPACE_TYPE_USER "RBD_SNAP_NAMESPACE_TYPE_USER"
-        _RBD_SNAP_NAMESPACE_TYPE_GROUP "RBD_SNAP_NAMESPACE_TYPE_GROUP"
-        _RBD_SNAP_NAMESPACE_TYPE_TRASH "RBD_SNAP_NAMESPACE_TYPE_TRASH"
-
     ctypedef enum rbd_lock_mode_t:
         _RBD_LOCK_MODE_EXCLUSIVE "RBD_LOCK_MODE_EXCLUSIVE"
         _RBD_LOCK_MODE_SHARED "RBD_LOCK_MODE_SHARED"
@@ -248,6 +259,12 @@ cdef extern from "rbd/librbd.h" nogil:
 
     void rbd_version(int *major, int *minor, int *extra)
 
+    void rbd_image_spec_list_cleanup(rbd_image_spec_t *image, size_t num_images)
+    void rbd_linked_image_spec_cleanup(rbd_linked_image_spec_t *image)
+    void rbd_linked_image_spec_list_cleanup(rbd_linked_image_spec_t *images,
+                                            size_t num_images)
+    void rbd_snap_spec_cleanup(rbd_snap_spec_t *snap)
+
     void rbd_image_options_create(rbd_image_options_t* opts)
     void rbd_image_options_destroy(rbd_image_options_t opts)
     int rbd_image_options_set_string(rbd_image_options_t opts, int optname,
@@ -263,6 +280,8 @@ cdef extern from "rbd/librbd.h" nogil:
     int rbd_image_options_is_empty(rbd_image_options_t opts)
 
     int rbd_list(rados_ioctx_t io, char *names, size_t *size)
+    int rbd_list2(rados_ioctx_t io, rbd_image_spec_t *images,
+                  size_t *num_images)
     int rbd_create(rados_ioctx_t io, const char *name, uint64_t size,
                    int *order)
     int rbd_create4(rados_ioctx_t io, const char *name, uint64_t size,
@@ -379,11 +398,9 @@ cdef extern from "rbd/librbd.h" nogil:
     int rbd_get_block_name_prefix(rbd_image_t image, char *prefix,
                                   size_t prefix_len)
     int64_t rbd_get_data_pool_id(rbd_image_t image)
-    int rbd_get_parent_info2(rbd_image_t image,
-                             char *parent_poolname, size_t ppoolnamelen,
-                             char *parent_name, size_t pnamelen,
-                             char *parent_id, size_t pidlen,
-                             char *parent_snapname, size_t psnapnamelen)
+    int rbd_get_parent(rbd_image_t image,
+                       rbd_linked_image_spec_t *parent_image,
+                       rbd_snap_spec_t *parent_snap)
     int rbd_get_flags(rbd_image_t image, uint64_t *flags)
     int rbd_get_group(rbd_image_t image, rbd_group_info_t *group_info,
                       size_t group_info_size)
@@ -428,16 +445,12 @@ cdef extern from "rbd/librbd.h" nogil:
     int rbd_snap_get_trash_namespace(rbd_image_t image, uint64_t snap_id,
                                      char *original_name, size_t max_length)
 
-
     int rbd_flatten(rbd_image_t image)
     int rbd_rebuild_object_map(rbd_image_t image, librbd_progress_fn_t cb,
                                void *cbdata)
-    ssize_t rbd_list_children(rbd_image_t image, char *pools, size_t *pools_len,
-                              char *images, size_t *images_len)
-    int rbd_list_children2(rbd_image_t image, rbd_child_info_t *children,
-                           int *max_children)
-    void rbd_list_children_cleanup(rbd_child_info_t *children,
-                                   size_t num_children)
+    int rbd_list_children3(rbd_image_t image, rbd_linked_image_spec_t *children,
+                           size_t *max_children)
+
     ssize_t rbd_list_lockers(rbd_image_t image, int *exclusive,
                              char *tag, size_t *tag_len,
                              char *clients, size_t *clients_len,
@@ -1141,6 +1154,16 @@ class RBD(object):
         finally:
             free(c_names)
 
+    def list2(self, ioctx):
+        """
+        Iterate over the images in the pool.
+
+        :param ioctx: determines which RADOS pool the image is in
+        :type ioctx: :class:`rados.Ioctx`
+        :returns: :class:`ImageIterator`
+        """
+        return ImageIterator(ioctx)
+
     def remove(self, ioctx, name):
         """
         Delete an RBD image. This may take a long time, since it does
@@ -2796,29 +2819,20 @@ cdef class Image(object):
         :raises: :class:`ImageNotFound` if the image doesn't have a parent
         """
         cdef:
-            int ret = -errno.ERANGE
-            size_t size = 8
-            char *pool = NULL
-            char *name = NULL
-            char *snapname = NULL
-        try:
-            while ret == -errno.ERANGE and size <= 4096:
-                pool = <char *>realloc_chk(pool, size)
-                name = <char *>realloc_chk(name, size)
-                snapname = <char *>realloc_chk(snapname, size)
-                with nogil:
-                    ret = rbd_get_parent_info2(self.image, pool, size, name,
-                                               size, NULL, 0, snapname, size)
-                if ret == -errno.ERANGE:
-                    size *= 2
+            rbd_linked_image_spec_t parent_spec
+            rbd_snap_spec_t snap_spec
+        with nogil:
+            ret = rbd_get_parent(self.image, &parent_spec, &snap_spec)
+        if ret != 0:
+            raise make_ex(ret, 'error getting parent info for image %s' % self.name)
 
-            if ret != 0:
-                raise make_ex(ret, 'error getting parent info for image %s' % self.name)
-            return (decode_cstr(pool), decode_cstr(name), decode_cstr(snapname))
-        finally:
-            free(pool)
-            free(name)
-            free(snapname)
+        result = (decode_cstr(parent_spec.pool_name),
+                  decode_cstr(parent_spec.image_name),
+                  decode_cstr(snap_spec.name))
+
+        rbd_linked_image_spec_cleanup(&parent_spec)
+        rbd_snap_spec_cleanup(&snap_spec)
+        return result
 
     def parent_id(self):
         """
@@ -2828,23 +2842,18 @@ cdef class Image(object):
         :raises: :class:`ImageNotFound` if the image doesn't have a parent
         """
         cdef:
-            int ret = -errno.ERANGE
-            size_t size = 32
-            char *parent_id = NULL
-        try:
-            while ret == -errno.ERANGE and size <= 4096:
-                parent_id = <char *>realloc_chk(parent_id, size)
-                with nogil:
-                    ret = rbd_get_parent_info2(self.image, NULL, 0, NULL, 0,
-                                               parent_id, size, NULL, 0)
-                if ret == -errno.ERANGE:
-                    size *= 2
+            rbd_linked_image_spec_t parent_spec
+            rbd_snap_spec_t snap_spec
+        with nogil:
+            ret = rbd_get_parent(self.image, &parent_spec, &snap_spec)
+        if ret != 0:
+            raise make_ex(ret, 'error getting parent info for image %s' % self.name)
 
-            if ret != 0:
-                raise make_ex(ret, 'error getting parent id for image %s' % self.name)
-            return decode_cstr(parent_id)
-        finally:
-            free(parent_id)
+        result = decode_cstr(parent_spec.image_id)
+
+        rbd_linked_image_spec_cleanup(&parent_spec)
+        rbd_snap_spec_cleanup(&snap_spec)
+        return result
 
     def old_format(self):
         """
@@ -3598,28 +3607,27 @@ written." % (self.name, ret, length))
         :returns: list - a list of (pool name, image name) tuples
         """
         cdef:
-            size_t pools_size = 512, images_size = 512
-            char *c_pools = NULL
-            char *c_images = NULL
+            rbd_linked_image_spec_t *children = NULL
+            size_t num_children = 10
+
         try:
             while True:
-                c_pools = <char *>realloc_chk(c_pools, pools_size)
-                c_images = <char *>realloc_chk(c_images, images_size)
+                children = <rbd_linked_image_spec_t*>realloc_chk(
+                    children, num_children * sizeof(rbd_linked_image_spec_t))
                 with nogil:
-                    ret = rbd_list_children(self.image, c_pools, &pools_size,
-                                            c_images, &images_size)
+                    ret = rbd_list_children3(self.image, children,
+                                             &num_children)
                 if ret >= 0:
                     break
                 elif ret != -errno.ERANGE:
-                    raise make_ex(ret, 'error listing images')
-            if ret == 0:
-                return []
-            pools = map(decode_cstr, c_pools[:pools_size - 1].split(b'\0'))
-            images = map(decode_cstr, c_images[:images_size - 1].split(b'\0'))
-            return list(zip(pools, images))
+                    raise make_ex(ret, 'error listing children.')
+
+            return [(decode_cstr(x.pool_name), decode_cstr(x.image_name)) for x
+                    in children[:num_children] if not x.trash]
         finally:
-            free(c_pools)
-            free(c_images)
+            if children:
+                rbd_linked_image_spec_list_cleanup(children, num_children)
+                free(children)
 
     def list_children2(self):
         """
@@ -4254,6 +4262,49 @@ written." % (self.name, ret, length))
             free(_name)
 
 
+cdef class ImageIterator(object):
+    """
+    Iterator over RBD images in a pool
+
+    Yields a dictionary containing information about the images
+
+    Keys are:
+
+    * ``id`` (str) - image id
+
+    * ``name`` (str) - image name
+    """
+    cdef rados_ioctx_t ioctx
+    cdef rbd_image_spec_t *images
+    cdef size_t num_images
+
+    def __init__(self, ioctx):
+        self.ioctx = convert_ioctx(ioctx)
+        self.images = NULL
+        self.num_images = 32
+        while True:
+            self.images = <rbd_image_spec_t*>realloc_chk(
+                self.images, self.num_images * sizeof(rbd_image_spec_t))
+            with nogil:
+                ret = rbd_list2(self.ioctx, self.images, &self.num_images)
+            if ret >= 0:
+                break
+            elif ret != -errno.ERANGE:
+                raise make_ex(ret, 'error listing images.')
+
+    def __iter__(self):
+        for i in range(self.num_images):
+            yield {
+                'id'   : decode_cstr(self.images[i].id),
+                'name' : decode_cstr(self.images[i].name)
+                }
+
+    def __dealloc__(self):
+        if self.images:
+            rbd_image_spec_list_cleanup(self.images, self.num_images)
+            free(self.images)
+
+
 cdef class LockOwnerIterator(object):
     """
     Iterator over managed lock owners for an image
@@ -4506,6 +4557,8 @@ cdef class ChildIterator(object):
 
     * ``pool`` (str) - name of the pool
 
+    * ``pool_namespace`` (str) - namespace of the pool
+
     * ``image`` (str) - name of the child
 
     * ``id`` (str) - id of the child
@@ -4513,8 +4566,8 @@ cdef class ChildIterator(object):
     * ``trash`` (bool) - True if child is in trash bin
     """
 
-    cdef rbd_child_info_t *children
-    cdef int num_children
+    cdef rbd_linked_image_spec_t *children
+    cdef size_t num_children
     cdef object image
 
     def __init__(self, Image image):
@@ -4522,13 +4575,11 @@ cdef class ChildIterator(object):
         self.children = NULL
         self.num_children = 10
         while True:
-            self.children = <rbd_child_info_t*>realloc_chk(self.children,
-                                                           self.num_children *
-                                                           sizeof(rbd_child_info_t))
+            self.children = <rbd_linked_image_spec_t*>realloc_chk(
+                self.children, self.num_children * sizeof(rbd_linked_image_spec_t))
             with nogil:
-                ret = rbd_list_children2(image.image, self.children, &self.num_children)
+                ret = rbd_list_children3(image.image, self.children, &self.num_children)
             if ret >= 0:
-                self.num_children = ret
                 break
             elif ret != -errno.ERANGE:
                 raise make_ex(ret, 'error listing children.')
@@ -4536,15 +4587,16 @@ cdef class ChildIterator(object):
     def __iter__(self):
         for i in range(self.num_children):
             yield {
-                'pool'  : decode_cstr(self.children[i].pool_name),
-                'image' : decode_cstr(self.children[i].image_name),
-                'id'    : decode_cstr(self.children[i].image_id),
-                'trash' : self.children[i].trash
+                'pool'           : decode_cstr(self.children[i].pool_name),
+                'pool_namespace' : decode_cstr(self.children[i].pool_namespace),
+                'image'          : decode_cstr(self.children[i].image_name),
+                'id'             : decode_cstr(self.children[i].image_id),
+                'trash'          : self.children[i].trash
                 }
 
     def __dealloc__(self):
         if self.children:
-            rbd_list_children_cleanup(self.children, self.num_children)
+            rbd_linked_image_spec_list_cleanup(self.children, self.num_children)
             free(self.children)
 
 cdef class WatcherIterator(object):
index ea679360301cae511b94411af0661a163824074e..bbc4777268c6878cd6bea3a2dabe44c5f9d72c4c 100644 (file)
 #include <sys/eventfd.h>
 #endif
 
+#pragma GCC diagnostic ignored "-Wpragmas"
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
 using namespace std;
 
 using std::chrono::seconds;
@@ -6131,6 +6135,20 @@ TEST_F(TestLibRBD, ImagePollIO)
 
 namespace librbd {
 
+static bool operator==(const image_spec_t &lhs, const image_spec_t &rhs) {
+  return (lhs.id == rhs.id && lhs.name == rhs.name);
+}
+
+static bool operator==(const linked_image_spec_t &lhs,
+                       const linked_image_spec_t &rhs) {
+  return (lhs.pool_id == rhs.pool_id &&
+          lhs.pool_name == rhs.pool_name &&
+          lhs.pool_namespace == rhs.pool_namespace &&
+          lhs.image_id == rhs.image_id &&
+          lhs.image_name == rhs.image_name &&
+          lhs.trash == rhs.trash);
+}
+
 static bool operator==(const mirror_peer_t &lhs, const mirror_peer_t &rhs) {
   return (lhs.uuid == rhs.uuid &&
           lhs.cluster_name == rhs.cluster_name &&
@@ -7473,6 +7491,85 @@ TEST_F(TestLibRBD, PoolStatsPP)
   ASSERT_EQ(1U, trash_snap_count);
 }
 
+TEST_F(TestLibRBD, ImageSpec) {
+  REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
+
+  librados::IoCtx ioctx;
+  ASSERT_EQ(0, _rados.ioctx_create(create_pool(true).c_str(), ioctx));
+
+  librbd::RBD rbd;
+  librbd::Image parent_image;
+  std::string name = get_temp_image_name();
+
+  uint64_t size = 1;
+  int order = 0;
+
+  ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
+  ASSERT_EQ(0, rbd.open(ioctx, parent_image, name.c_str(), NULL));
+
+  std::string parent_id;
+  ASSERT_EQ(0, parent_image.get_id(&parent_id));
+
+  uint64_t features;
+  ASSERT_EQ(0, parent_image.features(&features));
+
+  ASSERT_EQ(0, parent_image.snap_create("snap"));
+  ASSERT_EQ(0, parent_image.snap_protect("snap"));
+
+  std::string clone_name = this->get_temp_image_name();
+  ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "snap", ioctx, clone_name.c_str(),
+                         features, &order));
+
+  librbd::Image clone_image;
+  ASSERT_EQ(0, rbd.open(ioctx, clone_image, clone_name.c_str(), NULL));
+
+  std::string clone_id;
+  ASSERT_EQ(0, clone_image.get_id(&clone_id));
+
+  std::vector<librbd::image_spec_t> images;
+  ASSERT_EQ(0, rbd.list2(ioctx, &images));
+
+  std::vector<librbd::image_spec_t> expected_images{
+    {.id = parent_id, .name = name},
+    {.id = clone_id, .name = clone_name}
+  };
+  std::sort(expected_images.begin(), expected_images.end(),
+            [](const librbd::image_spec_t& lhs, const librbd::image_spec_t &rhs) {
+              return lhs.name < rhs.name;
+            });
+  ASSERT_EQ(expected_images, images);
+
+  librbd::linked_image_spec_t parent_image_spec;
+  librbd::snap_spec_t parent_snap_spec;
+  ASSERT_EQ(0, clone_image.get_parent(&parent_image_spec, &parent_snap_spec));
+
+  librbd::linked_image_spec_t expected_parent_image_spec{
+    .pool_id = ioctx.get_id(),
+    .pool_name = ioctx.get_pool_name(),
+    .pool_namespace = ioctx.get_namespace(),
+    .image_id = parent_id,
+    .image_name = name,
+    .trash = false
+  };
+  ASSERT_EQ(expected_parent_image_spec, parent_image_spec);
+  ASSERT_EQ(RBD_SNAP_NAMESPACE_TYPE_USER, parent_snap_spec.namespace_type);
+  ASSERT_EQ("snap", parent_snap_spec.name);
+
+  std::vector<librbd::linked_image_spec_t> children;
+  ASSERT_EQ(0, parent_image.list_children3(&children));
+
+  std::vector<librbd::linked_image_spec_t> expected_children{
+    {
+      .pool_id = ioctx.get_id(),
+      .pool_name = ioctx.get_pool_name(),
+      .pool_namespace = ioctx.get_namespace(),
+      .image_id = clone_id,
+      .image_name = clone_name,
+      .trash = false
+    }
+  };
+}
+
 // poorman's ceph_assert()
 namespace ceph {
   void __ceph_assert_fail(const char *assertion, const char *file, int line,
@@ -7480,3 +7577,6 @@ namespace ceph {
     ceph_abort();
   }
 }
+
+#pragma GCC diagnostic pop
+#pragma GCC diagnostic warning "-Wpragmas"
index 02362c1bd71df570a6990a561556550336ea61a7..510364edb6abf1ec4eb1870b9793f6d537ac8148 100644 (file)
@@ -320,6 +320,10 @@ def test_list_empty():
 def test_list():
     eq([image_name], RBD().list(ioctx))
 
+    with Image(ioctx, image_name) as image:
+        image_id = image.id()
+    eq([{'id': image_id, 'name': image_name}], list(RBD().list2(ioctx)))
+
 @with_setup(create_image, remove_image)
 def test_rename():
     rbd = RBD()
@@ -1334,7 +1338,8 @@ class TestClone(object):
         self.image.set_snap('snap1')
         self.check_children([(pool_name, self.clone_name)])
         self.check_children2(
-            [{'pool': pool_name, 'image': self.clone_name, 'trash': False,
+            [{'pool': pool_name, 'pool_namespace': '',
+              'image': self.clone_name, 'trash': False,
               'id': self.get_image_id(ioctx, self.clone_name)}])
         self.clone.close()
         self.rbd.remove(ioctx, self.clone_name)
@@ -1349,7 +1354,8 @@ class TestClone(object):
                            clone_name + str(i), features)
             expected_children.append((pool_name, clone_name + str(i)))
             expected_children2.append(
-                {'pool': pool_name, 'image': clone_name + str(i), 'trash': False,
+                {'pool': pool_name, 'pool_namespace': '',
+                 'image': clone_name + str(i), 'trash': False,
                  'id': self.get_image_id(ioctx, clone_name + str(i))})
             self.check_children(expected_children)
             self.check_children2(expected_children2)
@@ -1386,7 +1392,8 @@ class TestClone(object):
                        features)
         self.check_children([(pool_name, self.clone_name)])
         self.check_children2(
-            [{'pool': pool_name, 'image': self.clone_name, 'trash': False,
+            [{'pool': pool_name, 'pool_namespace': '',
+              'image': self.clone_name, 'trash': False,
               'id': self.get_image_id(ioctx, self.clone_name)}])
         self.clone = Image(ioctx, self.clone_name)