bool primary;
} rbd_mirror_image_info_t;
+typedef enum {
+ MIRROR_IMAGE_STATUS_STATE_UNKNOWN = 0,
+ MIRROR_IMAGE_STATUS_STATE_ERROR = 1,
+ MIRROR_IMAGE_STATUS_STATE_SYNCING = 2,
+ MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY = 3,
+ MIRROR_IMAGE_STATUS_STATE_REPLAYING = 4,
+ MIRROR_IMAGE_STATUS_STATE_STOPPING_REPLAY = 5,
+ MIRROR_IMAGE_STATUS_STATE_STOPPED = 6,
+} rbd_mirror_image_status_state_t;
+
+typedef struct {
+ rbd_mirror_image_status_state_t state;
+ char *description;
+ time_t last_update;
+ bool up;
+} rbd_mirror_image_status_t;
+
CEPH_RBD_API void rbd_version(int *major, int *minor, int *extra);
/* image options */
CEPH_RBD_API int rbd_mirror_peer_set_cluster(rados_ioctx_t io_ctx,
const char *uuid,
const char *cluster_name);
+CEPH_RBD_API int rbd_mirror_image_status_list(rados_ioctx_t io_ctx,
+ const char *start, size_t max, char **image_names,
+ rbd_mirror_image_info_t *images, rbd_mirror_image_status_t *image_statuses,
+ size_t *len);
+CEPH_RBD_API int rbd_mirror_image_status_summary(rados_ioctx_t io_ctx,
+ rbd_mirror_image_status_state_t *states, int *counts, size_t *maxlen);
CEPH_RBD_API int rbd_open(rados_ioctx_t io, const char *name,
rbd_image_t *image, const char *snap_name);
CEPH_RBD_API int rbd_mirror_image_get_info(rbd_image_t image,
rbd_mirror_image_info_t *mirror_image_info,
size_t info_size);
+CEPH_RBD_API int rbd_mirror_image_get_status(rbd_image_t image,
+ rbd_mirror_image_status_t *mirror_image_status, size_t info_size);
#ifdef __cplusplus
}
bool primary;
} mirror_image_info_t;
+ typedef rbd_mirror_image_status_state_t mirror_image_status_state_t;
+
+ typedef struct {
+ mirror_image_status_state_t state;
+ std::string description;
+ time_t last_update;
+ bool up;
+ } mirror_image_status_t;
+
typedef rbd_image_info_t image_info_t;
class CEPH_RBD_API ProgressContext
const std::string &client_name);
int mirror_peer_set_cluster(IoCtx& io_ctx, const std::string &uuid,
const std::string &cluster_name);
+ int mirror_image_status_list(IoCtx& io_ctx, const std::string &start,
+ size_t max, std::map<std::string, mirror_image_info_t> *images,
+ std::map<std::string, mirror_image_status_t> *statuses);
+ int mirror_image_status_summary(IoCtx& io_ctx,
+ std::map<mirror_image_status_state_t, int> *states);
private:
/* We don't allow assignment or copying */
int mirror_image_resync();
int mirror_image_get_info(mirror_image_info_t *mirror_image_info,
size_t info_size);
+ int mirror_image_get_status(mirror_image_status_t *mirror_image_status,
+ size_t status_size);
private:
friend class RBD;
return 0;
}
+ int mirror_image_get_status(ImageCtx *ictx, mirror_image_status_t *status,
+ size_t status_size) {
+ CephContext *cct = ictx->cct;
+ ldout(cct, 20) << __func__ << ": ictx=" << ictx << dendl;
+ if (status_size < sizeof(mirror_image_status_t)) {
+ return -ERANGE;
+ }
+
+ cls::rbd::MirrorImageStatus
+ s(cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN, "status not found");
+
+ cls::rbd::MirrorImage image;
+ int r = cls_client::mirror_image_get(&ictx->md_ctx, ictx->id, &image);
+ if (r < 0 && r != -ENOENT) {
+ lderr(cct) << "failed to retrieve mirroring state: " << cpp_strerror(r)
+ << dendl;
+ return r;
+ }
+
+ if (r == 0) {
+ r = cls_client::mirror_image_status_get(&ictx->md_ctx,
+ image.global_image_id, &s);
+ if (r < 0 && r != -ENOENT) {
+ lderr(cct) << "failed to retrieve image mirror status: "
+ << cpp_strerror(r) << dendl;
+ return r;
+ }
+ }
+
+ *status = mirror_image_status_t{
+ static_cast<mirror_image_status_state_t>(s.state),
+ s.description,
+ s.last_update.sec(),
+ s.up};
+ return 0;
+ }
+
int mirror_mode_get(IoCtx& io_ctx, rbd_mirror_mode_t *mirror_mode) {
CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
ldout(cct, 20) << __func__ << dendl;
return 0;
}
+ int mirror_image_status_list(IoCtx& io_ctx, const std::string &start,
+ size_t max, std::map<std::string, mirror_image_info_t> *images,
+ std::map<std::string, mirror_image_status_t> *statuses) {
+ CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
+ int r;
+
+ map<string, string> id_to_name;
+ {
+ map<string, string> name_to_id;
+ r = list_images_v2(io_ctx, name_to_id);
+ if (r < 0) {
+ return r;
+ }
+ for (auto it : name_to_id) {
+ id_to_name[it.second] = it.first;
+ }
+ }
+
+ map<std::string, cls::rbd::MirrorImage> images_;
+ map<std::string, cls::rbd::MirrorImageStatus> statuses_;
+
+ r = librbd::cls_client::mirror_image_status_list(&io_ctx, start, max,
+ &images_, &statuses_);
+ if (r < 0) {
+ lderr(cct) << "Failed to list mirror image statuses: "
+ << cpp_strerror(r) << dendl;
+ return r;
+ }
+
+ cls::rbd::MirrorImageStatus
+ unknown_status(cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN, "status not found");
+
+ for (auto it = images_.begin(); it != images_.end(); ++it) {
+ auto &image_id = it->first;
+ auto &info = it->second;
+ auto &image_name = id_to_name[image_id];
+ if (image_name.empty()) {
+ lderr(cct) << "Failed to find image name for image " << image_id
+ << ", using image id as name" << dendl;
+ image_name = image_id;
+ }
+ (*images)[image_name] = mirror_image_info_t{
+ info.global_image_id,
+ static_cast<mirror_image_state_t>(info.state),
+ false}; // XXX: To set "primary" properly would require additional call.
+ auto s_it = statuses_.find(image_id);
+ auto &s = s_it != statuses_.end() ? s_it->second : unknown_status;
+ (*statuses)[image_name] = mirror_image_status_t{
+ static_cast<mirror_image_status_state_t>(s.state),
+ s.description,
+ s.last_update.sec(),
+ s.up};
+ }
+
+ return 0;
+ }
+
+ int mirror_image_status_summary(IoCtx& io_ctx,
+ std::map<mirror_image_status_state_t, int> *states) {
+ CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
+
+ std::map<cls::rbd::MirrorImageStatusState, int> states_;
+ int r = cls_client::mirror_image_status_get_summary(&io_ctx, &states_);
+ if (r < 0) {
+ lderr(cct) << "Failed to get mirror status summary: "
+ << cpp_strerror(r) << dendl;
+ return r;
+ }
+ for (auto &s : states_) {
+ (*states)[static_cast<mirror_image_status_state_t>(s.first)] = s.second;
+ }
+ return 0;
+ }
+
void rbd_req_cb(completion_t cb, void *arg)
{
AioObjectRequest *req = reinterpret_cast<AioObjectRequest *>(arg);
const std::string &client_name);
int mirror_peer_set_cluster(IoCtx& io_ctx, const std::string &uuid,
const std::string &cluster_name);
+ int mirror_image_status_list(IoCtx& io_ctx, const std::string &start,
+ size_t max, std::map<std::string, mirror_image_info_t> *images,
+ std::map<std::string, mirror_image_status_t> *statuses);
+ int mirror_image_status_summary(IoCtx& io_ctx,
+ std::map<mirror_image_status_state_t, int> *states);
int mirror_image_enable(ImageCtx *ictx);
int mirror_image_disable(ImageCtx *ictx, bool force);
int mirror_image_resync(ImageCtx *ictx);
int mirror_image_get_info(ImageCtx *ictx, mirror_image_info_t *mirror_image_info,
size_t info_size);
+ int mirror_image_get_status(ImageCtx *ictx, mirror_image_status_t *status,
+ size_t status_size);
}
#endif
}
};
+void mirror_image_info_cpp_to_c(const librbd::mirror_image_info_t &cpp_info,
+ rbd_mirror_image_info_t *c_info) {
+ c_info->global_id = strdup(cpp_info.global_id.c_str());
+ c_info->state = cpp_info.state;
+ c_info->primary = cpp_info.primary;
+}
+
+void mirror_image_status_cpp_to_c(const librbd::mirror_image_status_t &cpp_status,
+ rbd_mirror_image_status_t *c_status) {
+ c_status->state = cpp_status.state;
+ c_status->description = strdup(cpp_status.description.c_str());
+ c_status->last_update = cpp_status.last_update;
+ c_status->up = cpp_status.up;
+}
+
} // anonymous namespace
namespace librbd {
return librbd::mirror_peer_set_cluster(io_ctx, uuid, cluster_name);
}
+ int RBD::mirror_image_status_list(IoCtx& io_ctx, const std::string &start,
+ size_t max, std::map<std::string, mirror_image_info_t> *images,
+ std::map<std::string, mirror_image_status_t> *statuses) {
+ return librbd::mirror_image_status_list(io_ctx, start, max, images,
+ statuses);
+ }
+
+ int RBD::mirror_image_status_summary(IoCtx& io_ctx,
+ std::map<mirror_image_status_state_t, int> *states) {
+ return librbd::mirror_image_status_summary(io_ctx, states);
+ }
+
RBD::AioCompletion::AioCompletion(void *cb_arg, callback_t complete_cb)
{
pc = reinterpret_cast<void*>(librbd::AioCompletion::create(
return librbd::mirror_image_get_info(ictx, mirror_image_info, info_size);
}
+ int Image::mirror_image_get_status(mirror_image_status_t *mirror_image_status,
+ size_t status_size) {
+ ImageCtx *ictx = (ImageCtx *)ctx;
+ return librbd::mirror_image_get_status(ictx, mirror_image_status,
+ status_size);
+ }
+
} // namespace librbd
extern "C" void rbd_version(int *major, int *minor, int *extra)
return librbd::mirror_peer_set_cluster(io_ctx, uuid, cluster_name);
}
+extern "C" int rbd_mirror_image_status_list(rados_ioctx_t p, const char *start,
+ size_t max, char **image_names, rbd_mirror_image_info_t *images,
+ rbd_mirror_image_status_t *statuses, size_t *len) {
+ librados::IoCtx io_ctx;
+ librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
+ std::map<std::string, librbd::mirror_image_info_t> cpp_images;
+ std::map<std::string, librbd::mirror_image_status_t> cpp_statuses;
+
+ int r = librbd::mirror_image_status_list(io_ctx, start, max, &cpp_images,
+ &cpp_statuses);
+ if (r < 0) {
+ return r;
+ }
+
+ size_t i = 0;
+ for (auto &it : cpp_images) {
+ assert(i < max);
+ const std::string &image_name = it.first;
+ image_names[i] = strdup(image_name.c_str());
+ mirror_image_info_cpp_to_c(it.second, &images[i]);
+ mirror_image_status_cpp_to_c(cpp_statuses[image_name], &statuses[i]);
+ i++;
+ }
+ *len = i;
+ return 0;
+}
+
+extern "C" int rbd_mirror_image_status_summary(rados_ioctx_t p,
+ rbd_mirror_image_status_state_t *states, int *counts, size_t *maxlen) {
+
+ librados::IoCtx io_ctx;
+ librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
+
+ std::map<librbd::mirror_image_status_state_t, int> states_;
+ int r = librbd::mirror_image_status_summary(io_ctx, &states_);
+ if (r < 0) {
+ return r;
+ }
+
+ size_t i = 0;
+ for (auto &it : states_) {
+ if (i == *maxlen) {
+ return -ERANGE;
+ }
+ states[i] = it.first;
+ counts[i] = it.second;
+ i++;
+ }
+ *maxlen = i;
+ return 0;
+}
+
/* images */
extern "C" int rbd_list(rados_ioctx_t p, char *names, size_t *size)
{
return r;
}
- mirror_image_info->global_id = strdup(cpp_mirror_image.global_id.c_str());
- mirror_image_info->state = cpp_mirror_image.state;
- mirror_image_info->primary = cpp_mirror_image.primary;
+ mirror_image_info_cpp_to_c(cpp_mirror_image, mirror_image_info);
+ return 0;
+}
+
+extern "C" int rbd_mirror_image_get_status(rbd_image_t image,
+ rbd_mirror_image_status_t *status,
+ size_t status_size)
+{
+ librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
+
+ librbd::mirror_image_status_t cpp_status;
+ int r = librbd::mirror_image_get_status(ictx, &cpp_status,
+ sizeof(cpp_status));
+ if (r < 0) {
+ return r;
+ }
+
+ mirror_image_status_cpp_to_c(cpp_status, status);
return 0;
}
ASSERT_EQ(0, image.mirror_image_get_info(&mirror_image, sizeof(mirror_image)));
ASSERT_EQ(mirror_state, mirror_image.state);
+ librbd::mirror_image_status_t status;
+ ASSERT_EQ(0, image.mirror_image_get_status(&status, sizeof(status)));
+ ASSERT_EQ(MIRROR_IMAGE_STATUS_STATE_UNKNOWN, status.state);
+
ASSERT_EQ(0, image.close());
ASSERT_EQ(0, m_rbd.remove(m_ioctx, image_name.c_str()));
ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, RBD_MIRROR_MODE_DISABLED));
ASSERT_EQ(0, image.mirror_image_get_info(&mirror_image, sizeof(mirror_image)));
ASSERT_EQ(mirror_state, mirror_image.state);
+ librbd::mirror_image_status_t status;
+ ASSERT_EQ(0, image.mirror_image_get_status(&status, sizeof(status)));
+ ASSERT_EQ(MIRROR_IMAGE_STATUS_STATE_UNKNOWN, status.state);
+
ASSERT_EQ(0, image.close());
ASSERT_EQ(0, m_rbd.remove(m_ioctx, image_name.c_str()));
ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, RBD_MIRROR_MODE_DISABLED));
}
+ void check_mirroring_status(size_t *images_count) {
+ std::map<std::string, librbd::mirror_image_info_t> images;
+ std::map<std::string, librbd::mirror_image_status_t> statuses;
+ ASSERT_EQ(0, m_rbd.mirror_image_status_list(m_ioctx, "", 4096, &images,
+ &statuses));
+ ASSERT_EQ(images.size(), statuses.size());
+
+ std::map<librbd::mirror_image_status_state_t, int> states;
+ ASSERT_EQ(0, m_rbd.mirror_image_status_summary(m_ioctx, &states));
+ size_t states_count = 0;
+ for (auto &s : states) {
+ states_count += s.second;
+ }
+ ASSERT_EQ(images.size(), states_count);
+
+ *images_count = images.size();
+ }
+
void check_mirroring_on_create(uint64_t features,
rbd_mirror_mode_t mirror_mode,
rbd_mirror_image_state_t mirror_state) {
ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, mirror_mode));
+ size_t mirror_images_count = 0;
+ check_mirroring_status(&mirror_images_count);
+
int order = 20;
ASSERT_EQ(0, m_rbd.create2(m_ioctx, image_name.c_str(), 4096, features, &order));
librbd::Image image;
ASSERT_EQ(0, image.mirror_image_get_info(&mirror_image, sizeof(mirror_image)));
ASSERT_EQ(mirror_state, mirror_image.state);
+ librbd::mirror_image_status_t status;
+ ASSERT_EQ(0, image.mirror_image_get_status(&status, sizeof(status)));
+ ASSERT_EQ(MIRROR_IMAGE_STATUS_STATE_UNKNOWN, status.state);
+
+ size_t mirror_images_new_count = 0;
+ check_mirroring_status(&mirror_images_new_count);
+ if (mirror_mode == RBD_MIRROR_MODE_POOL &&
+ mirror_state == RBD_MIRROR_IMAGE_ENABLED) {
+ ASSERT_EQ(mirror_images_new_count, mirror_images_count + 1);
+ } else {
+ ASSERT_EQ(mirror_images_new_count, mirror_images_count);
+ }
+
ASSERT_EQ(0, image.close());
ASSERT_EQ(0, m_rbd.remove(m_ioctx, image_name.c_str()));
ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, RBD_MIRROR_MODE_DISABLED));
+
+ check_mirroring_status(&mirror_images_new_count);
+ ASSERT_EQ(mirror_images_new_count, mirror_images_count);
}
void check_mirroring_on_update_features(uint64_t init_features,
ASSERT_EQ(0, image.mirror_image_get_info(&mirror_image, sizeof(mirror_image)));
ASSERT_EQ(mirror_state, mirror_image.state);
+ librbd::mirror_image_status_t status;
+ ASSERT_EQ(0, image.mirror_image_get_status(&status, sizeof(status)));
+ ASSERT_EQ(MIRROR_IMAGE_STATUS_STATE_UNKNOWN, status.state);
+
ASSERT_EQ(0, image.close());
ASSERT_EQ(0, m_rbd.remove(m_ioctx, image_name.c_str()));
ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, RBD_MIRROR_MODE_DISABLED));
ASSERT_EQ(0, image.mirror_image_get_info(&mirror_image, sizeof(mirror_image)));
ASSERT_EQ(mirror_state, mirror_image.state);
+ librbd::mirror_image_status_t status;
+ ASSERT_EQ(0, image.mirror_image_get_status(&status, sizeof(status)));
+ ASSERT_EQ(MIRROR_IMAGE_STATUS_STATE_UNKNOWN, status.state);
+
ASSERT_EQ(0, image.close());
ASSERT_EQ(0, m_rbd.remove(m_ioctx, img_name_str.c_str()));
}