]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: use task finisher thread for image open/close callbacks 36287/head
authorJason Dillaman <dillaman@redhat.com>
Fri, 24 Jul 2020 16:13:10 +0000 (12:13 -0400)
committerJason Dillaman <dillaman@redhat.com>
Mon, 27 Jul 2020 13:15:15 +0000 (09:15 -0400)
There was a potential race condition with utilizing the AsioEngine
to deliver asynchronous image open and close callbacks. This left
the potential for the io_context thread to attempt to destroy itself.

This commit changes the behavior of the image open and close callbacks
to always delete the ImageCtx (now matches the synchronous API behavior)
and it always invokes the callback in Finisher thread whose lifetime is
tied to the CephContext.

Signed-off-by: Jason Dillaman <dillaman@redhat.com>
28 files changed:
src/librbd/ImageCtx.h
src/librbd/ImageState.cc
src/librbd/TaskFinisher.h
src/librbd/api/Group.cc
src/librbd/deep_copy/ImageCopyRequest.cc
src/librbd/image/CloneRequest.cc
src/librbd/image/CloseRequest.cc
src/librbd/image/DetachChildRequest.cc
src/librbd/image/RefreshParentRequest.cc
src/librbd/image/RemoveRequest.cc
src/librbd/io/AioCompletion.cc
src/librbd/librbd.cc
src/librbd/mirror/EnableRequest.cc
src/librbd/trash/RemoveRequest.cc
src/test/librbd/deep_copy/test_mock_ImageCopyRequest.cc
src/test/librbd/image/test_mock_CloneRequest.cc
src/test/librbd/image/test_mock_DetachChildRequest.cc
src/test/librbd/image/test_mock_RemoveRequest.cc
src/test/librbd/mock/MockImageCtx.h
src/test/librbd/operation/test_mock_ResizeRequest.cc
src/test/librbd/trash/test_mock_RemoveRequest.cc
src/test/rbd_mirror/image_deleter/test_mock_SnapshotPurgeRequest.cc
src/test/rbd_mirror/image_deleter/test_mock_TrashMoveRequest.cc
src/tools/rbd_mirror/image_deleter/SnapshotPurgeRequest.cc
src/tools/rbd_mirror/image_deleter/TrashMoveRequest.cc
src/tools/rbd_mirror/image_replayer/CloseImageRequest.cc
src/tools/rbd_mirror/image_replayer/OpenImageRequest.cc
src/tools/rbd_mirror/image_replayer/OpenLocalImageRequest.cc

index de783e0fb3c68ceae2d0d5ac121bacda2d1adc2f..34677bdf31454272613cc3aea8a1a7a586b8981e 100644 (file)
@@ -246,9 +246,6 @@ namespace librbd {
                             bool read_only) {
       return new ImageCtx(image_name, image_id, snap_id, p, read_only);
     }
