]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: add aio_mirror_image_* API methods
authorJason Dillaman <dillaman@redhat.com>
Fri, 3 Feb 2017 18:37:43 +0000 (13:37 -0500)
committerJason Dillaman <dillaman@redhat.com>
Wed, 8 Mar 2017 17:02:27 +0000 (12:02 -0500)
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
src/include/rbd/librbd.h
src/include/rbd/librbd.hpp
src/librbd/api/Mirror.cc
src/librbd/api/Mirror.h
src/librbd/io/AioCompletion.cc
src/librbd/io/AioCompletion.h
src/librbd/io/Types.h
src/librbd/librbd.cc
src/test/librbd/test_mirroring.cc

index 460c1d2debf094a657c390f9ed17f507e1df41aa..78168b62fce30917d2ecf01c0a8052b8c11b926a 100644 (file)
@@ -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);
index 44f741fd6244ab23f8648671cf3c615e171b2bf8..3c667d2e871a774a055f813a136fa32ed252dcc6 100644 (file)
@@ -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);
index ca2940251283d628302f81d218f61b288739dafa..96b8421c98c69916b640bf59380202df5bffdfd1 100644 (file)
 #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;
@@ -296,6 +359,15 @@ int Mirror<I>::image_demote(I *ictx) {
   return 0;
 }
 
+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;
@@ -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;
 }
 
index 7a8b9f3a2877176bbad8818199a51c8556c5e3ad..08f7ec888b988805d06a614a05992f6076f23d9c 100644 (file)
@@ -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);
 
 };
 
index ecc0445efdae288988e1ff6535e2848e64b75fca..7f83f4deab5a4e4c139eb6225daa6652de1e8fbb 100644 (file)
@@ -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;
index a484365d3095fe01887d43d391156b13a8536750..0433ac945ca0077f00f68eb8174c08ecd9e1fc18 100644 (file)
@@ -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,
index 1c3f967c0c72315ff53cc95c5f005b04b4f24ba6..874e1dd3e28eabd145a825ecd409d539ce2d0538 100644 (file)
@@ -13,6 +13,7 @@ namespace io {
 
 typedef enum {
   AIO_TYPE_NONE = 0,
+  AIO_TYPE_GENERIC,
   AIO_TYPE_OPEN,
   AIO_TYPE_CLOSE,
   AIO_TYPE_READ,
index dea4ecb9478e5928f88c3e2ecc738b97b4c5ceca..92704f651382a67da3d8eeeacfe22c5e37b147c1 100644 (file)
@@ -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)
 {
index 8e70f383b238c4990a33af624539ee7f369210a7..ec81ae4705ae39a17dcd911b6e0574bcd13e67cd 100644 (file)
@@ -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);
+  }
+}