summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJason Dillaman <dillaman@redhat.com>2017-02-03 19:37:43 +0100
committerJason Dillaman <dillaman@redhat.com>2017-03-08 18:02:27 +0100
commit79627df0713969a4ba755767248d94890b429e49 (patch)
tree899ad64922e2f6867775847b77ba4cd5196b9885 /src
parentlibrbd: additional asynchronous mirror state machines (diff)
downloadceph-79627df0713969a4ba755767248d94890b429e49.tar.xz
ceph-79627df0713969a4ba755767248d94890b429e49.zip
librbd: add aio_mirror_image_* API methods
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
Diffstat (limited to 'src')
-rw-r--r--src/include/rbd/librbd.h12
-rw-r--r--src/include/rbd/librbd.hpp6
-rw-r--r--src/librbd/api/Mirror.cc185
-rw-r--r--src/librbd/api/Mirror.h9
-rw-r--r--src/librbd/io/AioCompletion.cc1
-rw-r--r--src/librbd/io/AioCompletion.h1
-rw-r--r--src/librbd/io/Types.h1
-rw-r--r--src/librbd/librbd.cc205
-rw-r--r--src/test/librbd/test_mirroring.cc160
9 files changed, 480 insertions, 100 deletions
diff --git a/src/include/rbd/librbd.h b/src/include/rbd/librbd.h
index 460c1d2debf..78168b62fce 100644
--- a/src/include/rbd/librbd.h
+++ b/src/include/rbd/librbd.h
@@ -735,6 +735,18 @@ CEPH_RBD_API int rbd_mirror_image_get_info(rbd_image_t image,
CEPH_RBD_API int rbd_mirror_image_get_status(rbd_image_t image,
rbd_mirror_image_status_t *mirror_image_status,
size_t status_size);
+CEPH_RBD_API int rbd_aio_mirror_image_promote(rbd_image_t image, bool force,
+ rbd_completion_t c);
+CEPH_RBD_API int rbd_aio_mirror_image_demote(rbd_image_t image,
+ rbd_completion_t c);
+CEPH_RBD_API int rbd_aio_mirror_image_get_info(rbd_image_t image,
+ rbd_mirror_image_info_t *mirror_image_info,
+ size_t info_size,
+ rbd_completion_t c);
+CEPH_RBD_API int rbd_aio_mirror_image_get_status(rbd_image_t image,
+ rbd_mirror_image_status_t *mirror_image_status,
+ size_t status_size,
+ rbd_completion_t c);
// RBD consistency groups support functions
CEPH_RBD_API int rbd_group_create(rados_ioctx_t p, const char *name);
diff --git a/src/include/rbd/librbd.hpp b/src/include/rbd/librbd.hpp
index 44f741fd624..3c667d2e871 100644
--- a/src/include/rbd/librbd.hpp
+++ b/src/include/rbd/librbd.hpp
@@ -408,6 +408,12 @@ public:
size_t info_size);
int mirror_image_get_status(mirror_image_status_t *mirror_image_status,
size_t status_size);
+ int aio_mirror_image_promote(bool force, RBD::AioCompletion *c);
+ int aio_mirror_image_demote(RBD::AioCompletion *c);
+ int aio_mirror_image_get_info(mirror_image_info_t *mirror_image_info,
+ size_t info_size, RBD::AioCompletion *c);
+ int aio_mirror_image_get_status(mirror_image_status_t *mirror_image_status,
+ size_t status_size, RBD::AioCompletion *c);
int update_watch(UpdateWatchCtx *ctx, uint64_t *handle);
int update_unwatch(uint64_t handle);
diff --git a/src/librbd/api/Mirror.cc b/src/librbd/api/Mirror.cc
index ca294025128..96b8421c98c 100644
--- a/src/librbd/api/Mirror.cc
+++ b/src/librbd/api/Mirror.cc
@@ -10,11 +10,15 @@
#include "librbd/ImageCtx.h"
#include "librbd/ImageState.h"
#include "librbd/Journal.h"
+#include "librbd/Utils.h"
#include "librbd/api/Image.h"
#include "librbd/mirror/DemoteRequest.h"
#include "librbd/mirror/DisableRequest.h"
#include "librbd/mirror/EnableRequest.h"
+#include "librbd/mirror/GetInfoRequest.h"
+#include "librbd/mirror/GetStatusRequest.h"
#include "librbd/mirror/PromoteRequest.h"
+#include "librbd/mirror/Types.h"
#include "librbd/MirroringWatcher.h"
#include <boost/scope_exit.hpp>
@@ -73,6 +77,62 @@ int list_mirror_images(librados::IoCtx& io_ctx,
return 0;
}
+struct C_ImageGetInfo : public Context {
+ mirror_image_info_t *mirror_image_info;
+ Context *on_finish;
+
+ cls::rbd::MirrorImage mirror_image;
+ mirror::PromotionState promotion_state;
+
+ C_ImageGetInfo(mirror_image_info_t *mirror_image_info, Context *on_finish)
+ : mirror_image_info(mirror_image_info), on_finish(on_finish) {
+ }
+
+ void finish(int r) override {
+ if (r < 0) {
+ on_finish->complete(r);
+ return;
+ }
+
+ mirror_image_info->global_id = mirror_image.global_image_id;
+ mirror_image_info->state = static_cast<rbd_mirror_image_state_t>(
+ mirror_image.state);
+ mirror_image_info->primary = (
+ promotion_state == mirror::PROMOTION_STATE_PRIMARY);
+ on_finish->complete(0);
+ }
+};
+
+struct C_ImageGetStatus : public C_ImageGetInfo {
+ std::string image_name;
+ mirror_image_status_t *mirror_image_status;
+
+ cls::rbd::MirrorImageStatus mirror_image_status_internal;
+
+ C_ImageGetStatus(const std::string &image_name,
+ mirror_image_status_t *mirror_image_status,
+ Context *on_finish)
+ : C_ImageGetInfo(&mirror_image_status->info, on_finish),
+ image_name(image_name), mirror_image_status(mirror_image_status) {
+ }
+
+ void finish(int r) override {
+ if (r < 0) {
+ on_finish->complete(r);
+ return;
+ }
+
+ mirror_image_status->name = image_name;
+ mirror_image_status->state = static_cast<mirror_image_status_state_t>(
+ mirror_image_status_internal.state);
+ mirror_image_status->description = mirror_image_status_internal.description;
+ mirror_image_status->last_update =
+ mirror_image_status_internal.last_update.sec();
+ mirror_image_status->up = mirror_image_status_internal.up;
+ C_ImageGetInfo::finish(0);
+ }
+};
+
} // anonymous namespace
template <typename I>
@@ -262,13 +322,9 @@ int Mirror<I>::image_disable(I *ictx, bool force) {
template <typename I>
int Mirror<I>::image_promote(I *ictx, bool force) {
CephContext *cct = ictx->cct;
- ldout(cct, 20) << "ictx=" << ictx << ", "
- << "force=" << force << dendl;
C_SaferCond ctx;
- auto req = mirror::PromoteRequest<>::create(*ictx, force, &ctx);
- req->send();
-
+ Mirror<I>::image_promote(ictx, force, &ctx);
int r = ctx.wait();
if (r < 0) {
lderr(cct) << "failed to promote image" << dendl;
@@ -279,14 +335,21 @@ int Mirror<I>::image_promote(I *ictx, bool force) {
}
template <typename I>
-int Mirror<I>::image_demote(I *ictx) {
+void Mirror<I>::image_promote(I *ictx, bool force, Context *on_finish) {
CephContext *cct = ictx->cct;
- ldout(cct, 20) << "ictx=" << ictx << dendl;
+ ldout(cct, 20) << "ictx=" << ictx << ", "
+ << "force=" << force << dendl;
- C_SaferCond ctx;
- auto req = mirror::DemoteRequest<>::create(*ictx, &ctx);
+ auto req = mirror::PromoteRequest<>::create(*ictx, force, on_finish);
req->send();
+}
+
+template <typename I>
+int Mirror<I>::image_demote(I *ictx) {
+ CephContext *cct = ictx->cct;
+ C_SaferCond ctx;
+ Mirror<I>::image_demote(ictx, &ctx);
int r = ctx.wait();
if (r < 0) {
lderr(cct) << "failed to demote image" << dendl;
@@ -297,6 +360,15 @@ int Mirror<I>::image_demote(I *ictx) {
}
template <typename I>
+void Mirror<I>::image_demote(I *ictx, Context *on_finish) {
+ CephContext *cct = ictx->cct;
+ ldout(cct, 20) << "ictx=" << ictx << dendl;
+
+ auto req = mirror::DemoteRequest<>::create(*ictx, on_finish);
+ req->send();
+}
+
+template <typename I>
int Mirror<I>::image_resync(I *ictx) {
CephContext *cct = ictx->cct;
ldout(cct, 20) << "ictx=" << ictx << dendl;
@@ -333,87 +405,62 @@ int Mirror<I>::image_resync(I *ictx) {
}
template <typename I>
-int Mirror<I>::image_get_info(I *ictx, mirror_image_info_t *mirror_image_info,
- size_t info_size) {
+void Mirror<I>::image_get_info(I *ictx, mirror_image_info_t *mirror_image_info,
+ size_t info_size, Context *on_finish) {
CephContext *cct = ictx->cct;
ldout(cct, 20) << "ictx=" << ictx << dendl;
if (info_size < sizeof(mirror_image_info_t)) {
- return -ERANGE;
- }
-
- int r = ictx->state->refresh_if_required();
- if (r < 0) {
- return r;
+ on_finish->complete(-ERANGE);
+ return;
}
- cls::rbd::MirrorImage mirror_image_internal;
- r = cls_client::mirror_image_get(&ictx->md_ctx, ictx->id,
- &mirror_image_internal);
- if (r < 0 && r != -ENOENT) {
- lderr(cct) << "failed to retrieve mirroring state: " << cpp_strerror(r)
- << dendl;
- return r;
- }
+ auto ctx = new C_ImageGetInfo(mirror_image_info, on_finish);
+ auto req = mirror::GetInfoRequest<I>::create(*ictx, &ctx->mirror_image,
+ &ctx->promotion_state,
+ ctx);
+ req->send();
+}
- mirror_image_info->global_id = mirror_image_internal.global_image_id;
- if (r == -ENOENT) {
- mirror_image_info->state = RBD_MIRROR_IMAGE_DISABLED;
- } else {
- mirror_image_info->state =
- static_cast<rbd_mirror_image_state_t>(mirror_image_internal.state);
- }
+template <typename I>
+int Mirror<I>::image_get_info(I *ictx, mirror_image_info_t *mirror_image_info,
+ size_t info_size) {
+ C_SaferCond ctx;
+ image_get_info(ictx, mirror_image_info, info_size, &ctx);
- if (mirror_image_info->state == RBD_MIRROR_IMAGE_ENABLED) {
- r = Journal<I>::is_tag_owner(ictx, &mirror_image_info->primary);
- if (r < 0) {
- lderr(cct) << "failed to check tag ownership: "
- << cpp_strerror(r) << dendl;
- return r;
- }
- } else {
- mirror_image_info->primary = false;
+ int r = ctx.wait();
+ if (r < 0) {
+ return r;
}
-
return 0;
}
template <typename I>
-int Mirror<I>::image_get_status(I *ictx, mirror_image_status_t *status,
- size_t status_size) {
+void Mirror<I>::image_get_status(I *ictx, mirror_image_status_t *status,
+ size_t status_size, Context *on_finish) {
CephContext *cct = ictx->cct;
ldout(cct, 20) << "ictx=" << ictx << dendl;
if (status_size < sizeof(mirror_image_status_t)) {
- return -ERANGE;
- }
-
- int r = ictx->state->refresh_if_required();
- if (r < 0) {
- return r;
+ on_finish->complete(-ERANGE);
+ return;
}
- mirror_image_info_t info;
- r = image_get_info(ictx, &info, sizeof(info));
- if (r < 0) {
- return r;
- }
+ auto ctx = new C_ImageGetStatus(ictx->name, status, on_finish);
+ auto req = mirror::GetStatusRequest<I>::create(
+ *ictx, &ctx->mirror_image_status_internal, &ctx->mirror_image,
+ &ctx->promotion_state, ctx);
+ req->send();
+}
- cls::rbd::MirrorImageStatus
- s(cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN, "status not found");
+template <typename I>
+int Mirror<I>::image_get_status(I *ictx, mirror_image_status_t *status,
+ size_t status_size) {
+ C_SaferCond ctx;
+ image_get_status(ictx, status, status_size, &ctx);
- r = cls_client::mirror_image_status_get(&ictx->md_ctx, info.global_id, &s);
- if (r < 0 && r != -ENOENT) {
- lderr(cct) << "failed to retrieve image mirror status: "
- << cpp_strerror(r) << dendl;
+ int r = ctx.wait();
+ if (r < 0) {
return r;
}
-
- *status = mirror_image_status_t{
- ictx->name,
- info,
- static_cast<mirror_image_status_state_t>(s.state),
- s.description,
- s.last_update.sec(),
- s.up};
return 0;
}
diff --git a/src/librbd/api/Mirror.h b/src/librbd/api/Mirror.h
index 7a8b9f3a287..08f7ec888b9 100644
--- a/src/librbd/api/Mirror.h
+++ b/src/librbd/api/Mirror.h
@@ -9,6 +9,8 @@
#include <string>
#include <vector>
+struct Context;
+
namespace librbd {
struct ImageCtx;
@@ -43,13 +45,20 @@ struct Mirror {
static int image_enable(ImageCtxT *ictx, bool relax_same_pool_parent_check);
static int image_disable(ImageCtxT *ictx, bool force);
static int image_promote(ImageCtxT *ictx, bool force);
+ static void image_promote(ImageCtxT *ictx, bool force, Context *on_finish);
static int image_demote(ImageCtxT *ictx);
+ static void image_demote(ImageCtxT *ictx, Context *on_finish);
static int image_resync(ImageCtxT *ictx);
static int image_get_info(ImageCtxT *ictx,
mirror_image_info_t *mirror_image_info,
size_t info_size);
+ static void image_get_info(ImageCtxT *ictx,
+ mirror_image_info_t *mirror_image_info,
+ size_t info_size, Context *on_finish);
static int image_get_status(ImageCtxT *ictx, mirror_image_status_t *status,
size_t status_size);
+ static void image_get_status(ImageCtxT *ictx, mirror_image_status_t *status,
+ size_t status_size, Context *on_finish);
};
diff --git a/src/librbd/io/AioCompletion.cc b/src/librbd/io/AioCompletion.cc
index ecc0445efda..7f83f4deab5 100644
--- a/src/librbd/io/AioCompletion.cc
+++ b/src/librbd/io/AioCompletion.cc
@@ -59,6 +59,7 @@ void AioCompletion::complete() {
utime_t elapsed;
elapsed = ceph_clock_now() - start_time;
switch (aio_type) {
+ case AIO_TYPE_GENERIC:
case AIO_TYPE_OPEN:
case AIO_TYPE_CLOSE:
break;
diff --git a/src/librbd/io/AioCompletion.h b/src/librbd/io/AioCompletion.h
index a484365d309..0433ac945ca 100644
--- a/src/librbd/io/AioCompletion.h
+++ b/src/librbd/io/AioCompletion.h
@@ -20,6 +20,7 @@ class CephContext;
namespace librbd {
namespace io {
+
/**
* AioCompletion is the overall completion for a single
* rbd I/O request. It may be composed of many AioObjectRequests,
diff --git a/src/librbd/io/Types.h b/src/librbd/io/Types.h
index 1c3f967c0c7..874e1dd3e28 100644
--- a/src/librbd/io/Types.h
+++ b/src/librbd/io/Types.h
@@ -13,6 +13,7 @@ namespace io {
typedef enum {
AIO_TYPE_NONE = 0,
+ AIO_TYPE_GENERIC,
AIO_TYPE_OPEN,
AIO_TYPE_CLOSE,
AIO_TYPE_READ,
diff --git a/src/librbd/librbd.cc b/src/librbd/librbd.cc
index dea4ecb9478..92704f65138 100644
--- a/src/librbd/librbd.cc
+++ b/src/librbd/librbd.cc
@@ -77,28 +77,48 @@ librbd::io::AioCompletion* get_aio_completion(librbd::RBD::AioCompletion *comp)
return reinterpret_cast<librbd::io::AioCompletion *>(comp->pc);
}
-struct C_OpenComplete : public Context {
+struct C_AioCompletion : public Context {
+ CephContext *cct;
+ librbd::io::aio_type_t aio_type;
+ librbd::io::AioCompletion* aio_comp;
+
+ C_AioCompletion(librbd::ImageCtx *ictx, librbd::io::aio_type_t aio_type,
+ librbd::io::AioCompletion* aio_comp)
+ : cct(ictx->cct), aio_type(aio_type), aio_comp(aio_comp) {
+ aio_comp->init_time(ictx, aio_type);
+ aio_comp->get();
+ }
+
+ void finish(int r) override {
+ ldout(cct, 20) << "C_AioComplete::finish: r=" << r << dendl;
+ if (r < 0) {
+ aio_comp->fail(r);
+ } else {
+ aio_comp->lock.Lock();
+ aio_comp->complete();
+ aio_comp->put_unlock();
+ }
+ }
+};
+
+struct C_OpenComplete : public C_AioCompletion {
librbd::ImageCtx *ictx;
- librbd::io::AioCompletion* comp;
void **ictxp;
bool reopen;
C_OpenComplete(librbd::ImageCtx *ictx, librbd::io::AioCompletion* comp,
void **ictxp)
- : ictx(ictx), comp(comp), ictxp(ictxp) {
- comp->init_time(ictx, librbd::io::AIO_TYPE_OPEN);
- comp->get();
+ : C_AioCompletion(ictx, librbd::io::AIO_TYPE_OPEN, comp),
+ ictx(ictx), ictxp(ictxp) {
}
void finish(int r) override {
ldout(ictx->cct, 20) << "C_OpenComplete::finish: r=" << r << dendl;
if (r < 0) {
*ictxp = nullptr;
- comp->fail(r);
} else {
*ictxp = ictx;
- comp->lock.Lock();
- comp->complete();
- comp->put_unlock();
}
+
+ C_AioCompletion::finish(r);
}
};
@@ -121,26 +141,6 @@ struct C_OpenAfterCloseComplete : public Context {
}
};
-struct C_CloseComplete : public Context {
- CephContext *cct;
- librbd::io::AioCompletion* comp;
- C_CloseComplete(librbd::ImageCtx *ictx, librbd::io::AioCompletion* comp)
- : cct(ictx->cct), comp(comp) {
- comp->init_time(ictx, librbd::io::AIO_TYPE_CLOSE);
- comp->get();
- }
- void finish(int r) override {
- ldout(cct, 20) << "C_CloseComplete::finish: r=" << r << dendl;
- if (r < 0) {
- comp->fail(r);
- } else {
- comp->lock.Lock();
- comp->complete();
- comp->put_unlock();
- }
- }
-};
-
struct C_UpdateWatchCB : public librbd::UpdateWatchCtx {
rbd_update_callback_t watch_cb;
void *arg;
@@ -184,6 +184,50 @@ void mirror_image_status_cpp_to_c(const librbd::mirror_image_status_t &cpp_statu
c_status->up = cpp_status.up;
}
+struct C_MirrorImageGetInfo : public Context {
+ rbd_mirror_image_info_t *mirror_image_info;
+ Context *on_finish;
+
+ librbd::mirror_image_info_t cpp_mirror_image_info;
+
+ C_MirrorImageGetInfo(rbd_mirror_image_info_t *mirror_image_info,
+ Context *on_finish)
+ : mirror_image_info(mirror_image_info), on_finish(on_finish) {
+ }
+
+ void finish(int r) override {
+ if (r < 0) {
+ on_finish->complete(r);
+ return;
+ }
+
+ mirror_image_info_cpp_to_c(cpp_mirror_image_info, mirror_image_info);
+ on_finish->complete(0);
+ }
+};
+
+struct C_MirrorImageGetStatus : public Context {
+ rbd_mirror_image_status_t *mirror_image_status;
+ Context *on_finish;
+
+ librbd::mirror_image_status_t cpp_mirror_image_status;
+
+ C_MirrorImageGetStatus(rbd_mirror_image_status_t *mirror_image_status,
+ Context *on_finish)
+ : mirror_image_status(mirror_image_status), on_finish(on_finish) {
+ }
+
+ void finish(int r) override {
+ if (r < 0) {
+ on_finish->complete(r);
+ return;
+ }
+
+ mirror_image_status_cpp_to_c(cpp_mirror_image_status, mirror_image_status);
+ on_finish->complete(0);
+ }
+};
+
} // anonymous namespace
namespace librbd {
@@ -680,7 +724,8 @@ namespace librbd {
ImageCtx *ictx = (ImageCtx *)ctx;
tracepoint(librbd, aio_close_image_enter, ictx, ictx->name.c_str(), ictx->id.c_str(), c->pc);
- ictx->state->close(new C_CloseComplete(ictx, get_aio_completion(c)));
+ ictx->state->close(new C_AioCompletion(ictx, librbd::io::AIO_TYPE_CLOSE,
+ get_aio_completion(c)));
ctx = NULL;
tracepoint(librbd, aio_close_image_exit, 0);
@@ -1582,6 +1627,44 @@ namespace librbd {
status_size);
}
+ int Image::aio_mirror_image_promote(bool force, RBD::AioCompletion *c) {
+ ImageCtx *ictx = (ImageCtx *)ctx;
+ librbd::api::Mirror<>::image_promote(
+ ictx, force, new C_AioCompletion(ictx, librbd::io::AIO_TYPE_GENERIC,
+ get_aio_completion(c)));
+ return 0;
+ }
+
+ int Image::aio_mirror_image_demote(RBD::AioCompletion *c) {
+ ImageCtx *ictx = (ImageCtx *)ctx;
+ librbd::api::Mirror<>::image_demote(
+ ictx, new C_AioCompletion(ictx, librbd::io::AIO_TYPE_GENERIC,
+ get_aio_completion(c)));
+ return 0;
+ }
+
+ int Image::aio_mirror_image_get_info(mirror_image_info_t *mirror_image_info,
+ size_t info_size,
+ RBD::AioCompletion *c) {
+ ImageCtx *ictx = (ImageCtx *)ctx;
+ librbd::api::Mirror<>::image_get_info(
+ ictx, mirror_image_info, info_size,
+ new C_AioCompletion(ictx, librbd::io::AIO_TYPE_GENERIC,
+ get_aio_completion(c)));
+ return 0;
+ }
+
+ int Image::aio_mirror_image_get_status(mirror_image_status_t *status,
+ size_t status_size,
+ RBD::AioCompletion *c) {
+ ImageCtx *ictx = (ImageCtx *)ctx;
+ librbd::api::Mirror<>::image_get_status(
+ ictx, status, status_size,
+ new C_AioCompletion(ictx, librbd::io::AIO_TYPE_GENERIC,
+ get_aio_completion(c)));
+ return 0;
+ }
+
int Image::update_watch(UpdateWatchCtx *wctx, uint64_t *handle) {
ImageCtx *ictx = (ImageCtx *)ctx;
tracepoint(librbd, update_watch_enter, ictx, wctx);
@@ -2198,7 +2281,8 @@ extern "C" int rbd_aio_close(rbd_image_t image, rbd_completion_t c)
librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
tracepoint(librbd, aio_close_image_enter, ictx, ictx->name.c_str(), ictx->id.c_str(), comp->pc);
- ictx->state->close(new C_CloseComplete(ictx, get_aio_completion(comp)));
+ ictx->state->close(new C_AioCompletion(ictx, librbd::io::AIO_TYPE_CLOSE,
+ get_aio_completion(comp)));
tracepoint(librbd, aio_close_image_exit, 0);
return 0;
}
@@ -3340,6 +3424,65 @@ extern "C" int rbd_mirror_image_get_status(rbd_image_t image,
return 0;
}
+extern "C" int rbd_aio_mirror_image_promote(rbd_image_t image, bool force,
+ rbd_completion_t c) {
+ librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
+ librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
+ librbd::api::Mirror<>::image_promote(
+ ictx, force, new C_AioCompletion(ictx, librbd::io::AIO_TYPE_GENERIC,
+ get_aio_completion(comp)));
+ return 0;
+}
+
+extern "C" int rbd_aio_mirror_image_demote(rbd_image_t image,
+ rbd_completion_t c) {
+ librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
+ librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
+ librbd::api::Mirror<>::image_demote(
+ ictx, new C_AioCompletion(ictx, librbd::io::AIO_TYPE_GENERIC,
+ get_aio_completion(comp)));
+ return 0;
+}
+
+extern "C" int rbd_aio_mirror_image_get_info(rbd_image_t image,
+ rbd_mirror_image_info_t *info,
+ size_t info_size,
+ rbd_completion_t c) {
+ librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
+ librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
+
+ if (sizeof(rbd_mirror_image_info_t) > info_size) {
+ return -ERANGE;
+ }
+
+ auto ctx = new C_MirrorImageGetInfo(
+ info, new C_AioCompletion(ictx, librbd::io::AIO_TYPE_GENERIC,
+ get_aio_completion(comp)));
+ librbd::api::Mirror<>::image_get_info(
+ ictx, &ctx->cpp_mirror_image_info, sizeof(ctx->cpp_mirror_image_info), ctx);
+ return 0;
+}
+
+extern "C" int rbd_aio_mirror_image_get_status(rbd_image_t image,
+ rbd_mirror_image_status_t *status,
+ size_t status_size,
+ rbd_completion_t c) {
+ librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
+ librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
+
+ if (sizeof(rbd_mirror_image_status_t) > status_size) {
+ return -ERANGE;
+ }
+
+ auto ctx = new C_MirrorImageGetStatus(
+ status, new C_AioCompletion(ictx, librbd::io::AIO_TYPE_GENERIC,
+ get_aio_completion(comp)));
+ librbd::api::Mirror<>::image_get_status(
+ ictx, &ctx->cpp_mirror_image_status, sizeof(ctx->cpp_mirror_image_status),
+ ctx);
+ return 0;
+}
+
extern "C" int rbd_update_watch(rbd_image_t image, uint64_t *handle,
rbd_update_callback_t watch_cb, void *arg)
{
diff --git a/src/test/librbd/test_mirroring.cc b/src/test/librbd/test_mirroring.cc
index 8e70f383b23..ec81ae4705a 100644
--- a/src/test/librbd/test_mirroring.cc
+++ b/src/test/librbd/test_mirroring.cc
@@ -681,3 +681,163 @@ TEST_F(TestMirroring, RemoveBootstrapped)
ASSERT_TRUE(watcher.m_notified);
ASSERT_EQ(0, image.close());
}
+
+TEST_F(TestMirroring, AioPromoteDemote) {
+ std::list<std::string> image_names;
+ for (size_t idx = 0; idx < 10; ++idx) {
+ image_names.push_back(get_temp_image_name());
+ }
+
+ ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, RBD_MIRROR_MODE_IMAGE));
+
+ // create mirror images
+ int order = 20;
+ std::list<librbd::Image> images;
+ for (auto &image_name : image_names) {
+ ASSERT_EQ(0, m_rbd.create2(m_ioctx, image_name.c_str(), 2048,
+ RBD_FEATURE_EXCLUSIVE_LOCK |
+ RBD_FEATURE_JOURNALING,
+ &order));
+
+ images.emplace_back();
+ ASSERT_EQ(0, m_rbd.open(m_ioctx, images.back(), image_name.c_str()));
+ ASSERT_EQ(0, images.back().mirror_image_enable());
+ }
+
+ // demote all images
+ std::list<librbd::RBD::AioCompletion *> aio_comps;
+ for (auto &image : images) {
+ aio_comps.push_back(new librbd::RBD::AioCompletion(nullptr, nullptr));
+ ASSERT_EQ(0, image.aio_mirror_image_demote(aio_comps.back()));
+ }
+ for (auto aio_comp : aio_comps) {
+ ASSERT_EQ(0, aio_comp->wait_for_complete());
+ ASSERT_EQ(1, aio_comp->is_complete());
+ ASSERT_EQ(0, aio_comp->get_return_value());
+ aio_comp->release();
+ }
+ aio_comps.clear();
+
+ // verify demotions
+ for (auto &image : images) {
+ librbd::mirror_image_info_t mirror_image;
+ ASSERT_EQ(0, image.mirror_image_get_info(&mirror_image,
+ sizeof(mirror_image)));
+ ASSERT_FALSE(mirror_image.primary);
+ }
+
+ // promote all images
+ for (auto &image : images) {
+ aio_comps.push_back(new librbd::RBD::AioCompletion(nullptr, nullptr));
+ ASSERT_EQ(0, image.aio_mirror_image_promote(false, aio_comps.back()));
+ }
+ for (auto aio_comp : aio_comps) {
+ ASSERT_EQ(0, aio_comp->wait_for_complete());
+ ASSERT_EQ(1, aio_comp->is_complete());
+ ASSERT_EQ(0, aio_comp->get_return_value());
+ aio_comp->release();
+ }
+
+ // verify promotions
+ for (auto &image : images) {
+ librbd::mirror_image_info_t mirror_image;
+ ASSERT_EQ(0, image.mirror_image_get_info(&mirror_image,
+ sizeof(mirror_image)));
+ ASSERT_TRUE(mirror_image.primary);
+ }
+}
+
+TEST_F(TestMirroring, AioGetInfo) {
+ std::list<std::string> image_names;
+ for (size_t idx = 0; idx < 10; ++idx) {
+ image_names.push_back(get_temp_image_name());
+ }
+
+ ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, RBD_MIRROR_MODE_POOL));
+
+ // create mirror images
+ int order = 20;
+ std::list<librbd::Image> images;
+ for (auto &image_name : image_names) {
+ ASSERT_EQ(0, m_rbd.create2(m_ioctx, image_name.c_str(), 2048,
+ RBD_FEATURE_EXCLUSIVE_LOCK |
+ RBD_FEATURE_JOURNALING,
+ &order));
+
+ images.emplace_back();
+ ASSERT_EQ(0, m_rbd.open(m_ioctx, images.back(), image_name.c_str()));
+ }
+
+ std::list<librbd::RBD::AioCompletion *> aio_comps;
+ std::list<librbd::mirror_image_info_t> infos;
+ for (auto &image : images) {
+ aio_comps.push_back(new librbd::RBD::AioCompletion(nullptr, nullptr));
+ infos.emplace_back();
+ ASSERT_EQ(0, image.aio_mirror_image_get_info(&infos.back(),
+ sizeof(infos.back()),
+ aio_comps.back()));
+ }
+ for (auto aio_comp : aio_comps) {
+ ASSERT_EQ(0, aio_comp->wait_for_complete());
+ ASSERT_EQ(1, aio_comp->is_complete());
+ ASSERT_EQ(0, aio_comp->get_return_value());
+ aio_comp->release();
+ }
+ aio_comps.clear();
+
+ for (auto &info : infos) {
+ ASSERT_NE("", info.global_id);
+ ASSERT_EQ(RBD_MIRROR_IMAGE_ENABLED, info.state);
+ ASSERT_TRUE(info.primary);
+ }
+}
+
+TEST_F(TestMirroring, AioGetStatus) {
+ std::list<std::string> image_names;
+ for (size_t idx = 0; idx < 10; ++idx) {
+ image_names.push_back(get_temp_image_name());
+ }
+
+ ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, RBD_MIRROR_MODE_POOL));
+
+ // create mirror images
+ int order = 20;
+ std::list<librbd::Image> images;
+ for (auto &image_name : image_names) {
+ ASSERT_EQ(0, m_rbd.create2(m_ioctx, image_name.c_str(), 2048,
+ RBD_FEATURE_EXCLUSIVE_LOCK |
+ RBD_FEATURE_JOURNALING,
+ &order));
+
+ images.emplace_back();
+ ASSERT_EQ(0, m_rbd.open(m_ioctx, images.back(), image_name.c_str()));
+ }
+
+ std::list<librbd::RBD::AioCompletion *> aio_comps;
+ std::list<librbd::mirror_image_status_t> statuses;
+ for (auto &image : images) {
+ aio_comps.push_back(new librbd::RBD::AioCompletion(nullptr, nullptr));
+ statuses.emplace_back();
+ ASSERT_EQ(0, image.aio_mirror_image_get_status(&statuses.back(),
+ sizeof(statuses.back()),
+ aio_comps.back()));
+ }
+ for (auto aio_comp : aio_comps) {
+ ASSERT_EQ(0, aio_comp->wait_for_complete());
+ ASSERT_EQ(1, aio_comp->is_complete());
+ ASSERT_EQ(0, aio_comp->get_return_value());
+ aio_comp->release();
+ }
+ aio_comps.clear();
+
+ for (auto &status : statuses) {
+ ASSERT_NE("", status.name);
+ ASSERT_NE("", status.info.global_id);
+ ASSERT_EQ(RBD_MIRROR_IMAGE_ENABLED, status.info.state);
+ ASSERT_TRUE(status.info.primary);
+ ASSERT_EQ(MIRROR_IMAGE_STATUS_STATE_UNKNOWN, status.state);
+ ASSERT_EQ("status not found", status.description);
+ ASSERT_FALSE(status.up);
+ ASSERT_EQ(0, status.last_update);
+ }
+}