]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: delay mirror registration when creating clones 12839/head
authorJason Dillaman <dillaman@redhat.com>
Tue, 6 Dec 2016 20:51:51 +0000 (15:51 -0500)
committerJason Dillaman <dillaman@redhat.com>
Mon, 9 Jan 2017 14:21:41 +0000 (09:21 -0500)
Fixes: http://tracker.ceph.com/issues/17993
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
12 files changed:
src/librbd/Journal.cc
src/librbd/Journal.h
src/librbd/image/CreateRequest.cc
src/librbd/image/CreateRequest.h
src/librbd/internal.cc
src/librbd/internal.h
src/librbd/librbd.cc
src/librbd/mirror/EnableRequest.cc
src/librbd/mirror/EnableRequest.h
src/test/librbd/test_mock_Journal.cc
src/test/rbd_mirror/image_replayer/test_mock_CreateImageRequest.cc
src/tools/rbd_mirror/image_replayer/CreateImageRequest.cc

index 8cca965ce7269ac5e4794689a3b5921330a3fa5d..f799f6b8d14246cf7eab7eee36d882c66a522c4c 100644 (file)
@@ -53,25 +53,29 @@ public:
 
 template <typename I>
 struct C_IsTagOwner : public Context {
-  I *image_ctx;
+  librados::IoCtx &io_ctx;
+  std::string image_id;
   bool *is_tag_owner;
+  ContextWQ *op_work_queue;
   Context *on_finish;
 
+  CephContext *cct = nullptr;
   Journaler *journaler;
   cls::journal::Client client;
   journal::ImageClientMeta client_meta;
   uint64_t tag_tid;
   journal::TagData tag_data;
 
-  C_IsTagOwner(I *image_ctx, bool *is_tag_owner, Context *on_finish)
-    : image_ctx(image_ctx), is_tag_owner(is_tag_owner), on_finish(on_finish),
-      journaler(new Journaler(image_ctx->md_ctx, image_ctx->id,
-                              Journal<>::IMAGE_CLIENT_ID, {})) {
+  C_IsTagOwner(librados::IoCtx &io_ctx, const std::string &image_id,
+               bool *is_tag_owner, ContextWQ *op_work_queue, Context *on_finish)
+    : io_ctx(io_ctx), image_id(image_id), is_tag_owner(is_tag_owner),
+      op_work_queue(op_work_queue), on_finish(on_finish),
+      cct(reinterpret_cast<CephContext*>(io_ctx.cct())),
+      journaler(new Journaler(io_ctx, image_id, Journal<>::IMAGE_CLIENT_ID,
+                              {})) {
   }
 
   virtual void finish(int r) {
-    CephContext *cct = image_ctx->cct;
-
     ldout(cct, 20) << this << " C_IsTagOwner::" << __func__ << ": r=" << r
                   << dendl;
     if (r < 0) {
@@ -88,7 +92,7 @@ struct C_IsTagOwner : public Context {
        on_finish->complete(r);
        delete journaler;
       });
-    image_ctx->op_work_queue->queue(ctx, r);
+    op_work_queue->queue(ctx, r);
   }
 };
 
@@ -432,7 +436,8 @@ int Journal<I>::reset(librados::IoCtx &io_ctx, const std::string &image_id) {
 
 template <typename I>
 int Journal<I>::is_tag_owner(I *image_ctx, bool *is_tag_owner) {
-  return Journal<>::is_tag_owner(image_ctx->md_ctx, image_ctx->id, is_tag_owner);
+  return Journal<>::is_tag_owner(image_ctx->md_ctx, image_ctx->id,
+                                 is_tag_owner);
 }
 
 template <typename I>
@@ -449,13 +454,21 @@ int Journal<I>::is_tag_owner(IoCtx& io_ctx, std::string& image_id,
 }
 
 template <typename I>
-void Journal<I>::is_tag_owner(I *image_ctx, bool *is_tag_owner,
+void Journal<I>::is_tag_owner(I *image_ctx, bool *owner,
                               Context *on_finish) {
-  CephContext *cct = image_ctx->cct;
+  is_tag_owner(image_ctx->md_ctx, image_ctx->id, owner,
+               image_ctx->op_work_queue, on_finish);
+}
+
+template <typename I>
+void Journal<I>::is_tag_owner(librados::IoCtx& io_ctx, std::string& image_id,
+                              bool *is_tag_owner, ContextWQ *op_work_queue,
+                              Context *on_finish) {
+  CephContext *cct = reinterpret_cast<CephContext*>(io_ctx.cct());
   ldout(cct, 20) << __func__ << dendl;
 
   C_IsTagOwner<I> *is_tag_owner_ctx =  new C_IsTagOwner<I>(
-    image_ctx, is_tag_owner, on_finish);
+    io_ctx, image_id, is_tag_owner, op_work_queue, on_finish);
   get_tags(cct, is_tag_owner_ctx->journaler, &is_tag_owner_ctx->client,
           &is_tag_owner_ctx->client_meta, &is_tag_owner_ctx->tag_tid,
           &is_tag_owner_ctx->tag_data, is_tag_owner_ctx);
index 4b70b99eb8ab56df4fa33b11103c31c38a4f5f6d..635b3147e7f374d41aaa3a5ddb251f0220a9fcbb 100644 (file)
@@ -107,6 +107,9 @@ public:
                           bool *is_tag_owner);
   static void is_tag_owner(ImageCtxT *image_ctx, bool *is_tag_owner,
                            Context *on_finish);
+  static void is_tag_owner(librados::IoCtx& io_ctx, std::string& image_id,
+                           bool *is_tag_owner, ContextWQ *op_work_queue,
+                           Context *on_finish);
   static int get_tag_owner(ImageCtxT *image_ctx, std::string *mirror_uuid);
   static int get_tag_owner(librados::IoCtx& io_ctx, std::string& image_id,
                            std::string *mirror_uuid);
index f71642ddc8bd2461e9d839f102b0cc932d8ae0a3..2a9dfac2fc1f26cc3a7aad38407b771513c2abf1 100644 (file)
 #include "common/ceph_context.h"
 #include "librbd/AioCompletion.h"
 #include "librbd/Journal.h"
+#include "librbd/MirroringWatcher.h"
 #include "librbd/journal/CreateRequest.h"
 #include "librbd/journal/RemoveRequest.h"
+#include "librbd/mirror/EnableRequest.h"
 #include "journal/Journaler.h"
-#include "librbd/MirroringWatcher.h"
 
 #define dout_subsys ceph_subsys_rbd
 #undef dout_prefix
@@ -122,10 +123,12 @@ CreateRequest<I>::CreateRequest(IoCtx &ioctx, const std::string &image_name,
                                 const ImageOptions &image_options,
                                 const std::string &non_primary_global_image_id,
                                 const std::string &primary_mirror_uuid,
+                                bool skip_mirror_enable,
                                 ContextWQ *op_work_queue, Context *on_finish)
   : m_image_name(image_name), m_image_id(image_id), m_size(size),
     m_non_primary_global_image_id(non_primary_global_image_id),
     m_primary_mirror_uuid(primary_mirror_uuid),
+    m_skip_mirror_enable(skip_mirror_enable),
     m_op_work_queue(op_work_queue), m_on_finish(on_finish) {
   m_ioctx.dup(ioctx);
   m_cct = reinterpret_cast<CephContext *>(m_ioctx.cct());
@@ -639,86 +642,25 @@ Context* CreateRequest<I>::handle_journal_create(int *result) {
     return nullptr;
   }
 
-  fetch_mirror_image();
+  mirror_image_enable();
   return nullptr;
 }
 
 template<typename I>
-void CreateRequest<I>::fetch_mirror_image() {
-  if ((m_mirror_mode != RBD_MIRROR_MODE_POOL) && !m_force_non_primary) {
+void CreateRequest<I>::mirror_image_enable() {
+  if (((m_mirror_mode != RBD_MIRROR_MODE_POOL) && !m_force_non_primary) ||
+      m_skip_mirror_enable) {
     complete(0);
     return;
   }
 
   ldout(m_cct, 20) << this << " " << __func__ << dendl;
-
-  librados::ObjectReadOperation op;
-  cls_client::mirror_image_get_start(&op, m_image_id);
-
-  using klass = CreateRequest<I>;
-  librados::AioCompletion *comp =
-    create_rados_ack_callback<klass, &klass::handle_fetch_mirror_image>(this);
-  m_outbl.clear();
-  int r = m_ioctx.aio_operate(RBD_MIRRORING, comp, &op, &m_outbl);
-  assert(r == 0);
-  comp->release();
-}
-
-template<typename I>
-Context *CreateRequest<I>::handle_fetch_mirror_image(int *result) {
-  ldout(m_cct, 20) << __func__ << ": r=" << *result << dendl;
-
-  if ((*result < 0) && (*result != -ENOENT)) {
-    lderr(m_cct) << "cannot enable mirroring: " << cpp_strerror(*result) << dendl;
-
-    m_r_saved = *result;
-    journal_remove();
-    return nullptr;
-  }
-
-  if (*result == 0) {
-    bufferlist::iterator it = m_outbl.begin();
-    *result = cls_client::mirror_image_get_finish(&it, &m_mirror_image_internal);
-    if (*result < 0) {
-      lderr(m_cct) << "cannot enable mirroring: " << cpp_strerror(*result) << dendl;
-
-      m_r_saved = *result;
-      journal_remove();
-      return nullptr;
-    }
-
-    if (m_mirror_image_internal.state == cls::rbd::MIRROR_IMAGE_STATE_ENABLED) {
-      return m_on_finish;
-    }
-  }
-
-  // enable image mirroring (-ENOENT or disabled earlier)
-  mirror_image_enable();
-  return nullptr;
-}
-
-template<typename I>
-void CreateRequest<I>::mirror_image_enable() {
-  ldout(m_cct, 20) << this << " " << __func__ << dendl;
-
-  m_mirror_image_internal.state = cls::rbd::MIRROR_IMAGE_STATE_ENABLED;
-  if (m_non_primary_global_image_id.empty()) {
-    uuid_d uuid_gen;
-    uuid_gen.generate_random();
-    m_mirror_image_internal.global_image_id = uuid_gen.to_string();
-  } else {
-    m_mirror_image_internal.global_image_id = m_non_primary_global_image_id;
-  }
-
-  librados::ObjectWriteOperation op;
-  cls_client::mirror_image_set(&op, m_image_id, m_mirror_image_internal);
-
-  using klass = CreateRequest<I>;
-  librados::AioCompletion *comp =
-    create_rados_ack_callback<klass, &klass::handle_mirror_image_enable>(this);
-  int r = m_ioctx.aio_operate(RBD_MIRRORING, comp, &op);
-  assert(r == 0);
-  comp->release();
+  auto ctx = create_context_callback<
+    CreateRequest<I>, &CreateRequest<I>::handle_mirror_image_enable>(this);
+  auto req = mirror::EnableRequest<I>::create(m_ioctx, m_image_id,
+                                              m_non_primary_global_image_id,
+                                              m_op_work_queue, ctx);
+  req->send();
 }
 
 template<typename I>
@@ -726,47 +668,14 @@ Context *CreateRequest<I>::handle_mirror_image_enable(int *result) {
   ldout(m_cct, 20) << __func__ << ": r=" << *result << dendl;
 
   if (*result < 0) {
-    lderr(m_cct) << "cannot enable mirroring: " << cpp_strerror(*result) << dendl;
+    lderr(m_cct) << "cannot enable mirroring: " << cpp_strerror(*result)
+                 << dendl;
 
     m_r_saved = *result;
     journal_remove();
     return nullptr;
   }
-
-  send_watcher_notification();
-  return nullptr;
-}
-
-// TODO: make this *really* async
-template<typename I>
-void CreateRequest<I>::send_watcher_notification() {
-  ldout(m_cct, 20) << this << " " << __func__ << dendl;
-
-  Context *ctx = new FunctionContext([this](int r) {
-      r = MirroringWatcher<>::notify_image_updated(
-        m_ioctx, cls::rbd::MIRROR_IMAGE_STATE_ENABLED,
-        m_image_id, m_mirror_image_internal.global_image_id);
-      handle_watcher_notify(r);
-    });
-
-  m_op_work_queue->queue(ctx, 0);
-}
-
-template<typename I>
-void CreateRequest<I>::handle_watcher_notify(int r) {
-  ldout(m_cct, 20) << __func__ << ": r=" << r << dendl;
-
-  if (r < 0) {
-    // non fatal error -- watchers would cope up upon noticing missing
-    // updates. just log and move on...
-    ldout(m_cct, 10) << "failed to send update notification: " << cpp_strerror(r)
-                     << dendl;
-  } else {
-    ldout(m_cct, 20) << "image mirroring is enabled: global_id=" <<
-      m_mirror_image_internal.global_image_id << dendl;
-  }
-
-  complete(0);
+  return m_on_finish;
 }
 
 template<typename I>
index 9841af941d9a1c23bba1e0f3ec0653ba12b1d59f..865fd772268274f10c27125b50e3eb0aa72e7494 100644 (file)
@@ -35,10 +35,12 @@ public:
                                const ImageOptions &image_options,
                                const std::string &non_primary_global_image_id,
                                const std::string &primary_mirror_uuid,
+                               bool skip_mirror_enable,
                                ContextWQ *op_work_queue, Context *on_finish) {
     return new CreateRequest(ioctx, image_name, image_id, size, image_options,
                              non_primary_global_image_id, primary_mirror_uuid,
-                             op_work_queue, on_finish);
+                             skip_mirror_enable, op_work_queue,
+                             on_finish);
   }
 
   static int validate_order(CephContext *cct, uint8_t order);
@@ -79,14 +81,9 @@ private:
    * |               |\             JOURNAL CREATE              .
    * |               | \               /  |                     .
    * v               |  *<------------/   v                     .
-   * |               |           FETCH MIRROR IMAGE             v
+   * |               |           MIRROR IMAGE ENABLE            .
    * |               |                /   |                     .
-   * |        JOURNAL REMOVE<--------/    v                     .
-   * |                \          MIRROR IMAGE ENABLE            .
-   * |                 \               /  |                     .
-   * |                  *<------------/   v                     .
-   * |                              NOTIFY WATCHERS             .
-   * |                                    |                     .
+   * |        JOURNAL REMOVE*<-------/    |                     .
    * |                                    v                     .
    * |_____________>___________________<finish> . . . . < . . . .
    *
@@ -98,6 +95,7 @@ private:
                 const ImageOptions &image_options,
                 const std::string &non_primary_global_image_id,
                 const std::string &primary_mirror_uuid,
+                bool skip_mirror_enable,
                 ContextWQ *op_work_queue, Context *on_finish);
 
   IoCtx m_ioctx;
@@ -115,6 +113,7 @@ private:
   int64_t m_data_pool_id = -1;
   const std::string m_non_primary_global_image_id;
   const std::string m_primary_mirror_uuid;
+  bool m_skip_mirror_enable;
   bool m_negotiate_features = false;
 
   ContextWQ *m_op_work_queue;
@@ -157,15 +156,9 @@ private:
   void journal_create();
   Context *handle_journal_create(int *result);
 
-  void fetch_mirror_image();
-  Context *handle_fetch_mirror_image(int *result);
-
   void mirror_image_enable();
   Context *handle_mirror_image_enable(int *result);
 
-  void send_watcher_notification();
-  void handle_watcher_notify(int r);
-
   void complete(int r);
 
   // cleanup
index 49e4e4b9f19112f82801fa6cca675a1267272e15..ab5587c2c61a262633e88e432f4a9352be622c0e 100644 (file)
@@ -948,7 +948,7 @@ void filter_out_mirror_watchers(ImageCtx *ictx,
     int r = opts.set(RBD_IMAGE_OPTION_ORDER, order_);
     assert(r == 0);
 
-    r = create(io_ctx, imgname, size, opts, "", "");
+    r = create(io_ctx, imgname, size, opts, "", "", false);
 
     int r1 = opts.get(RBD_IMAGE_OPTION_ORDER, &order_);
     assert(r1 == 0);
@@ -980,7 +980,7 @@ void filter_out_mirror_watchers(ImageCtx *ictx,
     r = opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, stripe_count);
     assert(r == 0);
 
-    r = create(io_ctx, imgname, size, opts, "", "");
+    r = create(io_ctx, imgname, size, opts, "", "", false);
 
     int r1 = opts.get(RBD_IMAGE_OPTION_ORDER, &order_);
     assert(r1 == 0);
@@ -992,7 +992,8 @@ void filter_out_mirror_watchers(ImageCtx *ictx,
   int create(IoCtx& io_ctx, const char *imgname, uint64_t size,
             ImageOptions& opts,
              const std::string &non_primary_global_image_id,
-             const std::string &primary_mirror_uuid)
+             const std::string &primary_mirror_uuid,
+             bool skip_mirror_enable)
   {
     CephContext *cct = (CephContext *)io_ctx.cct();
     ldout(cct, 10) << __func__ << " name=" << imgname << ", "
@@ -1035,7 +1036,7 @@ void filter_out_mirror_watchers(ImageCtx *ictx,
       std::string id = util::generate_image_id(io_ctx);
       image::CreateRequest<> *req = image::CreateRequest<>::create(
         io_ctx, imgname, id, size, opts, non_primary_global_image_id,
-        primary_mirror_uuid, &op_work_queue, &cond);
+        primary_mirror_uuid, skip_mirror_enable, &op_work_queue, &cond);
       req->send();
 
       r = cond.wait();
@@ -1216,7 +1217,7 @@ void filter_out_mirror_watchers(ImageCtx *ictx,
 
     c_opts.set(RBD_IMAGE_OPTION_FEATURES, features);
     r = create(c_ioctx, c_name, size, c_opts, non_primary_global_image_id,
-               primary_mirror_uuid);
+               primary_mirror_uuid, true);
     if (r < 0) {
       lderr(cct) << "error creating child: " << cpp_strerror(r) << dendl;
       return r;
@@ -1267,6 +1268,35 @@ void filter_out_mirror_watchers(ImageCtx *ictx,
       }
     }
 
+    if (c_imctx->test_features(RBD_FEATURE_JOURNALING)) {
+      cls::rbd::MirrorMode mirror_mode_internal =
+        cls::rbd::MIRROR_MODE_DISABLED;
+      r = cls_client::mirror_mode_get(&c_imctx->md_ctx, &mirror_mode_internal);
+      if (r < 0 && r != -ENOENT) {
+        lderr(cct) << "failed to retrieve mirror mode: " << cpp_strerror(r)
+                   << dendl;
+        goto err_remove_child;
+      }
+
+      // enable mirroring now that clone has been fully created
+      if (mirror_mode_internal == cls::rbd::MIRROR_MODE_POOL ||
+          !non_primary_global_image_id.empty()) {
+        C_SaferCond ctx;
+        mirror::EnableRequest<ImageCtx> *req =
+          mirror::EnableRequest<ImageCtx>::create(c_imctx->md_ctx, c_imctx->id,
+                                                  non_primary_global_image_id,
+                                                  c_imctx->op_work_queue, &ctx);
+        req->send();
+
+        r = ctx.wait();
+        if (r < 0) {
+          lderr(cct) << "failed to enable mirroring: " << cpp_strerror(r)
+                     << dendl;
+          goto err_remove_child;
+        }
+      }
+    }
+
     ldout(cct, 2) << "done." << dendl;
     r = c_imctx->state->close();
     return r;
@@ -1972,7 +2002,7 @@ void filter_out_mirror_watchers(ImageCtx *ictx,
       return -ENOSYS;
     }
 
-    int r = create(dest_md_ctx, destname, src_size, opts, "", "");
+    int r = create(dest_md_ctx, destname, src_size, opts, "", "", false);
     if (r < 0) {
       lderr(cct) << "header creation failed" << dendl;
       return r;
index b4e1ad959a67553b2e4bf16f6e8ed45841c9a8df..550eecf9ac5c74ce98365f7a7339e3a3d4f9c601 100644 (file)
@@ -107,7 +107,8 @@ namespace librbd {
   int create(IoCtx& io_ctx, const char *imgname, uint64_t size,
             ImageOptions& opts,
              const std::string &non_primary_global_image_id,
-             const std::string &primary_mirror_uuid);
+             const std::string &primary_mirror_uuid,
+             bool skip_mirror_enable);
   int clone(IoCtx& p_ioctx, const char *p_name, const char *p_snap_name,
            IoCtx& c_ioctx, const char *c_name,
            uint64_t features, int *c_order,
index 690ae3284f2ea67fef645c900366fcafd91459e2..5669213a28ec671d664392002ca6e538cc4ee335 100644 (file)
@@ -337,7 +337,7 @@ namespace librbd {
   {
     TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
     tracepoint(librbd, create4_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name, size, opts.opts);
-    int r = librbd::create(io_ctx, name, size, opts, "", "");
+    int r = librbd::create(io_ctx, name, size, opts, "", "", false);
     tracepoint(librbd, create4_exit, r);
     return r;
   }
@@ -1849,7 +1849,7 @@ extern "C" int rbd_create4(rados_ioctx_t p, const char *name,
   TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
   tracepoint(librbd, create4_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name, size, opts);
   librbd::ImageOptions opts_(opts);
-  int r = librbd::create(io_ctx, name, size, opts_, "", "");
+  int r = librbd::create(io_ctx, name, size, opts_, "", "", false);
   tracepoint(librbd, create4_exit, r);
   return r;
 }
index a9b03a23d12d27c3722e90ae548dca9309aef261..8f621e4cc03ceffd6812b91056582a605d5c1d92 100644 (file)
@@ -21,9 +21,14 @@ using util::create_context_callback;
 using util::create_rados_ack_callback;
 
 template <typename I>
-EnableRequest<I>::EnableRequest(I *image_ctx, Context *on_finish)
-  : m_io_ctx(&image_ctx->md_ctx), m_image_ctx(image_ctx),
-    m_on_finish(on_finish) {
+EnableRequest<I>::EnableRequest(librados::IoCtx &io_ctx,
+                                const std::string &image_id,
+                                const std::string &non_primary_global_image_id,
+                                ContextWQ *op_work_queue, Context *on_finish)
+  : m_io_ctx(io_ctx), m_image_id(image_id),
+    m_non_primary_global_image_id(non_primary_global_image_id),
+    m_op_work_queue(op_work_queue), m_on_finish(on_finish),
+    m_cct(reinterpret_cast<CephContext*>(io_ctx.cct())) {
 }
 
 template <typename I>
@@ -33,29 +38,31 @@ void EnableRequest<I>::send() {
 
 template <typename I>
 void EnableRequest<I>::send_get_tag_owner() {
-  CephContext *cct = m_image_ctx->cct;
-  ldout(cct, 10) << this << " " << __func__ << dendl;
+  if (!m_non_primary_global_image_id.empty()) {
+    return
+    send_get_mirror_image();
+  }
+  ldout(m_cct, 10) << this << " " << __func__ << dendl;
 
   using klass = EnableRequest<I>;
   Context *ctx = create_context_callback<
       klass, &klass::handle_get_tag_owner>(this);
-
-  librbd::Journal<>::is_tag_owner(m_image_ctx, &m_is_primary, ctx);
+  librbd::Journal<>::is_tag_owner(m_io_ctx, m_image_id, &m_is_primary,
+                                  m_op_work_queue, ctx);
 }
 
 template <typename I>
 Context *EnableRequest<I>::handle_get_tag_owner(int *result) {
-  CephContext *cct = m_image_ctx->cct;
-  ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
+  ldout(m_cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
 
   if (*result < 0) {
-    lderr(cct) << "failed to check tag ownership: " << cpp_strerror(*result)
-               << dendl;
+    lderr(m_cct) << "failed to check tag ownership: " << cpp_strerror(*result)
+                 << dendl;
     return m_on_finish;
   }
 
   if (!m_is_primary) {
-    lderr(cct) << "last journal tag not owned by local cluster" << dendl;
+    lderr(m_cct) << "last journal tag not owned by local cluster" << dendl;
     *result = -EINVAL;
     return m_on_finish;
   }
@@ -66,25 +73,23 @@ Context *EnableRequest<I>::handle_get_tag_owner(int *result) {
 
 template <typename I>
 void EnableRequest<I>::send_get_mirror_image() {
-  CephContext *cct = m_image_ctx->cct;
-  ldout(cct, 10) << this << " " << __func__ << dendl;
+  ldout(m_cct, 10) << this << " " << __func__ << dendl;
 
   librados::ObjectReadOperation op;
-  cls_client::mirror_image_get_start(&op, m_image_ctx->id);
+  cls_client::mirror_image_get_start(&op, m_image_id);
 
   using klass = EnableRequest<I>;
   librados::AioCompletion *comp =
     create_rados_ack_callback<klass, &klass::handle_get_mirror_image>(this);
   m_out_bl.clear();
-  int r = m_image_ctx->md_ctx.aio_operate(RBD_MIRRORING, comp, &op, &m_out_bl);
+  int r = m_io_ctx.aio_operate(RBD_MIRRORING, comp, &op, &m_out_bl);
   assert(r == 0);
   comp->release();
 }
 
 template <typename I>
 Context *EnableRequest<I>::handle_get_mirror_image(int *result) {
-  CephContext *cct = m_image_ctx->cct;
-  ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
+  ldout(m_cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
 
   if (*result == 0) {
     bufferlist::iterator iter = m_out_bl.begin();
@@ -93,26 +98,30 @@ Context *EnableRequest<I>::handle_get_mirror_image(int *result) {
 
   if (*result == 0) {
     if (m_mirror_image.state == cls::rbd::MIRROR_IMAGE_STATE_ENABLED) {
-      ldout(cct, 10) << this << " " << __func__
-                     << ": mirroring is already enabled" << dendl;
+      ldout(m_cct, 10) << this << " " << __func__
+                       << ": mirroring is already enabled" << dendl;
     } else {
-      lderr(cct) << "currently disabling" << dendl;
+      lderr(m_cct) << "currently disabling" << dendl;
       *result = -EINVAL;
     }
     return m_on_finish;
   }
 
   if (*result != -ENOENT) {
-    lderr(cct) << "failed to retreive mirror image: " << cpp_strerror(*result)
-               << dendl;
+    lderr(m_cct) << "failed to retreive mirror image: " << cpp_strerror(*result)
+                 << dendl;
     return m_on_finish;
   }
 
   *result = 0;
   m_mirror_image.state = cls::rbd::MIRROR_IMAGE_STATE_ENABLED;
-  uuid_d uuid_gen;
-  uuid_gen.generate_random();
-  m_mirror_image.global_image_id = uuid_gen.to_string();
+  if (m_non_primary_global_image_id.empty()) {
+    uuid_d uuid_gen;
+    uuid_gen.generate_random();
+    m_mirror_image.global_image_id = uuid_gen.to_string();
+  } else {
+    m_mirror_image.global_image_id = m_non_primary_global_image_id;
+  }
 
   send_set_mirror_image();
   return nullptr;
@@ -120,29 +129,27 @@ Context *EnableRequest<I>::handle_get_mirror_image(int *result) {
 
 template <typename I>
 void EnableRequest<I>::send_set_mirror_image() {
-  CephContext *cct = m_image_ctx->cct;
-  ldout(cct, 10) << this << " " << __func__ << dendl;
+  ldout(m_cct, 10) << this << " " << __func__ << dendl;
 
   librados::ObjectWriteOperation op;
-  cls_client::mirror_image_set(&op, m_image_ctx->id, m_mirror_image);
+  cls_client::mirror_image_set(&op, m_image_id, m_mirror_image);
 
   using klass = EnableRequest<I>;
   librados::AioCompletion *comp =
     create_rados_ack_callback<klass, &klass::handle_set_mirror_image>(this);
   m_out_bl.clear();
-  int r = m_image_ctx->md_ctx.aio_operate(RBD_MIRRORING, comp, &op);
+  int r = m_io_ctx.aio_operate(RBD_MIRRORING, comp, &op);
   assert(r == 0);
   comp->release();
 }
 
 template <typename I>
 Context *EnableRequest<I>::handle_set_mirror_image(int *result) {
-  CephContext *cct = m_image_ctx->cct;
-  ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
+  ldout(m_cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
 
   if (*result < 0) {
-    lderr(cct) << "failed to enable mirroring: " << cpp_strerror(*result)
-               << dendl;
+    lderr(m_cct) << "failed to enable mirroring: " << cpp_strerror(*result)
+                 << dendl;
     return m_on_finish;
   }
 
@@ -152,27 +159,25 @@ Context *EnableRequest<I>::handle_set_mirror_image(int *result) {
 
 template <typename I>
 void EnableRequest<I>::send_notify_mirroring_watcher() {
-  CephContext *cct = m_image_ctx->cct;
-  ldout(cct, 10) << this << " " << __func__ << dendl;
+  ldout(m_cct, 10) << this << " " << __func__ << dendl;
 
   using klass = EnableRequest<I>;
   Context *ctx = create_context_callback<
     klass, &klass::handle_notify_mirroring_watcher>(this);
 
-  MirroringWatcher<>::notify_image_updated(m_image_ctx->md_ctx,
+  MirroringWatcher<>::notify_image_updated(m_io_ctx,
                                            cls::rbd::MIRROR_IMAGE_STATE_ENABLED,
-                                           m_image_ctx->id,
+                                           m_image_id,
                                            m_mirror_image.global_image_id, ctx);
 }
 
 template <typename I>
 Context *EnableRequest<I>::handle_notify_mirroring_watcher(int *result) {
-  CephContext *cct = m_image_ctx->cct;
-  ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
+  ldout(m_cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
 
   if (*result < 0) {
-    lderr(cct) << "failed to send update notification: "
-               << cpp_strerror(*result) << dendl;
+    lderr(m_cct) << "failed to send update notification: "
+                 << cpp_strerror(*result) << dendl;
     *result = 0;
   }
 
index 8860365de3c57775976f4209378505d9f2ad7eb8..e2145374a2cbf225a2d4dac3285e31d49dacac9d 100644 (file)
@@ -10,6 +10,7 @@
 #include <string>
 
 class Context;
+class ContextWQ;
 
 namespace librados { class IoCtx; }
 
@@ -23,7 +24,15 @@ template <typename ImageCtxT = ImageCtx>
 class EnableRequest {
 public:
   static EnableRequest *create(ImageCtxT *image_ctx, Context *on_finish) {
-    return new EnableRequest(image_ctx, on_finish);
+    return create(image_ctx->md_ctx, image_ctx->id, "",
+                  image_ctx->op_work_queue, on_finish);
+  }
+  static EnableRequest *create(librados::IoCtx &io_ctx,
+                               const std::string &image_id,
+                               const std::string &non_primary_global_image_id,
+                               ContextWQ *op_work_queue, Context *on_finish) {
+    return new EnableRequest(io_ctx, image_id, non_primary_global_image_id,
+                             op_work_queue, on_finish);
   }
 
   void send();
@@ -35,6 +44,9 @@ private:
    * <start>
    *    |
    *    v
+   * GET_MIRROR_MODE  * * * * * * *
+   *    |                         *
+   *    v                         *
    * GET_TAG_OWNER  * * * * * * * *
    *    |                         *
    *    v                         *
@@ -52,13 +64,17 @@ private:
    * @endverbatim
    */
 
-  EnableRequest(ImageCtxT *image_ctx, Context *on_finish);
+  EnableRequest(librados::IoCtx &io_ctx, const std::string &image_id,
+                const std::string &non_primary_global_image_id,
+                ContextWQ *op_work_queue, Context *on_finish);
 
-  librados::IoCtx *m_io_ctx = nullptr;
+  librados::IoCtx &m_io_ctx;
   std::string m_image_id;
-  ImageCtxT *m_image_ctx = nullptr;
+  std::string m_non_primary_global_image_id;
+  ContextWQ *m_op_work_queue;
   Context *m_on_finish;
 
+  CephContext *m_cct = nullptr;
   bool m_is_primary = false;
   bufferlist m_out_bl;
   cls::rbd::MirrorImage m_mirror_image;
index 1745bc60452c4652bec55bdcb32c2f230a700a14..0eb97b207f8ca3877e5f1bf65c9d4fd432c9941a 100644 (file)
@@ -187,7 +187,6 @@ OpenRequest<MockJournalImageCtx> *OpenRequest<MockJournalImageCtx>::s_instance =
 
 // template definitions
 #include "librbd/Journal.cc"
-template class librbd::Journal<librbd::MockJournalImageCtx>;
 
 using ::testing::_;
 using ::testing::DoAll;
index f00c113aa7952f2f4aedb057fad516a7a0f4d458..629f6090fe034b3d1f507b9144cb8ed5e5ff93bc 100644 (file)
@@ -40,9 +40,13 @@ struct CreateRequest<librbd::MockTestImageCtx> {
                                const librbd::ImageOptions &image_options,
                                const std::string &non_primary_global_image_id,
                                const std::string &primary_mirror_uuid,
+                               bool skip_mirror_enable,
                                MockContextWQ *op_work_queue,
                                Context *on_finish) {
     assert(s_instance != nullptr);
+    EXPECT_FALSE(non_primary_global_image_id.empty());
+    EXPECT_FALSE(primary_mirror_uuid.empty());
+    EXPECT_FALSE(skip_mirror_enable);
     s_instance->on_finish = on_finish;
     s_instance->construct(ioctx);
     return s_instance;
index 96c726a6206595c6e263409f679e2beef27d8a4c..88d856c467f729bea61df2bafdee3aee2d6a7e12 100644 (file)
@@ -78,7 +78,7 @@ void CreateImageRequest<I>::create_image() {
 
   librbd::image::CreateRequest<I> *req = librbd::image::CreateRequest<I>::create(
     m_local_io_ctx, m_local_image_name, id, m_remote_image_ctx->size,
-    image_options, m_global_image_id, m_remote_mirror_uuid,
+    image_options, m_global_image_id, m_remote_mirror_uuid, false,
     m_remote_image_ctx->op_work_queue, ctx);
   req->send();
 }