-    void destroy() {
-      delete this;
-    }
 
     /**
      * Either image_name or image_id must be set.
index 96f57f87910e583e372b3d9eb0a050580a7e5203..b528cc260fc1b143c82cd320faf8f1fc0e845bbe 100644 (file)
@@ -9,6 +9,7 @@
 #include "common/WorkQueue.h"
 #include "librbd/AsioEngine.h"
 #include "librbd/ImageCtx.h"
+#include "librbd/TaskFinisher.h"
 #include "librbd/Utils.h"
 #include "librbd/asio/ContextWQ.h"
 #include "librbd/image/CloseRequest.h"
@@ -441,9 +442,6 @@ int ImageState<I>::open(uint64_t flags) {
   open(flags, &ctx);
 
   int r = ctx.wait();
-  if (r < 0) {
-    delete m_image_ctx;
-  }
   return r;
 }
 
@@ -468,7 +466,6 @@ int ImageState<I>::close() {
   close(&ctx);
 
   int r = ctx.wait();
-  delete m_image_ctx;
   return r;
 }
 
@@ -763,11 +760,23 @@ void ImageState<I>::complete_action_unlock(State next_state, int r) {
   m_state = next_state;
   m_lock.unlock();
 
-  for (auto ctx : action_contexts.second) {
-    ctx->complete(r);
-  }
+  if (next_state == STATE_CLOSED ||
+      (next_state == STATE_UNINITIALIZED && r < 0)) {
+    // the ImageCtx must be deleted outside the scope of its callback threads
+    auto ctx = new LambdaContext(
+      [image_ctx=m_image_ctx, contexts=std::move(action_contexts.second)]
+      (int r) {
+        delete image_ctx;
+        for (auto ctx : contexts) {
+          ctx->complete(r);
+        }
+      });
+    TaskFinisherSingleton::get_singleton(m_image_ctx->cct).queue(ctx, r);
+  } else {
+    for (auto ctx : action_contexts.second) {
+      ctx->complete(r);
+    }
 
-  if (next_state != STATE_UNINITIALIZED && next_state != STATE_CLOSED) {
     m_lock.lock();
     if (!is_transition_state() && !m_actions_contexts.empty()) {
       execute_next_action_unlock();
index a791e786ff157afd8dc2d7dd50315916e901c8b5..bf76f633f7b4c7af12492fb1f6fb6266f1089d4f 100644 (file)
@@ -20,6 +20,11 @@ struct TaskFinisherSingleton {
   SafeTimer *m_safe_timer;
   Finisher *m_finisher;
 
+  static TaskFinisherSingleton& get_singleton(CephContext* cct) {
+    return cct->lookup_or_create_singleton_object<
+      TaskFinisherSingleton>("librbd::TaskFinisherSingleton", false, cct);
+  }
+
   explicit TaskFinisherSingleton(CephContext *cct) {
     m_safe_timer = new SafeTimer(cct, m_lock, false);
     m_safe_timer->init();
@@ -36,6 +41,10 @@ struct TaskFinisherSingleton {
     m_finisher->stop();
     delete m_finisher;
   }
+
+  void queue(Context* ctx, int r) {
+    m_finisher->queue(ctx, r);
+  }
 };
 
 
@@ -43,9 +52,7 @@ template <typename Task>
 class TaskFinisher {
 public:
   TaskFinisher(CephContext &cct) : m_cct(cct) {
-    auto& singleton =
-      cct.lookup_or_create_singleton_object<TaskFinisherSingleton>(
-       "librbd::TaskFinisher::m_safe_timer", false, &cct);
+    auto& singleton = TaskFinisherSingleton::get_singleton(&cct);
     m_lock = &singleton.m_lock;
     m_safe_timer = singleton.m_safe_timer;
     m_finisher = singleton.m_finisher;
index 2beca5adb0b9e8db71c6ce56d2af1dbefa4ae6f6..b33b3f4998f878bbe96528af832723b10141522a 100644 (file)
@@ -251,7 +251,6 @@ int group_snap_remove_by_record(librados::IoCtx& group_ioctx,
     r = on_finishes[i]->wait();
     delete on_finishes[i];
     if (r < 0) {
-      delete ictxs[i];
       ictxs[i] = nullptr;
       ret_code = r;
     }
@@ -359,7 +358,6 @@ int group_snap_rollback_by_record(librados::IoCtx& group_ioctx,
     r = on_finishes[i]->wait();
     delete on_finishes[i];
     if (r < 0) {
-      delete ictxs[i];
       ictxs[i] = nullptr;
       ret_code = r;
     }
@@ -973,7 +971,6 @@ int Group<I>::snap_create(librados::IoCtx& group_ioctx,
     r = on_finishes[i]->wait();
     delete on_finishes[i];
     if (r < 0) {
-      delete ictxs[i];
       ictxs[i] = nullptr;
       ret_code = r;
     }
index 739e55c33ccc240890434c5f1a962e8efc740e07..859b13adb6ce96fff4245381ff0a14ecbfd43dd5 100644 (file)
@@ -7,8 +7,6 @@
 #include "librbd/Utils.h"
 #include "librbd/deep_copy/Handler.h"
 #include "librbd/deep_copy/Utils.h"
-#include "librbd/image/CloseRequest.h"
-#include "librbd/image/OpenRequest.h"
 #include "librbd/object_map/DiffRequest.h"
 #include "osdc/Striper.h"
 
index 8db5ee0efc7f3081a6a2563e65d2913ffcb671e5..1b11b3a5fae034c12c8be7040ee243eab351e0de 100644 (file)
@@ -160,7 +160,6 @@ void CloneRequest<I>::handle_open_parent(int r) {
   ldout(m_cct, 20) << "r=" << r << dendl;
 
   if (r < 0) {
-    m_parent_image_ctx->destroy();
     m_parent_image_ctx = nullptr;
 
     lderr(m_cct) << "failed to open parent image: " << cpp_strerror(r) << dendl;
@@ -345,7 +344,6 @@ void CloneRequest<I>::handle_open_child(int r) {
   ldout(m_cct, 15) << "r=" << r << dendl;
 
   if (r < 0) {
-    m_imctx->destroy();
     m_imctx = nullptr;
 
     lderr(m_cct) << "Error opening new image: " << cpp_strerror(r) << dendl;
@@ -517,10 +515,8 @@ void CloneRequest<I>::close_child() {
 
   ceph_assert(m_imctx != nullptr);
 
-  using klass = CloneRequest<I>;
-  Context *ctx = create_async_context_callback(
-    *m_imctx, create_context_callback<
-      klass, &klass::handle_close_child>(this));
+  auto ctx = create_context_callback<
+    CloneRequest<I>, &CloneRequest<I>::handle_close_child>(this);
   m_imctx->state->close(ctx);
 }
 
@@ -528,7 +524,6 @@ template <typename I>
 void CloneRequest<I>::handle_close_child(int r) {
   ldout(m_cct, 15) << dendl;
 
-  m_imctx->destroy();
   m_imctx = nullptr;
 
   if (r < 0) {
@@ -576,9 +571,8 @@ void CloneRequest<I>::close_parent() {
   ldout(m_cct, 20) << dendl;
   ceph_assert(m_parent_image_ctx != nullptr);
 
-  Context *ctx = create_async_context_callback(
-    *m_parent_image_ctx, create_context_callback<
-      CloneRequest<I>, &CloneRequest<I>::handle_close_parent>(this));
+  auto ctx = create_context_callback<
+    CloneRequest<I>, &CloneRequest<I>::handle_close_parent>(this);
   m_parent_image_ctx->state->close(ctx);
 }
 
@@ -586,7 +580,6 @@ template <typename I>
 void CloneRequest<I>::handle_close_parent(int r) {
   ldout(m_cct, 20) << "r=" << r << dendl;
 
-  m_parent_image_ctx->destroy();
   m_parent_image_ctx = nullptr;
 
   if (r < 0) {
index 95460268251e1cfdb1b679d8e00496ee9c20d11c..ecd1af7852b10fb8e69cd4805d297d2fa1143c04 100644 (file)
@@ -297,7 +297,6 @@ void CloseRequest<I>::handle_close_parent(int r) {
   CephContext *cct = m_image_ctx->cct;
   ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl;
 
-  delete m_image_ctx->parent;
   m_image_ctx->parent = nullptr;
   save_result(r);
   if (r < 0) {
index f786c2d3a651e80b907c74edb8f491c9cb14cf53..ab39dbcd72ddcebf4709ae726fe11a928594f204 100644 (file)
@@ -184,7 +184,6 @@ void DetachChildRequest<I>::handle_clone_v2_open_parent(int r) {
   if (r < 0) {
     ldout(cct, 5) << "failed to open parent for read/write: "
                   << cpp_strerror(r) << dendl;
-    m_parent_image_ctx->destroy();
     m_parent_image_ctx = nullptr;
     finish(0);
     return;
@@ -339,7 +338,6 @@ void DetachChildRequest<I>::handle_clone_v2_close_parent(int r) {
                   << dendl;
   }
 
-  m_parent_image_ctx->destroy();
   m_parent_image_ctx = nullptr;
   finish(0);
 }
index 8cc0cf949a0f2f1d4e891763cc5ab7e32fce89a1..6689b137b05f65b4faae7972c19c0562556784cf 100644 (file)
@@ -6,10 +6,9 @@
 #include "common/dout.h"
 #include "common/errno.h"
 #include "librbd/ImageCtx.h"
+#include "librbd/ImageState.h"
 #include "librbd/Utils.h"
 #include "librbd/asio/ContextWQ.h"
-#include "librbd/image/CloseRequest.h"
-#include "librbd/image/OpenRequest.h"
 #include "librbd/io/ObjectDispatcherInterface.h"
 
 #define dout_subsys ceph_subsys_rbd
@@ -140,12 +139,11 @@ void RefreshParentRequest<I>::send_open_parent() {
     m_parent_image_ctx->set_read_flag(librados::OPERATION_LOCALIZE_READS);
   }
 
-  using klass = RefreshParentRequest<I>;
-  Context *ctx = create_async_context_callback(
+  auto ctx = create_async_context_callback(
     m_child_image_ctx, create_context_callback<
-      klass, &klass::handle_open_parent, false>(this));
-  OpenRequest<I> *req = OpenRequest<I>::create(m_parent_image_ctx, flags, ctx);
-  req->send();
+      RefreshParentRequest<I>,
+      &RefreshParentRequest<I>::handle_open_parent, false>(this));
+  m_parent_image_ctx->state->open(flags, ctx);
 }
 
 template <typename I>
@@ -159,7 +157,6 @@ Context *RefreshParentRequest<I>::handle_open_parent(int *result) {
                << dendl;
 
     // image already closed by open state machine
-    delete m_parent_image_ctx;
     m_parent_image_ctx = nullptr;
   }
 
@@ -173,12 +170,11 @@ void RefreshParentRequest<I>::send_close_parent() {
   CephContext *cct = m_child_image_ctx.cct;
   ldout(cct, 10) << this << " " << __func__ << dendl;
 
-  using klass = RefreshParentRequest<I>;
-  Context *ctx = create_async_context_callback(
+  auto ctx = create_async_context_callback(
     m_child_image_ctx, create_context_callback<
-      klass, &klass::handle_close_parent, false>(this));
-  CloseRequest<I> *req = CloseRequest<I>::create(m_parent_image_ctx, ctx);
-  req->send();
+      RefreshParentRequest<I>,
+      &RefreshParentRequest<I>::handle_close_parent, false>(this));
+  m_parent_image_ctx->state->close(ctx);
 }
 
 template <typename I>
@@ -186,7 +182,6 @@ Context *RefreshParentRequest<I>::handle_close_parent(int *result) {
   CephContext *cct = m_child_image_ctx.cct;
   ldout(cct, 10) << this << " " << __func__ << " r=" << *result << dendl;
 
-  delete m_parent_image_ctx;
   m_parent_image_ctx = nullptr;
 
   if (*result < 0) {
index 3142b7e3928cefa7b04d1dc8af514a6c7b355b57..42af593b1b5e7403e0416d23b779c475909f3196 100644 (file)
@@ -85,7 +85,6 @@ void RemoveRequest<I>::handle_open_image(int r) {
   ldout(m_cct, 20) << "r=" << r << dendl;
 
   if (r < 0) {
-    m_image_ctx->destroy();
     m_image_ctx = nullptr;
 
     if (r != -ENOENT) {
@@ -251,7 +250,6 @@ void RemoveRequest<I>::handle_send_close_image(int r) {
                  << cpp_strerror(r) << dendl;
   }
 
-  m_image_ctx->destroy();
   m_image_ctx = nullptr;
   if (m_ret_val < 0) {
     r = m_ret_val;
index cad103364244c1a1f4a970a86c679dee4d3c2f72..f518694e603504ebdabfa5603d12becc71ed2f7e 100644 (file)
@@ -63,41 +63,38 @@ void AioCompletion::finalize() {
 
 void AioCompletion::complete() {
   ceph_assert(ictx != nullptr);
-  CephContext *cct = ictx->cct;
 
   ssize_t r = rval;
-  tracepoint(librbd, aio_complete_enter, this, r);
-  if (ictx->perfcounter != nullptr) {
-    ceph::timespan elapsed = coarse_mono_clock::now() - start_time;
-    switch (aio_type) {
-    case AIO_TYPE_GENERIC:
-    case AIO_TYPE_OPEN:
-    case AIO_TYPE_CLOSE:
-      break;
-    case AIO_TYPE_READ:
-      ictx->perfcounter->tinc(l_librbd_rd_latency, elapsed); break;
-    case AIO_TYPE_WRITE:
-      ictx->perfcounter->tinc(l_librbd_wr_latency, elapsed); break;
-    case AIO_TYPE_DISCARD:
-      ictx->perfcounter->tinc(l_librbd_discard_latency, elapsed); break;
-    case AIO_TYPE_FLUSH:
-      ictx->perfcounter->tinc(l_librbd_flush_latency, elapsed); break;
-    case AIO_TYPE_WRITESAME:
-      ictx->perfcounter->tinc(l_librbd_ws_latency, elapsed); break;
-    case AIO_TYPE_COMPARE_AND_WRITE:
-      ictx->perfcounter->tinc(l_librbd_cmp_latency, elapsed); break;
-    default:
-      lderr(cct) << "completed invalid aio_type: " << aio_type << dendl;
-      break;
-    }
-  }
-
-  if ((aio_type == AIO_TYPE_CLOSE) ||
-      (aio_type == AIO_TYPE_OPEN && r < 0)) {
-    // must destroy ImageCtx prior to invoking callback
-    delete ictx;
+  if ((aio_type == AIO_TYPE_CLOSE) || (aio_type == AIO_TYPE_OPEN && r < 0)) {
     ictx = nullptr;
     external_callback = false;
+  } else {
+    CephContext *cct = ictx->cct;
+
+    tracepoint(librbd, aio_complete_enter, this, r);
+    if (ictx->perfcounter != nullptr) {
+      ceph::timespan elapsed = coarse_mono_clock::now() - start_time;
+      switch (aio_type) {
+      case AIO_TYPE_GENERIC:
+      case AIO_TYPE_OPEN:
+        break;
+      case AIO_TYPE_READ:
+        ictx->perfcounter->tinc(l_librbd_rd_latency, elapsed); break;
+      case AIO_TYPE_WRITE:
+        ictx->perfcounter->tinc(l_librbd_wr_latency, elapsed); break;
+      case AIO_TYPE_DISCARD:
+        ictx->perfcounter->tinc(l_librbd_discard_latency, elapsed); break;
+      case AIO_TYPE_FLUSH:
+        ictx->perfcounter->tinc(l_librbd_flush_latency, elapsed); break;
+      case AIO_TYPE_WRITESAME:
+        ictx->perfcounter->tinc(l_librbd_ws_latency, elapsed); break;
+      case AIO_TYPE_COMPARE_AND_WRITE:
+        ictx->perfcounter->tinc(l_librbd_cmp_latency, elapsed); break;
+      default:
+        lderr(cct) << "completed invalid aio_type: " << aio_type << dendl;
+        break;
+      }
+    }
   }
 
   state = AIO_STATE_CALLBACK;
@@ -182,17 +179,29 @@ void AioCompletion::unblock(CephContext* cct) {
 void AioCompletion::fail(int r)
 {
   ceph_assert(ictx != nullptr);
-  CephContext *cct = ictx->cct;
-  lderr(cct) << cpp_strerror(r) << dendl;
+  ceph_assert(r < 0);
+
+  bool queue_required = true;
+  if (aio_type == AIO_TYPE_CLOSE || aio_type == AIO_TYPE_OPEN) {
+    // executing from a safe context and the ImageCtx has been destructed
+    queue_required = false;
+  } else {
+    CephContext *cct = ictx->cct;
+    lderr(cct) << cpp_strerror(r) << dendl;
+  }
 
   ceph_assert(!was_armed);
   was_armed = true;
 
-  error_rval = r;
+  rval = r;
 
   uint32_t previous_pending_count = pending_count.load();
   if (previous_pending_count == 0) {
-    queue_complete();
+    if (queue_required) {
+      queue_complete();
+    } else {
+      complete();
+    }
   }
 }
 
index 2e10188acea9f7d03c1bfc89255860d20de13fb2..34c47ea885e3ffeb9f413a15f37052b3a84d5579 100644 (file)
@@ -127,7 +127,7 @@ struct C_AioCompletion : public Context {
   }
 
   void finish(int r) override {
-    ldout(cct, 20) << "C_AioComplete::finish: r=" << r << dendl;
+    ldout(cct, 20) << "C_AioCompletion::finish: r=" << r << dendl;
     if (r < 0) {
       aio_comp->fail(r);
     } else {
@@ -145,7 +145,7 @@ struct C_OpenComplete : public C_AioCompletion {
       ictx(ictx), ictxp(ictxp) {
   }
   void finish(int r) override {
-    ldout(ictx->cct, 20) << "C_OpenComplete::finish: r=" << r << dendl;
+    ldout(cct, 20) << "C_OpenComplete::finish: r=" << r << dendl;
     if (r < 0) {
       *ictxp = nullptr;
     } else {
@@ -168,7 +168,6 @@ struct C_OpenAfterCloseComplete : public Context {
   void finish(int r) override {
     ldout(ictx->cct, 20) << "C_OpenAfterCloseComplete::finish: r=" << r
                         << dendl;
-    delete reinterpret_cast<librbd::ImageCtx*>(*ictxp);
     *ictxp = nullptr;
 
     ictx->state->open(0, new C_OpenComplete(ictx, comp, ictxp));
index d4627c2c13047fc9d7676c0d28b1df3bf93b74bc..c7f7d8746f0d7ce9ce6f528994556495d29bd8ac 100644 (file)
@@ -173,7 +173,6 @@ void EnableRequest<I>::handle_open_image(int r) {
 
   if (r < 0) {
     lderr(m_cct) << "failed to open image: " << cpp_strerror(r) << dendl;
-    m_image_ctx->destroy();
     m_image_ctx = nullptr;
     finish(r);
     return;
@@ -237,7 +236,6 @@ template <typename I>
 void EnableRequest<I>::handle_close_image(int r) {
   ldout(m_cct, 10) << "r=" << r << dendl;
 
-  m_image_ctx->destroy();
   m_image_ctx = nullptr;
 
   if (r < 0) {
index bff30df6cec86092976ee670a43a69bb1e9f537e..1149d1d8011db98c853a696ebd9246c295b05551 100644 (file)
@@ -91,7 +91,6 @@ void RemoveRequest<I>::handle_close_image(int r) {
     ldout(m_cct, 5) << "failed to close image:" << cpp_strerror(r) << dendl;
   }
 
-  m_image_ctx->destroy();
   m_image_ctx = nullptr;
   finish(m_ret_val);
 }
index f20867cd4ba30700bc7518679c172d4b6ff83957..815401c97fc7284b121b4293e51c416c56e9363b 100644 (file)
@@ -11,8 +11,6 @@
 #include "librbd/deep_copy/Handler.h"
 #include "librbd/deep_copy/ImageCopyRequest.h"
 #include "librbd/deep_copy/ObjectCopyRequest.h"
-#include "librbd/image/CloseRequest.h"
-#include "librbd/image/OpenRequest.h"
 #include "librbd/object_map/DiffRequest.h"
 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
 #include "test/librbd/mock/MockImageCtx.h"
@@ -83,49 +81,6 @@ ObjectCopyRequest<librbd::MockTestImageCtx>* ObjectCopyRequest<librbd::MockTestI
 
 } // namespace deep_copy
 
-namespace image {
-
-template <>
-struct CloseRequest<MockTestImageCtx> {
-  Context* on_finish = nullptr;
-  static CloseRequest* s_instance;
-  static CloseRequest* create(MockTestImageCtx *image_ctx, Context *on_finish) {
-    ceph_assert(s_instance != nullptr);
-    s_instance->on_finish = on_finish;
-    return s_instance;
-  }
-
-  MOCK_METHOD0(send, void());
-
-  CloseRequest() {
-    s_instance = this;
-  }
-};
-
-CloseRequest<MockTestImageCtx>* CloseRequest<MockTestImageCtx>::s_instance = nullptr;
-
-template <>
-struct OpenRequest<MockTestImageCtx> {
-  Context* on_finish = nullptr;
-  static OpenRequest* s_instance;
-  static OpenRequest* create(MockTestImageCtx *image_ctx,
-                             bool skip_open_parent, Context *on_finish) {
-    ceph_assert(s_instance != nullptr);
-    s_instance->on_finish = on_finish;
-    return s_instance;
-  }
-
-  MOCK_METHOD0(send, void());
-
-  OpenRequest() {
-    s_instance = this;
-  }
-};
-
-OpenRequest<MockTestImageCtx>* OpenRequest<MockTestImageCtx>::s_instance = nullptr;
-
-} // namespace image
-
 namespace object_map {
 
 template <>
index 1a0524e56898266473484d600483180de29df72d..25de66dabb75f3c8449fa08da0ac96024901cb0c 100644 (file)
@@ -291,9 +291,6 @@ public:
       .WillOnce(WithArg<1>(Invoke([this, r](Context* ctx) {
                              image_ctx->op_work_queue->queue(ctx, r);
                            })));
-    if (r < 0) {
-      EXPECT_CALL(mock_image_ctx, destroy());
-    }
   }
 
   void expect_attach_parent(MockAttachParentRequest& mock_request, int r) {
@@ -352,7 +349,6 @@ public:
       .WillOnce(Invoke([this, r](Context* ctx) {
                   image_ctx->op_work_queue->queue(ctx, r);
                 }));
-    EXPECT_CALL(mock_image_ctx, destroy());
   }
 
   void expect_remove(MockRemoveRequest& mock_remove_request, int r) {
index f160305a0071d531f4ef4fe9c8415d3f0b53bdb3..6812125cb20a406547bb457fe001e8af8f1ad5b1 100644 (file)
@@ -174,7 +174,6 @@ public:
       .WillOnce(Invoke([this, r](Context* ctx) {
                   image_ctx->op_work_queue->queue(ctx, r);
                 }));
-    EXPECT_CALL(mock_image_ctx, destroy());
   }
 
   void expect_snap_remove(MockImageCtx &mock_image_ctx,
@@ -373,7 +372,6 @@ TEST_F(TestMockImageDetachChildRequest, TrashedSnapshotOpenParentError) {
                       {234, {cls::rbd::TrashSnapshotNamespace{}},
                        "snap1", 123, {}, 0}, 0);
   expect_open(mock_image_ctx, -EPERM);
-  EXPECT_CALL(mock_image_ctx, destroy());
 
   C_SaferCond ctx;
   auto req = MockDetachChildRequest::create(mock_image_ctx, &ctx);
index 9a6e8abdb00de83b4a35915912f5f5f633f3e118..9700202d64fe47b25c6010446d0a803c242cbab7 100644 (file)
@@ -245,9 +245,6 @@ public:
       .WillOnce(Invoke([r](bool open_parent, Context *on_ready) {
                  on_ready->complete(r);
                 }));
-    if (r < 0) {
-      EXPECT_CALL(mock_image_ctx, destroy());
-    }
   }
 
   void expect_state_close(MockTestImageCtx &mock_image_ctx) {
@@ -255,7 +252,6 @@ public:
       .WillOnce(Invoke([](Context *on_ready) {
                   on_ready->complete(0);
                 }));
-    EXPECT_CALL(mock_image_ctx, destroy());
   }
 
   void expect_wq_queue(ContextWQ &wq, int r) {
index a06ce09e6a5dc966232198a7c2a4111a7ca28618..70ba2d8a0caf6f7e5bd3abd16324556f5619fe3c 100644 (file)
@@ -40,7 +40,6 @@ struct MockImageCtx {
     ceph_assert(s_instance != nullptr);
     return s_instance;
   }
-  MOCK_METHOD0(destroy, void());
 
   MockImageCtx(librbd::ImageCtx &image_ctx)
     : image_ctx(&image_ctx),
index 7c5fb546209058f6bcbfcdebfcf51d5279b36d9f..fb7d263ba2593e43c7ffe371cc4d4ebd4ca6928e 100644 (file)
@@ -160,7 +160,13 @@ public:
       .WillOnce(Invoke([&mock_image_ctx, &mock_io_image_dispatch_spec, r]() {
                   auto aio_comp = mock_io_image_dispatch_spec.s_instance->aio_comp;
                   auto ctx = new LambdaContext([aio_comp](int r) {
-                    aio_comp->fail(r);
+                    if (r < 0) {
+                      aio_comp->fail(r);
+                    } else {
+                      aio_comp->set_request_count(1);
+                      aio_comp->add_request();
+                      aio_comp->complete_request(r);
+                    }
                   });
                   mock_image_ctx.image_ctx->op_work_queue->queue(ctx, r);
                 }));
index 2e75b3ac5b8f1f927ca956685926b1ede711cf0d..51d6123de02cf7e5eb351e276d06960ad341dfcc 100644 (file)
@@ -122,7 +122,6 @@ struct TestMockTrashRemoveRequest : public TestMockFixture {
       .WillOnce(Invoke([r](Context *on_finish) {
                   on_finish->complete(r);
                 }));
-    EXPECT_CALL(mock_image_ctx, destroy());
   }
 
   void expect_remove_image(MockImageRemoveRequest& mock_image_remove_request,
index ef0d0afb1c08c8cecdee2d5e79c55d08678e204e..2f14854def5816198daac16bdbf3c29a16a24790 100644 (file)
@@ -152,10 +152,6 @@ public:
                 }));
   }
 
-  void expect_destroy(librbd::MockTestImageCtx& mock_image_ctx) {
-    EXPECT_CALL(mock_image_ctx, destroy());
-  }
-
   librbd::ImageCtx *m_local_image_ctx;
 };
 
@@ -198,7 +194,6 @@ TEST_F(TestMockImageDeleterSnapshotPurgeRequest, SuccessJournal) {
                      0);
 
   expect_close(mock_image_ctx, 0);
-  expect_destroy(mock_image_ctx);
 
   C_SaferCond ctx;
   auto req = MockSnapshotPurgeRequest::create(m_local_io_ctx, mock_image_ctx.id,
@@ -240,7 +235,6 @@ TEST_F(TestMockImageDeleterSnapshotPurgeRequest, SuccessSnapshot) {
                      0);
 
   expect_close(mock_image_ctx, 0);
-  expect_destroy(mock_image_ctx);
 
   C_SaferCond ctx;
   auto req = MockSnapshotPurgeRequest::create(m_local_io_ctx, mock_image_ctx.id,
@@ -264,7 +258,6 @@ TEST_F(TestMockImageDeleterSnapshotPurgeRequest, OpenError) {
   InSequence seq;
   expect_set_journal_policy(mock_image_ctx);
   expect_open(mock_image_ctx, -EPERM);
-  expect_destroy(mock_image_ctx);
 
   C_SaferCond ctx;
   auto req = MockSnapshotPurgeRequest::create(m_local_io_ctx, mock_image_ctx.id,
@@ -290,7 +283,6 @@ TEST_F(TestMockImageDeleterSnapshotPurgeRequest, AcquireLockError) {
   expect_open(mock_image_ctx, 0);
   expect_acquire_lock(mock_image_ctx, -EPERM);
   expect_close(mock_image_ctx, -EINVAL);
-  expect_destroy(mock_image_ctx);
 
   C_SaferCond ctx;
   auto req = MockSnapshotPurgeRequest::create(m_local_io_ctx, mock_image_ctx.id,
@@ -324,7 +316,6 @@ TEST_F(TestMockImageDeleterSnapshotPurgeRequest, SnapUnprotectBusy) {
                         "snap1", -EBUSY);
 
   expect_close(mock_image_ctx, -EINVAL);
-  expect_destroy(mock_image_ctx);
 
   C_SaferCond ctx;
   auto req = MockSnapshotPurgeRequest::create(m_local_io_ctx, mock_image_ctx.id,
@@ -358,7 +349,6 @@ TEST_F(TestMockImageDeleterSnapshotPurgeRequest, SnapUnprotectError) {
                         "snap1", -EPERM);
 
   expect_close(mock_image_ctx, -EINVAL);
-  expect_destroy(mock_image_ctx);
 
   C_SaferCond ctx;
   auto req = MockSnapshotPurgeRequest::create(m_local_io_ctx, mock_image_ctx.id,
@@ -393,7 +383,6 @@ TEST_F(TestMockImageDeleterSnapshotPurgeRequest, SnapRemoveError) {
                      -EINVAL);
 
   expect_close(mock_image_ctx, -EPERM);
-  expect_destroy(mock_image_ctx);
 
   C_SaferCond ctx;
   auto req = MockSnapshotPurgeRequest::create(m_local_io_ctx, mock_image_ctx.id,
@@ -428,7 +417,6 @@ TEST_F(TestMockImageDeleterSnapshotPurgeRequest, CloseError) {
                      0);
 
   expect_close(mock_image_ctx, -EINVAL);
-  expect_destroy(mock_image_ctx);
 
   C_SaferCond ctx;
   auto req = MockSnapshotPurgeRequest::create(m_local_io_ctx, mock_image_ctx.id,
index c85fb150014e08256e00c303c951e6e0da0e959c..c3702a9cc33bf2433667a27edbe7a55ab4854846 100644 (file)
@@ -260,10 +260,6 @@ public:
                 }));
   }
 
-  void expect_destroy(librbd::MockTestImageCtx& mock_image_ctx) {
-    EXPECT_CALL(mock_image_ctx, destroy());
-  }
-
   void expect_mirror_image_set(const std::string& image_id,
                                const cls::rbd::MirrorImage& mirror_image,
                                int r) {
@@ -362,7 +358,6 @@ TEST_F(TestMockImageDeleterTrashMoveRequest, SuccessJournal) {
   expect_mirror_image_remove(m_local_io_ctx, 0);
 
   expect_close(mock_image_ctx, 0);
-  expect_destroy(mock_image_ctx);
 
   MockTrashWatcher mock_trash_watcher;
   expect_notify_image_added(mock_trash_watcher, "image id");
@@ -404,7 +399,6 @@ TEST_F(TestMockImageDeleterTrashMoveRequest, SuccessSnapshot) {
   expect_mirror_image_remove(m_local_io_ctx, 0);
 
   expect_close(mock_image_ctx, 0);
-  expect_destroy(mock_image_ctx);
 
   MockTrashWatcher mock_trash_watcher;
   expect_notify_image_added(mock_trash_watcher, "image id");
@@ -581,7 +575,6 @@ TEST_F(TestMockImageDeleterTrashMoveRequest, OpenImageError) {
 
   expect_set_journal_policy(mock_image_ctx);
   expect_open(mock_image_ctx, -EINVAL);
-  expect_destroy(mock_image_ctx);
 
   C_SaferCond ctx;
   auto req = MockTrashMoveRequest::create(m_local_io_ctx, "global image id",
@@ -620,7 +613,6 @@ TEST_F(TestMockImageDeleterTrashMoveRequest, ResetJournalError) {
   expect_journal_reset(mock_journal_reset_request, -EINVAL);
 
   expect_close(mock_image_ctx, 0);
-  expect_destroy(mock_image_ctx);
 
   C_SaferCond ctx;
   auto req = MockTrashMoveRequest::create(m_local_io_ctx, "global image id",
@@ -662,7 +654,6 @@ TEST_F(TestMockImageDeleterTrashMoveRequest, AcquireLockError) {
   expect_acquire_lock(mock_image_ctx, -EINVAL);
 
   expect_close(mock_image_ctx, 0);
-  expect_destroy(mock_image_ctx);
 
   C_SaferCond ctx;
   auto req = MockTrashMoveRequest::create(m_local_io_ctx, "global image id",
@@ -708,7 +699,6 @@ TEST_F(TestMockImageDeleterTrashMoveRequest, TrashMoveError) {
                     {}, -EINVAL);
 
   expect_close(mock_image_ctx, 0);
-  expect_destroy(mock_image_ctx);
 
   C_SaferCond ctx;
   auto req = MockTrashMoveRequest::create(m_local_io_ctx, "global image id",
@@ -755,7 +745,6 @@ TEST_F(TestMockImageDeleterTrashMoveRequest, RemoveMirrorImageError) {
   expect_mirror_image_remove(m_local_io_ctx, -EINVAL);
 
   expect_close(mock_image_ctx, 0);
-  expect_destroy(mock_image_ctx);
 
   MockTrashWatcher mock_trash_watcher;
   expect_notify_image_added(mock_trash_watcher, "image id");
@@ -805,7 +794,6 @@ TEST_F(TestMockImageDeleterTrashMoveRequest, CloseImageError) {
   expect_mirror_image_remove(m_local_io_ctx, 0);
 
   expect_close(mock_image_ctx, -EINVAL);
-  expect_destroy(mock_image_ctx);
 
   MockTrashWatcher mock_trash_watcher;
   expect_notify_image_added(mock_trash_watcher, "image id");
@@ -856,7 +844,6 @@ TEST_F(TestMockImageDeleterTrashMoveRequest, DelayedDelation) {
 
   expect_mirror_image_remove(m_local_io_ctx, 0);
   expect_close(mock_image_ctx, 0);
-  expect_destroy(mock_image_ctx);
 
   MockTrashWatcher mock_trash_watcher;
   expect_notify_image_added(mock_trash_watcher, "image id");
index 642149c31aebffbe9ec838e872e86e14664151b5..19a98804c71a9841fa70d4cb57a70f6070019070 100644 (file)
@@ -55,7 +55,6 @@ void SnapshotPurgeRequest<I>::handle_open_image(int r) {
   if (r < 0) {
     derr << "failed to open image '" << m_image_id << "': " << cpp_strerror(r)
          << dendl;
-    m_image_ctx->destroy();
     m_image_ctx = nullptr;
 
     finish(r);
@@ -264,7 +263,6 @@ template <typename I>
 void SnapshotPurgeRequest<I>::handle_close_image(int r) {
   dout(10) << "r=" << r << dendl;
 
-  m_image_ctx->destroy();
   m_image_ctx = nullptr;
 
   if (r < 0) {
index 243651bba0d46a938cbdf0d9401d9161b265524e..7f718cb9c66e2f390feb4993093fca4f434a48f9 100644 (file)
@@ -183,7 +183,6 @@ void TrashMoveRequest<I>::handle_open_image(int r) {
 
   if (r < 0) {
     derr << "failed to open image: " << cpp_strerror(r) << dendl;
-    m_image_ctx->destroy();
     m_image_ctx = nullptr;
     finish(r);
     return;
@@ -355,7 +354,6 @@ template <typename I>
 void TrashMoveRequest<I>::handle_close_image(int r) {
   dout(10) << "r=" << r << dendl;
 
-  m_image_ctx->destroy();
   m_image_ctx = nullptr;
 
   if (r < 0) {
index 10ab661e277114abae322fd16bbcbbb4fb689b16..872c8baa996ebedc4dde636ea33108b41fd8adf8 100644 (file)
@@ -48,7 +48,6 @@ void CloseImageRequest<I>::handle_close_image(int r) {
          << dendl;
   }
 
-  delete *m_image_ctx;
   *m_image_ctx = nullptr;
 
   m_on_finish->complete(0);
index 0827a1dcaa7f6cc17e3dd14f6f044a648de5c67e..e6ab382bea03971ca16c80709c504b4496b7297b 100644 (file)
@@ -58,7 +58,6 @@ void OpenImageRequest<I>::handle_open_image(int r) {
   if (r < 0) {
     derr << ": failed to open image '" << m_image_id << "': "
          << cpp_strerror(r) << dendl;
-    (*m_image_ctx)->destroy();
     *m_image_ctx = nullptr;
   }
 
index 8040cd214ba11e9d0e7a0aca99e8154bcd4b3ecc..7f8d9608eb4d899f84c81bdad3eef33c3c9df277 100644 (file)
@@ -149,7 +149,6 @@ void OpenLocalImageRequest<I>::handle_open_image(int r) {
       derr << ": failed to open image '" << m_local_image_id << "': "
            << cpp_strerror(r) << dendl;
     }
-    (*m_local_image_ctx)->destroy();
     *m_local_image_ctx = nullptr;
     finish(r);
     return;