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;
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;
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,
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);
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);
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,
*/
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
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;
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);
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);
* 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,
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;
}
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;
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;
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) {
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
}
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;
}
#ifndef LIBRBD_API_IMAGE_H
#define LIBRBD_API_IMAGE_H
+#include "include/rbd/librbd.hpp"
#include "librbd/Types.h"
#include <map>
#include <set>
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,
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;
}
}
}
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;
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;
}
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;
}
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,
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)
{
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;
}
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();
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,
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);
}
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);
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;
}
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;
}
}
}
+/* 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;
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;
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;
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;
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,
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;
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;
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);
}
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);
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;
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,
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"
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"
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,
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,
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)
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,
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
: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):
"""
: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):
"""
: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):
"""
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
* ``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
* ``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):
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.')
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):
#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;
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 &&
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,
ceph_abort();
}
}
+
+#pragma GCC diagnostic pop
+#pragma GCC diagnostic warning "-Wpragmas"
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()
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)
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)
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)